diff --git a/DEPS b/DEPS
index 59eaa14..089a2ff 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': 'ba7b7abda177c4b4ebcab0f32f18816495018062',
+  'skia_revision': 'e65a5cd3fc34ab90743056ace2ef0a3a01bf6346',
   # 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': '09e7152ea60732cac61120982ae63b4630a1fb9f',
+  'v8_revision': 'b2c284af96714cb677f37ca0ccb435497b598ca0',
   # 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': 'b2c60b1a195049ede3f3d28a81cb1ff35929f88b',
+  'angle_revision': '115b2c4a2fc647de747814b26a840e25742f81d6',
   # 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.
@@ -99,11 +99,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
-  'swiftshader_revision': 'f120c92a4e7b4ee954cfb96171f9e4ff97b6cc9e',
+  'swiftshader_revision': 'b04881b856b90984a54c9d370f2d5e04d6383cc1',
   # 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': '765d1ebe41defa659a703a2f0ff5284c0da96a95',
+  'pdfium_revision': 'a17ac192c043a6bce51e16cf7cd076087c78d9a9',
   # 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.
@@ -210,7 +210,7 @@
   },
 
   'src/ios/third_party/material_components_ios/src': {
-      'url': Var('chromium_git') + '/external/github.com/material-components/material-components-ios.git' + '@' + 'dd21af4fef24ddb42d39e9610b84109273c50899',
+      'url': Var('chromium_git') + '/external/github.com/material-components/material-components-ios.git' + '@' + '3ac6d0ff2ac59613b12f3278a2ca36f43692ad8c',
       'condition': 'checkout_ios',
   },
 
diff --git a/ash/magnifier/magnification_controller.cc b/ash/magnifier/magnification_controller.cc
index 99146d15..0b0b3b09 100644
--- a/ash/magnifier/magnification_controller.cc
+++ b/ash/magnifier/magnification_controller.cc
@@ -6,6 +6,7 @@
 
 #include <memory>
 #include <utility>
+#include <vector>
 
 #include "ash/accelerators/accelerator_controller.h"
 #include "ash/accessibility/accessibility_delegate.h"
@@ -13,70 +14,63 @@
 #include "ash/host/ash_window_tree_host.h"
 #include "ash/host/root_window_transformer.h"
 #include "ash/magnifier/magnifier_scale_utils.h"
-#include "ash/public/cpp/ash_switches.h"
 #include "ash/public/cpp/config.h"
 #include "ash/root_window_controller.h"
 #include "ash/shell.h"
 #include "ash/shell_port.h"
-#include "base/command_line.h"
 #include "base/numerics/ranges.h"
 #include "base/synchronization/waitable_event.h"
-#include "base/timer/timer.h"
 #include "ui/aura/client/cursor_client.h"
 #include "ui/aura/window.h"
 #include "ui/aura/window_tree_host.h"
 #include "ui/base/ime/input_method.h"
-#include "ui/base/ime/input_method_observer.h"
 #include "ui/base/ime/text_input_client.h"
 #include "ui/compositor/dip_util.h"
 #include "ui/compositor/layer.h"
-#include "ui/compositor/layer_animation_observer.h"
 #include "ui/compositor/scoped_layer_animation_settings.h"
 #include "ui/display/display.h"
 #include "ui/display/screen.h"
 #include "ui/events/event.h"
-#include "ui/events/event_handler.h"
-#include "ui/events/event_rewriter.h"
-#include "ui/events/gesture_event_details.h"
 #include "ui/events/gestures/gesture_provider_aura.h"
 #include "ui/gfx/geometry/point3_f.h"
 #include "ui/gfx/geometry/point_conversions.h"
-#include "ui/gfx/geometry/point_f.h"
 #include "ui/gfx/geometry/rect_conversions.h"
 #include "ui/wm/core/compound_event_filter.h"
 #include "ui/wm/core/coordinate_conversion.h"
 
+namespace ash {
+
 namespace {
 
-const float kMaxMagnifiedScale = 20.0f;
-const float kMinMagnifiedScaleThreshold = 1.1f;
-const float kNonMagnifiedScale = 1.0f;
+constexpr float kMaxMagnifiedScale = 20.0f;
+constexpr float kMinMagnifiedScaleThreshold = 1.1f;
+constexpr float kNonMagnifiedScale = 1.0f;
 
-const float kInitialMagnifiedScale = 2.0f;
-const float kScrollScaleChangeFactor = 0.00125f;
+constexpr float kInitialMagnifiedScale = 2.0f;
+constexpr float kScrollScaleChangeFactor = 0.00125f;
 
-const float kZoomGestureLockThreshold = 0.2f;
-const float kScrollGestureLockThreshold = 2500.0f;
+constexpr float kZoomGestureLockThreshold = 0.2f;
+constexpr float kScrollGestureLockThreshold = 2500.0f;
 
 // Default animation parameters for redrawing the magnification window.
-const gfx::Tween::Type kDefaultAnimationTweenType = gfx::Tween::EASE_OUT;
-const int kDefaultAnimationDurationInMs = 100;
+constexpr gfx::Tween::Type kDefaultAnimationTweenType = gfx::Tween::EASE_OUT;
+constexpr int kDefaultAnimationDurationInMs = 100;
 
 // Use linear transformation to make the magnifier window move smoothly
 // to center the focus when user types in a text input field.
-const gfx::Tween::Type kCenterCaretAnimationTweenType = gfx::Tween::LINEAR;
+constexpr gfx::Tween::Type kCenterCaretAnimationTweenType = gfx::Tween::LINEAR;
 
 // The delay of the timer for moving magnifier window for centering the text
 // input focus.
-const int kMoveMagnifierDelayInMs = 10;
+constexpr int kMoveMagnifierDelayInMs = 10;
 
 // Threadshold of panning. If the cursor moves to within pixels (in DIP) of
 // |kCursorPanningMargin| from the edge, the view-port moves.
-const int kCursorPanningMargin = 100;
+constexpr int kCursorPanningMargin = 100;
 
 // Threadshold of panning. If the caret moves to within pixels (in DIP) of
 // |kCaretPanningMargin| from the edge, the view-port moves.
-const int kCaretPanningMargin = 50;
+constexpr int kCaretPanningMargin = 50;
 
 void MoveCursorTo(aura::WindowTreeHost* host, const gfx::Point& root_location) {
   auto host_location_3f = gfx::Point3F(gfx::PointF(root_location));
@@ -93,278 +87,34 @@
 
 }  // namespace
 
-namespace ash {
-
-void MagnificationController::StepToNextScaleValue(int delta_index) {
-  SetScale(magnifier_scale_utils::GetNextMagnifierScaleValue(
-               delta_index, GetScale(), kNonMagnifiedScale, kMaxMagnifiedScale),
-           true /* animate */);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// MagnificationControllerImpl:
-
-// MagnificationControllerImpl implements GestureConsumer as it has its own
-// GestureProvider to recognize gestures with screen coordinates of touches.
-// Logical coordinates of touches cannot be used as they are changed with
-// viewport change: scroll, zoom.
-// MagnificationControllerImpl implements EventRewriter to see and rewrite touch
-// events. Once the controller detects two fingers pinch or scroll, it starts
-// consuming all touch events not to confuse an app or a browser on the screen.
-// It needs to rewrite events to dispatch touch cancel events.
-class MagnificationControllerImpl : public MagnificationController,
-                                    public ui::EventHandler,
-                                    public ui::ImplicitAnimationObserver,
-                                    public aura::WindowObserver,
-                                    public ui::InputMethodObserver,
-                                    public ui::GestureConsumer,
-                                    public ui::EventRewriter {
+class MagnificationController::GestureProviderClient
+    : public ui::GestureProviderAuraClient {
  public:
-  MagnificationControllerImpl();
-  ~MagnificationControllerImpl() override;
+  GestureProviderClient() = default;
+  ~GestureProviderClient() override = default;
 
-  // MagnificationController overrides:
-  void SetEnabled(bool enabled) override;
-  bool IsEnabled() const override;
-  void SetKeepFocusCentered(bool keep_focus_centered) override;
-  bool KeepFocusCentered() const override;
-  void SetScale(float scale, bool animate) override;
-  float GetScale() const override { return scale_; }
-  void MoveWindow(int x, int y, bool animate) override;
-  void MoveWindow(const gfx::Point& point, bool animate) override;
-  gfx::Point GetWindowPosition() const override {
-    return gfx::ToFlooredPoint(origin_);
-  }
-  void SetScrollDirection(ScrollDirection direction) override;
-  gfx::Rect GetViewportRect() const override;
-  void HandleFocusedNodeChanged(
-      bool is_editable_node,
-      const gfx::Rect& node_bounds_in_screen) override;
-  void SwitchTargetRootWindow(aura::Window* new_root_window,
-                              bool redraw_original_root_window) override;
-
-  // For test
-  gfx::Point GetPointOfInterestForTesting() override {
-    return point_of_interest_in_root_;
-  }
-
-  bool IsOnAnimationForTesting() const override { return is_on_animation_; }
-
-  void DisableMoveMagnifierDelayForTesting() override {
-    disable_move_magnifier_delay_ = true;
+  // ui::GestureProviderAuraClient overrides:
+  void OnGestureEvent(GestureConsumer* consumer,
+                      ui::GestureEvent* event) override {
+    // Do nothing. OnGestureEvent is for timer based gesture events, e.g. tap.
+    // MagnificationController is interested only in pinch and scroll
+    // gestures.
+    DCHECK_NE(ui::ET_GESTURE_SCROLL_BEGIN, event->type());
+    DCHECK_NE(ui::ET_GESTURE_SCROLL_END, event->type());
+    DCHECK_NE(ui::ET_GESTURE_SCROLL_UPDATE, event->type());
+    DCHECK_NE(ui::ET_GESTURE_PINCH_BEGIN, event->type());
+    DCHECK_NE(ui::ET_GESTURE_PINCH_END, event->type());
+    DCHECK_NE(ui::ET_GESTURE_PINCH_UPDATE, event->type());
   }
 
  private:
-  class GestureProviderClient : public ui::GestureProviderAuraClient {
-   public:
-    GestureProviderClient() = default;
-    ~GestureProviderClient() override = default;
-
-    // ui::GestureProviderAuraClient overrides:
-    void OnGestureEvent(GestureConsumer* consumer,
-                        ui::GestureEvent* event) override {
-      // Do nothing. OnGestureEvent is for timer based gesture events, e.g. tap.
-      // MagnificationController is interested only in pinch and scroll
-      // gestures.
-      DCHECK_NE(ui::ET_GESTURE_SCROLL_BEGIN, event->type());
-      DCHECK_NE(ui::ET_GESTURE_SCROLL_END, event->type());
-      DCHECK_NE(ui::ET_GESTURE_SCROLL_UPDATE, event->type());
-      DCHECK_NE(ui::ET_GESTURE_PINCH_BEGIN, event->type());
-      DCHECK_NE(ui::ET_GESTURE_PINCH_END, event->type());
-      DCHECK_NE(ui::ET_GESTURE_PINCH_UPDATE, event->type());
-    }
-  };
-
-  enum LockedGestureType { NO_GESTURE, ZOOM, SCROLL };
-
-  // ui::ImplicitAnimationObserver overrides:
-  void OnImplicitAnimationsCompleted() override;
-
-  // aura::WindowObserver overrides:
-  void OnWindowDestroying(aura::Window* root_window) override;
-  void OnWindowBoundsChanged(aura::Window* window,
-                             const gfx::Rect& old_bounds,
-                             const gfx::Rect& new_bounds,
-                             ui::PropertyChangeReason reason) override;
-
-  // Redraws the magnification window with the given origin position and the
-  // given scale. Returns true if the window is changed; otherwise, false.
-  // These methods should be called internally just after the scale and/or
-  // the position are changed to redraw the window.
-  bool Redraw(const gfx::PointF& position, float scale, bool animate);
-
-  // Redraws the magnification window with the given origin position in dip and
-  // the given scale. Returns true if the window is changed; otherwise, false.
-  // The last two parameters specify the animation duration and tween type.
-  // If |animation_in_ms| is zero, there will be no animation, and |tween_type|
-  // will be ignored.
-  bool RedrawDIP(const gfx::PointF& position_in_dip,
-                 float scale,
-                 int animation_in_ms,
-                 gfx::Tween::Type tween_type);
-
-  // 1) If the screen is scrolling (i.e. animating) and should scroll further,
-  // it does nothing.
-  // 2) If the screen is scrolling (i.e. animating) and the direction is NONE,
-  // it stops the scrolling animation.
-  // 3) If the direction is set to value other than NONE, it starts the
-  // scrolling/ animation towards that direction.
-  void StartOrStopScrollIfNecessary();
-
-  // Redraw with the given zoom scale keeping the mouse cursor location. In
-  // other words, zoom (or unzoom) centering around the cursor.
-  // Ignore mouse position change after redrawing if |ignore_mouse_change| is
-  // true.
-  void RedrawKeepingMousePosition(float scale,
-                                  bool animate,
-                                  bool ignore_mouse_change);
-
-  void OnMouseMove(const gfx::Point& location);
-
-  // Move the mouse cursot to the given point. Actual move will be done when
-  // the animation is completed. This should be called after animation is
-  // started.
-  void AfterAnimationMoveCursorTo(const gfx::Point& location);
-
-  // Returns if the magnification scale is 1.0 or not (larger then 1.0).
-  bool IsMagnified() const;
-
-  // Returns the rect of the magnification window.
-  gfx::RectF GetWindowRectDIP(float scale) const;
-  // Returns the size of the root window.
-  gfx::Size GetHostSizeDIP() const;
-
-  // Correct the given scale value if necessary.
-  void ValidateScale(float* scale);
-
-  // ui::EventHandler overrides:
-  void OnMouseEvent(ui::MouseEvent* event) override;
-  void OnScrollEvent(ui::ScrollEvent* event) override;
-  void OnTouchEvent(ui::TouchEvent* event) override;
-
-  // ui::EventRewriter overrides:
-  ui::EventRewriteStatus RewriteEvent(
-      const ui::Event& event,
-      std::unique_ptr<ui::Event>* rewritten_event) override;
-  ui::EventRewriteStatus NextDispatchEvent(
-      const ui::Event& last_event,
-      std::unique_ptr<ui::Event>* new_event) override;
-
-  // Process pending gestures in |gesture_provider_|. This method returns true
-  // if the controller needs to cancel existing touches.
-  bool ProcessGestures();
-
-  // Moves the view port when |point| is located within
-  // |x_panning_margin| and |y_pannin_margin| to the edge of the visible
-  // window region. The view port will be moved so that the |point| will be
-  // moved to the point where it has |x_target_margin| and |y_target_margin|
-  // to the edge of the visible region.
-  void MoveMagnifierWindowFollowPoint(const gfx::Point& point,
-                                      int x_panning_margin,
-                                      int y_panning_margin,
-                                      int x_target_margin,
-                                      int y_target_margin);
-
-  // Moves the view port to center |point| in magnifier screen.
-  void MoveMagnifierWindowCenterPoint(const gfx::Point& point);
-
-  // Moves the viewport so that |rect| is fully visible. If |rect| is larger
-  // than the viewport horizontally or vertically, the viewport will be moved
-  // to center the |rect| in that dimension.
-  void MoveMagnifierWindowFollowRect(const gfx::Rect& rect);
-
-  // Invoked when |move_magnifier_timer_| fires to move the magnifier window to
-  // follow the caret.
-  void OnMoveMagnifierTimer();
-
-  // ui::InputMethodObserver:
-  void OnFocus() override {}
-  void OnBlur() override {}
-  void OnTextInputStateChanged(const ui::TextInputClient* client) override {}
-  void OnInputMethodDestroyed(const ui::InputMethod* input_method) override {}
-  void OnShowImeIfNeeded() override {}
-  void OnCaretBoundsChanged(const ui::TextInputClient* client) override;
-
-  // Target root window. This must not be NULL.
-  aura::Window* root_window_;
-
-  // True if the magnified window is currently animating a change. Otherwise,
-  // false.
-  bool is_on_animation_;
-
-  bool is_enabled_;
-
-  bool keep_focus_centered_;
-
-  // True if the cursor needs to move the given position after the animation
-  // will be finished. When using this, set |position_after_animation_| as well.
-  bool move_cursor_after_animation_;
-  // Stores the position of cursor to be moved after animation.
-  gfx::Point position_after_animation_;
-
-  // Stores the last mouse cursor (or last touched) location. This value is
-  // used on zooming to keep this location visible.
-  gfx::Point point_of_interest_in_root_;
-
-  // Current scale, origin (left-top) position of the magnification window.
-  float scale_;
-  gfx::PointF origin_;
-
-  float original_scale_;
-  gfx::PointF original_origin_;
-
-  ScrollDirection scroll_direction_;
-
-  // MagnificationController locks gesture once user performs either scroll or
-  // pinch gesture above those thresholds.
-  LockedGestureType locked_gesture_ = NO_GESTURE;
-
-  // If true, MagnificationController consumes all touch events.
-  bool consume_touch_event_ = false;
-
-  // Number of touch points on the screen.
-  int32_t touch_points_ = 0;
-
-  // Map for holding ET_TOUCH_PRESS events. Those events are used to dispatch
-  // ET_TOUCH_CANCELLED events. Events will be removed from this map when press
-  // events are cancelled, i.e. size of this map can be different from number of
-  // touches on the screen. Key is pointer id.
-  std::map<int32_t, std::unique_ptr<ui::TouchEvent>> press_event_map_;
-
-  std::unique_ptr<GestureProviderClient> gesture_provider_client_;
-
-  // MagnificationCotroller owns its GestureProvider to detect gestures with
-  // screen coordinates of touch events. As MagnificationController changes zoom
-  // level and moves viewport, logical coordinates of touches cannot be used for
-  // gesture detection as they are changed if the controller reacts to gestures.
-  std::unique_ptr<ui::GestureProviderAura> gesture_provider_;
-
-  // Timer for moving magnifier window when it fires.
-  base::OneShotTimer move_magnifier_timer_;
-
-  // Most recent caret position in |root_window_| coordinates.
-  gfx::Point caret_point_;
-
-  // Flag for disabling moving magnifier delay. It can only be true in testing
-  // mode.
-  bool disable_move_magnifier_delay_;
-
-  DISALLOW_COPY_AND_ASSIGN(MagnificationControllerImpl);
+  DISALLOW_COPY_AND_ASSIGN(GestureProviderClient);
 };
 
-////////////////////////////////////////////////////////////////////////////////
-// MagnificationControllerImpl:
-
-MagnificationControllerImpl::MagnificationControllerImpl()
+MagnificationController::MagnificationController()
     : root_window_(Shell::GetPrimaryRootWindow()),
-      is_on_animation_(false),
-      is_enabled_(false),
-      keep_focus_centered_(false),
-      move_cursor_after_animation_(false),
       scale_(kNonMagnifiedScale),
-      original_scale_(kNonMagnifiedScale),
-      scroll_direction_(SCROLL_NONE),
-      disable_move_magnifier_delay_(false) {
+      original_scale_(kNonMagnifiedScale) {
   Shell::Get()->AddPreTargetHandler(this);
   root_window_->AddObserver(this);
   root_window_->GetHost()->GetEventSource()->AddEventRewriter(this);
@@ -376,7 +126,7 @@
       this, gesture_provider_client_.get());
 }
 
-MagnificationControllerImpl::~MagnificationControllerImpl() {
+MagnificationController::~MagnificationController() {
   ui::InputMethod* input_method = GetInputMethod(root_window_);
   if (input_method)
     input_method->RemoveObserver(this);
@@ -387,309 +137,7 @@
   Shell::Get()->RemovePreTargetHandler(this);
 }
 
-void MagnificationControllerImpl::RedrawKeepingMousePosition(
-    float scale,
-    bool animate,
-    bool ignore_mouse_change) {
-  gfx::Point mouse_in_root = point_of_interest_in_root_;
-  // mouse_in_root is invalid value when the cursor is hidden.
-  if (!root_window_->bounds().Contains(mouse_in_root))
-    mouse_in_root = root_window_->bounds().CenterPoint();
-
-  const gfx::PointF origin = gfx::PointF(
-      mouse_in_root.x() - (scale_ / scale) * (mouse_in_root.x() - origin_.x()),
-      mouse_in_root.y() - (scale_ / scale) * (mouse_in_root.y() - origin_.y()));
-  bool changed =
-      RedrawDIP(origin, scale, animate ? kDefaultAnimationDurationInMs : 0,
-                kDefaultAnimationTweenType);
-  if (!ignore_mouse_change && changed)
-    AfterAnimationMoveCursorTo(mouse_in_root);
-}
-
-bool MagnificationControllerImpl::Redraw(const gfx::PointF& position,
-                                         float scale,
-                                         bool animate) {
-  const gfx::PointF position_in_dip =
-      ui::ConvertPointToDIP(root_window_->layer(), position);
-  return RedrawDIP(position_in_dip, scale,
-                   animate ? kDefaultAnimationDurationInMs : 0,
-                   kDefaultAnimationTweenType);
-}
-
-bool MagnificationControllerImpl::RedrawDIP(const gfx::PointF& position_in_dip,
-                                            float scale,
-                                            int duration_in_ms,
-                                            gfx::Tween::Type tween_type) {
-  DCHECK(root_window_);
-
-  float x = position_in_dip.x();
-  float y = position_in_dip.y();
-
-  ValidateScale(&scale);
-
-  if (x < 0)
-    x = 0;
-  if (y < 0)
-    y = 0;
-
-  const gfx::Size host_size_in_dip = GetHostSizeDIP();
-  const gfx::SizeF window_size_in_dip = GetWindowRectDIP(scale).size();
-  float max_x = host_size_in_dip.width() - window_size_in_dip.width();
-  float max_y = host_size_in_dip.height() - window_size_in_dip.height();
-  if (x > max_x)
-    x = max_x;
-  if (y > max_y)
-    y = max_y;
-
-  // Does nothing if both the origin and the scale are not changed.
-  if (origin_.x() == x && origin_.y() == y && scale == scale_) {
-    return false;
-  }
-
-  origin_.set_x(x);
-  origin_.set_y(y);
-  scale_ = scale;
-
-  // Creates transform matrix.
-  gfx::Transform transform;
-  // Flips the signs intentionally to convert them from the position of the
-  // magnification window.
-  transform.Scale(scale_, scale_);
-  transform.Translate(-origin_.x(), -origin_.y());
-
-  ui::ScopedLayerAnimationSettings settings(
-      root_window_->layer()->GetAnimator());
-  settings.AddObserver(this);
-  settings.SetPreemptionStrategy(
-      ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
-  settings.SetTweenType(tween_type);
-  settings.SetTransitionDuration(
-      base::TimeDelta::FromMilliseconds(duration_in_ms));
-
-  display::Display display =
-      display::Screen::GetScreen()->GetDisplayNearestWindow(root_window_);
-  std::unique_ptr<RootWindowTransformer> transformer(
-      CreateRootWindowTransformerForDisplay(root_window_, display));
-  RootWindowController::ForWindow(root_window_)
-      ->ash_host()
-      ->SetRootWindowTransformer(std::move(transformer));
-
-  if (duration_in_ms > 0)
-    is_on_animation_ = true;
-
-  return true;
-}
-
-void MagnificationControllerImpl::StartOrStopScrollIfNecessary() {
-  // This value controls the scrolling speed.
-  const int kMoveOffset = 40;
-  if (is_on_animation_) {
-    if (scroll_direction_ == SCROLL_NONE)
-      root_window_->layer()->GetAnimator()->StopAnimating();
-    return;
-  }
-
-  gfx::PointF new_origin = origin_;
-  switch (scroll_direction_) {
-    case SCROLL_NONE:
-      // No need to take action.
-      return;
-    case SCROLL_LEFT:
-      new_origin.Offset(-kMoveOffset, 0);
-      break;
-    case SCROLL_RIGHT:
-      new_origin.Offset(kMoveOffset, 0);
-      break;
-    case SCROLL_UP:
-      new_origin.Offset(0, -kMoveOffset);
-      break;
-    case SCROLL_DOWN:
-      new_origin.Offset(0, kMoveOffset);
-      break;
-  }
-  RedrawDIP(new_origin, scale_, kDefaultAnimationDurationInMs,
-            kDefaultAnimationTweenType);
-}
-
-void MagnificationControllerImpl::OnMouseMove(const gfx::Point& location) {
-  DCHECK(root_window_);
-
-  gfx::Point mouse(location);
-  int margin = kCursorPanningMargin / scale_;  // No need to consider DPI.
-  MoveMagnifierWindowFollowPoint(mouse, margin, margin, margin, margin);
-}
-
-gfx::Rect MagnificationControllerImpl::GetViewportRect() const {
-  return gfx::ToEnclosingRect(GetWindowRectDIP(scale_));
-}
-
-void MagnificationControllerImpl::HandleFocusedNodeChanged(
-    bool is_editable_node,
-    const gfx::Rect& node_bounds_in_screen) {
-  // The editable node is handled by OnCaretBoundsChanged.
-  if (is_editable_node)
-    return;
-
-  // Nothing to recenter on.
-  if (node_bounds_in_screen.IsEmpty())
-    return;
-
-  gfx::Rect node_bounds_in_root = node_bounds_in_screen;
-  ::wm::ConvertRectFromScreen(root_window_, &node_bounds_in_root);
-  if (GetViewportRect().Contains(node_bounds_in_root))
-    return;
-
-  MoveMagnifierWindowFollowRect(node_bounds_in_root);
-}
-
-void MagnificationControllerImpl::SwitchTargetRootWindow(
-    aura::Window* new_root_window,
-    bool redraw_original_root_window) {
-  DCHECK(new_root_window);
-
-  if (new_root_window == root_window_)
-    return;
-
-  // Stores the previous scale.
-  float scale = GetScale();
-
-  // Unmagnify the previous root window.
-  root_window_->RemoveObserver(this);
-  // TODO: This may need to remove the IME observer from the old root window
-  // and add it to the new root window. https://crbug.com/820464
-
-  // Do not move mouse back to its original position (point at border of the
-  // root window) after redrawing as doing so will trigger root window switch
-  // again.
-  if (redraw_original_root_window)
-    RedrawKeepingMousePosition(1.0f, true, true);
-  root_window_ = new_root_window;
-  RedrawKeepingMousePosition(scale, true, true);
-
-  root_window_->AddObserver(this);
-}
-
-void MagnificationControllerImpl::AfterAnimationMoveCursorTo(
-    const gfx::Point& location) {
-  DCHECK(root_window_);
-
-  aura::client::CursorClient* cursor_client =
-      aura::client::GetCursorClient(root_window_);
-  if (cursor_client) {
-    // When cursor is invisible, do not move or show the cursor after the
-    // animation.
-    if (!cursor_client->IsCursorVisible())
-      return;
-    cursor_client->DisableMouseEvents();
-  } else if (Shell::GetAshConfig() == Config::MASH) {
-    ShellPort::Get()->SetCursorTouchVisible(false);
-  }
-  move_cursor_after_animation_ = true;
-  position_after_animation_ = location;
-}
-
-gfx::Size MagnificationControllerImpl::GetHostSizeDIP() const {
-  return root_window_->bounds().size();
-}
-
-gfx::RectF MagnificationControllerImpl::GetWindowRectDIP(float scale) const {
-  const gfx::Size size_in_dip = root_window_->bounds().size();
-  const float width = size_in_dip.width() / scale;
-  const float height = size_in_dip.height() / scale;
-
-  return gfx::RectF(origin_.x(), origin_.y(), width, height);
-}
-
-bool MagnificationControllerImpl::IsMagnified() const {
-  return scale_ >= kMinMagnifiedScaleThreshold;
-}
-
-void MagnificationControllerImpl::ValidateScale(float* scale) {
-  *scale = base::ClampToRange(*scale, kNonMagnifiedScale, kMaxMagnifiedScale);
-  DCHECK(kNonMagnifiedScale <= *scale && *scale <= kMaxMagnifiedScale);
-}
-
-void MagnificationControllerImpl::OnImplicitAnimationsCompleted() {
-  if (!is_on_animation_)
-    return;
-
-  if (move_cursor_after_animation_) {
-    MoveCursorTo(root_window_->GetHost(), position_after_animation_);
-    move_cursor_after_animation_ = false;
-
-    aura::client::CursorClient* cursor_client =
-        aura::client::GetCursorClient(root_window_);
-    if (cursor_client)
-      cursor_client->EnableMouseEvents();
-    else if (Shell::GetAshConfig() == Config::MASH)
-      ShellPort::Get()->SetCursorTouchVisible(true);
-  }
-
-  is_on_animation_ = false;
-
-  StartOrStopScrollIfNecessary();
-}
-
-void MagnificationControllerImpl::OnWindowDestroying(
-    aura::Window* root_window) {
-  if (root_window == root_window_) {
-    // There must be at least one root window because this controller is
-    // destroyed before the root windows get destroyed.
-    DCHECK(root_window);
-
-    aura::Window* target_root_window = Shell::GetRootWindowForNewWindows();
-    CHECK(target_root_window);
-
-    // The destroyed root window must not be target.
-    CHECK_NE(target_root_window, root_window);
-    // Don't redraw the old root window as it's being destroyed.
-    SwitchTargetRootWindow(target_root_window, false);
-    point_of_interest_in_root_ = target_root_window->bounds().CenterPoint();
-  }
-}
-
-void MagnificationControllerImpl::OnWindowBoundsChanged(
-    aura::Window* window,
-    const gfx::Rect& old_bounds,
-    const gfx::Rect& new_bounds,
-    ui::PropertyChangeReason reason) {
-  // TODO(yoshiki): implement here. crbug.com/230979
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// MagnificationControllerImpl: MagnificationController implementation
-
-void MagnificationControllerImpl::SetScale(float scale, bool animate) {
-  if (!is_enabled_)
-    return;
-
-  ValidateScale(&scale);
-  Shell::Get()->accessibility_delegate()->SaveScreenMagnifierScale(scale);
-  RedrawKeepingMousePosition(scale, animate, false);
-}
-
-void MagnificationControllerImpl::MoveWindow(int x, int y, bool animate) {
-  if (!is_enabled_)
-    return;
-
-  Redraw(gfx::PointF(x, y), scale_, animate);
-}
-
-void MagnificationControllerImpl::MoveWindow(const gfx::Point& point,
-                                             bool animate) {
-  if (!is_enabled_)
-    return;
-
-  Redraw(gfx::PointF(point), scale_, animate);
-}
-
-void MagnificationControllerImpl::SetScrollDirection(
-    ScrollDirection direction) {
-  scroll_direction_ = direction;
-  StartOrStopScrollIfNecessary();
-}
-
-void MagnificationControllerImpl::SetEnabled(bool enabled) {
+void MagnificationController::SetEnabled(bool enabled) {
   ui::InputMethod* input_method = GetInputMethod(root_window_);
   if (enabled) {
     if (!is_enabled_ && input_method)
@@ -722,23 +170,154 @@
   }
 }
 
-bool MagnificationControllerImpl::IsEnabled() const {
+bool MagnificationController::IsEnabled() const {
   return is_enabled_;
 }
 
-void MagnificationControllerImpl::SetKeepFocusCentered(
-    bool keep_focus_centered) {
+void MagnificationController::SetKeepFocusCentered(bool keep_focus_centered) {
   keep_focus_centered_ = keep_focus_centered;
 }
 
-bool MagnificationControllerImpl::KeepFocusCentered() const {
+bool MagnificationController::KeepFocusCentered() const {
   return keep_focus_centered_;
 }
 
-////////////////////////////////////////////////////////////////////////////////
-// MagnificationControllerImpl: aura::EventFilter implementation
+void MagnificationController::SetScale(float scale, bool animate) {
+  if (!is_enabled_)
+    return;
 
-void MagnificationControllerImpl::OnMouseEvent(ui::MouseEvent* event) {
+  ValidateScale(&scale);
+  Shell::Get()->accessibility_delegate()->SaveScreenMagnifierScale(scale);
+  RedrawKeepingMousePosition(scale, animate, false);
+}
+
+void MagnificationController::StepToNextScaleValue(int delta_index) {
+  SetScale(magnifier_scale_utils::GetNextMagnifierScaleValue(
+               delta_index, GetScale(), kNonMagnifiedScale, kMaxMagnifiedScale),
+           true /* animate */);
+}
+
+void MagnificationController::MoveWindow(int x, int y, bool animate) {
+  if (!is_enabled_)
+    return;
+
+  Redraw(gfx::PointF(x, y), scale_, animate);
+}
+
+void MagnificationController::MoveWindow(const gfx::Point& point,
+                                         bool animate) {
+  if (!is_enabled_)
+    return;
+
+  Redraw(gfx::PointF(point), scale_, animate);
+}
+
+gfx::Point MagnificationController::GetWindowPosition() const {
+  return gfx::ToFlooredPoint(origin_);
+}
+
+void MagnificationController::SetScrollDirection(ScrollDirection direction) {
+  scroll_direction_ = direction;
+  StartOrStopScrollIfNecessary();
+}
+
+gfx::Rect MagnificationController::GetViewportRect() const {
+  return gfx::ToEnclosingRect(GetWindowRectDIP(scale_));
+}
+
+void MagnificationController::HandleFocusedNodeChanged(
+    bool is_editable_node,
+    const gfx::Rect& node_bounds_in_screen) {
+  // The editable node is handled by OnCaretBoundsChanged.
+  if (is_editable_node)
+    return;
+
+  // Nothing to recenter on.
+  if (node_bounds_in_screen.IsEmpty())
+    return;
+
+  gfx::Rect node_bounds_in_root = node_bounds_in_screen;
+  ::wm::ConvertRectFromScreen(root_window_, &node_bounds_in_root);
+  if (GetViewportRect().Contains(node_bounds_in_root))
+    return;
+
+  MoveMagnifierWindowFollowRect(node_bounds_in_root);
+}
+
+void MagnificationController::SwitchTargetRootWindow(
+    aura::Window* new_root_window,
+    bool redraw_original_root_window) {
+  DCHECK(new_root_window);
+
+  if (new_root_window == root_window_)
+    return;
+
+  // Stores the previous scale.
+  float scale = GetScale();
+
+  // Unmagnify the previous root window.
+  root_window_->RemoveObserver(this);
+  // TODO: This may need to remove the IME observer from the old root window
+  // and add it to the new root window. https://crbug.com/820464
+
+  // Do not move mouse back to its original position (point at border of the
+  // root window) after redrawing as doing so will trigger root window switch
+  // again.
+  if (redraw_original_root_window)
+    RedrawKeepingMousePosition(1.0f, true, true);
+  root_window_ = new_root_window;
+  RedrawKeepingMousePosition(scale, true, true);
+
+  root_window_->AddObserver(this);
+}
+
+void MagnificationController::OnImplicitAnimationsCompleted() {
+  if (!is_on_animation_)
+    return;
+
+  if (move_cursor_after_animation_) {
+    MoveCursorTo(root_window_->GetHost(), position_after_animation_);
+    move_cursor_after_animation_ = false;
+
+    aura::client::CursorClient* cursor_client =
+        aura::client::GetCursorClient(root_window_);
+    if (cursor_client)
+      cursor_client->EnableMouseEvents();
+    else if (Shell::GetAshConfig() == Config::MASH)
+      ShellPort::Get()->SetCursorTouchVisible(true);
+  }
+
+  is_on_animation_ = false;
+
+  StartOrStopScrollIfNecessary();
+}
+
+void MagnificationController::OnWindowDestroying(aura::Window* root_window) {
+  if (root_window == root_window_) {
+    // There must be at least one root window because this controller is
+    // destroyed before the root windows get destroyed.
+    DCHECK(root_window);
+
+    aura::Window* target_root_window = Shell::GetRootWindowForNewWindows();
+    CHECK(target_root_window);
+
+    // The destroyed root window must not be target.
+    CHECK_NE(target_root_window, root_window);
+    // Don't redraw the old root window as it's being destroyed.
+    SwitchTargetRootWindow(target_root_window, false);
+    point_of_interest_in_root_ = target_root_window->bounds().CenterPoint();
+  }
+}
+
+void MagnificationController::OnWindowBoundsChanged(
+    aura::Window* window,
+    const gfx::Rect& old_bounds,
+    const gfx::Rect& new_bounds,
+    ui::PropertyChangeReason reason) {
+  // TODO(yoshiki): implement here. crbug.com/230979
+}
+
+void MagnificationController::OnMouseEvent(ui::MouseEvent* event) {
   aura::Window* target = static_cast<aura::Window*>(event->target());
   aura::Window* current_root = target->GetRootWindow();
   gfx::Rect root_bounds = current_root->bounds();
@@ -761,7 +340,7 @@
   }
 }
 
-void MagnificationControllerImpl::OnScrollEvent(ui::ScrollEvent* event) {
+void MagnificationController::OnScrollEvent(ui::ScrollEvent* event) {
   if (event->IsAltDown() && event->IsControlDown()) {
     if (event->type() == ui::ET_SCROLL_FLING_START) {
       event->StopPropagation();
@@ -790,7 +369,7 @@
   }
 }
 
-void MagnificationControllerImpl::OnTouchEvent(ui::TouchEvent* event) {
+void MagnificationController::OnTouchEvent(ui::TouchEvent* event) {
   aura::Window* target = static_cast<aura::Window*>(event->target());
   aura::Window* current_root = target->GetRootWindow();
 
@@ -804,7 +383,7 @@
     SwitchTargetRootWindow(current_root, true);
 }
 
-ui::EventRewriteStatus MagnificationControllerImpl::RewriteEvent(
+ui::EventRewriteStatus MagnificationController::RewriteEvent(
     const ui::Event& event,
     std::unique_ptr<ui::Event>* rewritten_event) {
   if (!IsEnabled())
@@ -883,66 +462,7 @@
   return ui::EVENT_REWRITE_CONTINUE;
 }
 
-bool MagnificationControllerImpl::ProcessGestures() {
-  bool cancel_pressed_touches = false;
-
-  std::vector<std::unique_ptr<ui::GestureEvent>> gestures =
-      gesture_provider_->GetAndResetPendingGestures();
-  for (const auto& gesture : gestures) {
-    const ui::GestureEventDetails& details = gesture->details();
-
-    if (details.touch_points() != 2)
-      continue;
-
-    if (gesture->type() == ui::ET_GESTURE_PINCH_BEGIN) {
-      original_scale_ = scale_;
-
-      // Start consuming touch events with cancelling existing touches.
-      if (!consume_touch_event_)
-        cancel_pressed_touches = true;
-    } else if (gesture->type() == ui::ET_GESTURE_PINCH_UPDATE) {
-      if (locked_gesture_ == NO_GESTURE || locked_gesture_ == ZOOM) {
-        float scale = GetScale() * details.scale();
-        ValidateScale(&scale);
-
-        if (locked_gesture_ == NO_GESTURE &&
-            std::abs(scale - original_scale_) > kZoomGestureLockThreshold) {
-          locked_gesture_ = MagnificationControllerImpl::ZOOM;
-        }
-
-        RedrawDIP(origin_, scale, 0, kDefaultAnimationTweenType);
-      }
-    } else if (gesture->type() == ui::ET_GESTURE_SCROLL_BEGIN) {
-      original_origin_ = origin_;
-
-      // Start consuming all touch events with cancelling existing touches.
-      if (!consume_touch_event_)
-        cancel_pressed_touches = true;
-    } else if (gesture->type() == ui::ET_GESTURE_SCROLL_UPDATE) {
-      if (locked_gesture_ == NO_GESTURE || locked_gesture_ == SCROLL) {
-        // Divide by scale to keep scroll speed same at any scale.
-        float new_x = origin_.x() + (-1.0f * details.scroll_x() / scale_);
-        float new_y = origin_.y() + (-1.0f * details.scroll_y() / scale_);
-
-        if (locked_gesture_ == NO_GESTURE) {
-          float diff_x = (new_x - original_origin_.x()) * scale_;
-          float diff_y = (new_y - original_origin_.y()) * scale_;
-          float squared_distance = (diff_x * diff_x) + (diff_y * diff_y);
-          if (squared_distance > kScrollGestureLockThreshold) {
-            locked_gesture_ = SCROLL;
-          }
-        }
-
-        RedrawDIP(gfx::PointF(new_x, new_y), scale_, 0,
-                  kDefaultAnimationTweenType);
-      }
-    }
-  }
-
-  return cancel_pressed_touches;
-}
-
-ui::EventRewriteStatus MagnificationControllerImpl::NextDispatchEvent(
+ui::EventRewriteStatus MagnificationController::NextDispatchEvent(
     const ui::Event& last_event,
     std::unique_ptr<ui::Event>* new_event) {
   DCHECK_EQ(1u, press_event_map_.size());
@@ -964,117 +484,7 @@
   return ui::EVENT_REWRITE_REWRITTEN;
 }
 
-void MagnificationControllerImpl::MoveMagnifierWindowFollowPoint(
-    const gfx::Point& point,
-    int x_panning_margin,
-    int y_panning_margin,
-    int x_target_margin,
-    int y_target_margin) {
-  DCHECK(root_window_);
-  bool start_zoom = false;
-
-  const gfx::Rect window_rect = GetViewportRect();
-  const int left = window_rect.x();
-  const int right = window_rect.right();
-
-  int x_diff = 0;
-  if (point.x() < left + x_panning_margin) {
-    // Panning left.
-    x_diff = point.x() - (left + x_target_margin);
-    start_zoom = true;
-  } else if (right - x_panning_margin < point.x()) {
-    // Panning right.
-    x_diff = point.x() - (right - x_target_margin);
-    start_zoom = true;
-  }
-  int x = left + x_diff;
-
-  const int top = window_rect.y();
-  const int bottom = window_rect.bottom();
-
-  int y_diff = 0;
-  if (point.y() < top + y_panning_margin) {
-    // Panning up.
-    y_diff = point.y() - (top + y_target_margin);
-    start_zoom = true;
-  } else if (bottom - y_panning_margin < point.y()) {
-    // Panning down.
-    y_diff = point.y() - (bottom - y_target_margin);
-    start_zoom = true;
-  }
-  int y = top + y_diff;
-  if (start_zoom && !is_on_animation_) {
-    bool ret = RedrawDIP(gfx::PointF(x, y), scale_,
-                         0,  // No animation on panning.
-                         kDefaultAnimationTweenType);
-
-    if (ret) {
-      // If the magnified region is moved, hides the mouse cursor and moves it.
-      if (x_diff != 0 || y_diff != 0)
-        MoveCursorTo(root_window_->GetHost(), point);
-    }
-  }
-}
-
-void MagnificationControllerImpl::MoveMagnifierWindowCenterPoint(
-    const gfx::Point& point) {
-  DCHECK(root_window_);
-
-  const gfx::Rect window_rect = GetViewportRect();
-  if (point == window_rect.CenterPoint())
-    return;
-
-  if (!is_on_animation_) {
-    // With animation on panning.
-    RedrawDIP(
-        gfx::PointF(window_rect.origin() + (point - window_rect.CenterPoint())),
-        scale_, kDefaultAnimationDurationInMs, kCenterCaretAnimationTweenType);
-  }
-}
-
-void MagnificationControllerImpl::MoveMagnifierWindowFollowRect(
-    const gfx::Rect& rect) {
-  DCHECK(root_window_);
-  bool should_pan = false;
-
-  const gfx::Rect viewport_rect = GetViewportRect();
-  const int left = viewport_rect.x();
-  const int right = viewport_rect.right();
-  const gfx::Point rect_center = rect.CenterPoint();
-
-  int x = left;
-  if (rect.x() < left || right < rect.right()) {
-    // Panning horizontally.
-    x = rect_center.x() - viewport_rect.width() / 2;
-    should_pan = true;
-  }
-
-  const int top = viewport_rect.y();
-  const int bottom = viewport_rect.bottom();
-
-  int y = top;
-  if (rect.y() < top || bottom < rect.bottom()) {
-    // Panning vertically.
-    y = rect_center.y() - viewport_rect.height() / 2;
-    should_pan = true;
-  }
-
-  if (should_pan) {
-    if (is_on_animation_) {
-      root_window_->layer()->GetAnimator()->StopAnimating();
-      is_on_animation_ = false;
-    }
-    RedrawDIP(gfx::PointF(x, y), scale_,
-              0,  // No animation on panning.
-              kDefaultAnimationTweenType);
-  }
-}
-
-void MagnificationControllerImpl::OnMoveMagnifierTimer() {
-  MoveMagnifierWindowCenterPoint(caret_point_);
-}
-
-void MagnificationControllerImpl::OnCaretBoundsChanged(
+void MagnificationController::OnCaretBoundsChanged(
     const ui::TextInputClient* client) {
   // caret bounds in screen coordinates.
   const gfx::Rect caret_bounds = client->GetCaretBounds();
@@ -1126,15 +536,348 @@
       FROM_HERE,
       base::TimeDelta::FromMilliseconds(
           disable_move_magnifier_delay_ ? 0 : kMoveMagnifierDelayInMs),
-      this, &MagnificationControllerImpl::OnMoveMagnifierTimer);
+      this, &MagnificationController::OnMoveMagnifierTimer);
 }
 
-////////////////////////////////////////////////////////////////////////////////
-// MagnificationController:
+bool MagnificationController::Redraw(const gfx::PointF& position,
+                                     float scale,
+                                     bool animate) {
+  const gfx::PointF position_in_dip =
+      ui::ConvertPointToDIP(root_window_->layer(), position);
+  return RedrawDIP(position_in_dip, scale,
+                   animate ? kDefaultAnimationDurationInMs : 0,
+                   kDefaultAnimationTweenType);
+}
 
-// static
-MagnificationController* MagnificationController::CreateInstance() {
-  return new MagnificationControllerImpl();
+bool MagnificationController::RedrawDIP(const gfx::PointF& position_in_dip,
+                                        float scale,
+                                        int duration_in_ms,
+                                        gfx::Tween::Type tween_type) {
+  DCHECK(root_window_);
+
+  float x = position_in_dip.x();
+  float y = position_in_dip.y();
+
+  ValidateScale(&scale);
+
+  if (x < 0)
+    x = 0;
+  if (y < 0)
+    y = 0;
+
+  const gfx::Size host_size_in_dip = GetHostSizeDIP();
+  const gfx::SizeF window_size_in_dip = GetWindowRectDIP(scale).size();
+  float max_x = host_size_in_dip.width() - window_size_in_dip.width();
+  float max_y = host_size_in_dip.height() - window_size_in_dip.height();
+  if (x > max_x)
+    x = max_x;
+  if (y > max_y)
+    y = max_y;
+
+  // Does nothing if both the origin and the scale are not changed.
+  if (origin_.x() == x && origin_.y() == y && scale == scale_) {
+    return false;
+  }
+
+  origin_.set_x(x);
+  origin_.set_y(y);
+  scale_ = scale;
+
+  // Creates transform matrix.
+  gfx::Transform transform;
+  // Flips the signs intentionally to convert them from the position of the
+  // magnification window.
+  transform.Scale(scale_, scale_);
+  transform.Translate(-origin_.x(), -origin_.y());
+
+  ui::ScopedLayerAnimationSettings settings(
+      root_window_->layer()->GetAnimator());
+  settings.AddObserver(this);
+  settings.SetPreemptionStrategy(
+      ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
+  settings.SetTweenType(tween_type);
+  settings.SetTransitionDuration(
+      base::TimeDelta::FromMilliseconds(duration_in_ms));
+
+  display::Display display =
+      display::Screen::GetScreen()->GetDisplayNearestWindow(root_window_);
+  std::unique_ptr<RootWindowTransformer> transformer(
+      CreateRootWindowTransformerForDisplay(root_window_, display));
+  RootWindowController::ForWindow(root_window_)
+      ->ash_host()
+      ->SetRootWindowTransformer(std::move(transformer));
+
+  if (duration_in_ms > 0)
+    is_on_animation_ = true;
+
+  return true;
+}
+
+void MagnificationController::StartOrStopScrollIfNecessary() {
+  // This value controls the scrolling speed.
+  const int kMoveOffset = 40;
+  if (is_on_animation_) {
+    if (scroll_direction_ == SCROLL_NONE)
+      root_window_->layer()->GetAnimator()->StopAnimating();
+    return;
+  }
+
+  gfx::PointF new_origin = origin_;
+  switch (scroll_direction_) {
+    case SCROLL_NONE:
+      // No need to take action.
+      return;
+    case SCROLL_LEFT:
+      new_origin.Offset(-kMoveOffset, 0);
+      break;
+    case SCROLL_RIGHT:
+      new_origin.Offset(kMoveOffset, 0);
+      break;
+    case SCROLL_UP:
+      new_origin.Offset(0, -kMoveOffset);
+      break;
+    case SCROLL_DOWN:
+      new_origin.Offset(0, kMoveOffset);
+      break;
+  }
+  RedrawDIP(new_origin, scale_, kDefaultAnimationDurationInMs,
+            kDefaultAnimationTweenType);
+}
+
+void MagnificationController::RedrawKeepingMousePosition(
+    float scale,
+    bool animate,
+    bool ignore_mouse_change) {
+  gfx::Point mouse_in_root = point_of_interest_in_root_;
+  // mouse_in_root is invalid value when the cursor is hidden.
+  if (!root_window_->bounds().Contains(mouse_in_root))
+    mouse_in_root = root_window_->bounds().CenterPoint();
+
+  const gfx::PointF origin = gfx::PointF(
+      mouse_in_root.x() - (scale_ / scale) * (mouse_in_root.x() - origin_.x()),
+      mouse_in_root.y() - (scale_ / scale) * (mouse_in_root.y() - origin_.y()));
+  bool changed =
+      RedrawDIP(origin, scale, animate ? kDefaultAnimationDurationInMs : 0,
+                kDefaultAnimationTweenType);
+  if (!ignore_mouse_change && changed)
+    AfterAnimationMoveCursorTo(mouse_in_root);
+}
+
+void MagnificationController::OnMouseMove(const gfx::Point& location) {
+  DCHECK(root_window_);
+
+  gfx::Point mouse(location);
+  int margin = kCursorPanningMargin / scale_;  // No need to consider DPI.
+  MoveMagnifierWindowFollowPoint(mouse, margin, margin, margin, margin);
+}
+
+void MagnificationController::AfterAnimationMoveCursorTo(
+    const gfx::Point& location) {
+  DCHECK(root_window_);
+
+  aura::client::CursorClient* cursor_client =
+      aura::client::GetCursorClient(root_window_);
+  if (cursor_client) {
+    // When cursor is invisible, do not move or show the cursor after the
+    // animation.
+    if (!cursor_client->IsCursorVisible())
+      return;
+    cursor_client->DisableMouseEvents();
+  } else if (Shell::GetAshConfig() == Config::MASH) {
+    ShellPort::Get()->SetCursorTouchVisible(false);
+  }
+  move_cursor_after_animation_ = true;
+  position_after_animation_ = location;
+}
+
+bool MagnificationController::IsMagnified() const {
+  return scale_ >= kMinMagnifiedScaleThreshold;
+}
+
+gfx::RectF MagnificationController::GetWindowRectDIP(float scale) const {
+  const gfx::Size size_in_dip = root_window_->bounds().size();
+  const float width = size_in_dip.width() / scale;
+  const float height = size_in_dip.height() / scale;
+
+  return gfx::RectF(origin_.x(), origin_.y(), width, height);
+}
+
+gfx::Size MagnificationController::GetHostSizeDIP() const {
+  return root_window_->bounds().size();
+}
+
+void MagnificationController::ValidateScale(float* scale) {
+  *scale = base::ClampToRange(*scale, kNonMagnifiedScale, kMaxMagnifiedScale);
+  DCHECK(kNonMagnifiedScale <= *scale && *scale <= kMaxMagnifiedScale);
+}
+
+bool MagnificationController::ProcessGestures() {
+  bool cancel_pressed_touches = false;
+
+  std::vector<std::unique_ptr<ui::GestureEvent>> gestures =
+      gesture_provider_->GetAndResetPendingGestures();
+  for (const auto& gesture : gestures) {
+    const ui::GestureEventDetails& details = gesture->details();
+
+    if (details.touch_points() != 2)
+      continue;
+
+    if (gesture->type() == ui::ET_GESTURE_PINCH_BEGIN) {
+      original_scale_ = scale_;
+
+      // Start consuming touch events with cancelling existing touches.
+      if (!consume_touch_event_)
+        cancel_pressed_touches = true;
+    } else if (gesture->type() == ui::ET_GESTURE_PINCH_UPDATE) {
+      if (locked_gesture_ == NO_GESTURE || locked_gesture_ == ZOOM) {
+        float scale = GetScale() * details.scale();
+        ValidateScale(&scale);
+
+        if (locked_gesture_ == NO_GESTURE &&
+            std::abs(scale - original_scale_) > kZoomGestureLockThreshold) {
+          locked_gesture_ = MagnificationController::ZOOM;
+        }
+
+        RedrawDIP(origin_, scale, 0, kDefaultAnimationTweenType);
+      }
+    } else if (gesture->type() == ui::ET_GESTURE_SCROLL_BEGIN) {
+      original_origin_ = origin_;
+
+      // Start consuming all touch events with cancelling existing touches.
+      if (!consume_touch_event_)
+        cancel_pressed_touches = true;
+    } else if (gesture->type() == ui::ET_GESTURE_SCROLL_UPDATE) {
+      if (locked_gesture_ == NO_GESTURE || locked_gesture_ == SCROLL) {
+        // Divide by scale to keep scroll speed same at any scale.
+        float new_x = origin_.x() + (-1.0f * details.scroll_x() / scale_);
+        float new_y = origin_.y() + (-1.0f * details.scroll_y() / scale_);
+
+        if (locked_gesture_ == NO_GESTURE) {
+          float diff_x = (new_x - original_origin_.x()) * scale_;
+          float diff_y = (new_y - original_origin_.y()) * scale_;
+          float squared_distance = (diff_x * diff_x) + (diff_y * diff_y);
+          if (squared_distance > kScrollGestureLockThreshold) {
+            locked_gesture_ = SCROLL;
+          }
+        }
+
+        RedrawDIP(gfx::PointF(new_x, new_y), scale_, 0,
+                  kDefaultAnimationTweenType);
+      }
+    }
+  }
+
+  return cancel_pressed_touches;
+}
+
+void MagnificationController::MoveMagnifierWindowFollowPoint(
+    const gfx::Point& point,
+    int x_panning_margin,
+    int y_panning_margin,
+    int x_target_margin,
+    int y_target_margin) {
+  DCHECK(root_window_);
+  bool start_zoom = false;
+
+  const gfx::Rect window_rect = GetViewportRect();
+  const int left = window_rect.x();
+  const int right = window_rect.right();
+
+  int x_diff = 0;
+  if (point.x() < left + x_panning_margin) {
+    // Panning left.
+    x_diff = point.x() - (left + x_target_margin);
+    start_zoom = true;
+  } else if (right - x_panning_margin < point.x()) {
+    // Panning right.
+    x_diff = point.x() - (right - x_target_margin);
+    start_zoom = true;
+  }
+  int x = left + x_diff;
+
+  const int top = window_rect.y();
+  const int bottom = window_rect.bottom();
+
+  int y_diff = 0;
+  if (point.y() < top + y_panning_margin) {
+    // Panning up.
+    y_diff = point.y() - (top + y_target_margin);
+    start_zoom = true;
+  } else if (bottom - y_panning_margin < point.y()) {
+    // Panning down.
+    y_diff = point.y() - (bottom - y_target_margin);
+    start_zoom = true;
+  }
+  int y = top + y_diff;
+  if (start_zoom && !is_on_animation_) {
+    bool ret = RedrawDIP(gfx::PointF(x, y), scale_,
+                         0,  // No animation on panning.
+                         kDefaultAnimationTweenType);
+
+    if (ret) {
+      // If the magnified region is moved, hides the mouse cursor and moves it.
+      if (x_diff != 0 || y_diff != 0)
+        MoveCursorTo(root_window_->GetHost(), point);
+    }
+  }
+}
+
+void MagnificationController::MoveMagnifierWindowCenterPoint(
+    const gfx::Point& point) {
+  DCHECK(root_window_);
+
+  const gfx::Rect window_rect = GetViewportRect();
+  if (point == window_rect.CenterPoint())
+    return;
+
+  if (!is_on_animation_) {
+    // With animation on panning.
+    RedrawDIP(
+        gfx::PointF(window_rect.origin() + (point - window_rect.CenterPoint())),
+        scale_, kDefaultAnimationDurationInMs, kCenterCaretAnimationTweenType);
+  }
+}
+
+void MagnificationController::MoveMagnifierWindowFollowRect(
+    const gfx::Rect& rect) {
+  DCHECK(root_window_);
+  bool should_pan = false;
+
+  const gfx::Rect viewport_rect = GetViewportRect();
+  const int left = viewport_rect.x();
+  const int right = viewport_rect.right();
+  const gfx::Point rect_center = rect.CenterPoint();
+
+  int x = left;
+  if (rect.x() < left || right < rect.right()) {
+    // Panning horizontally.
+    x = rect_center.x() - viewport_rect.width() / 2;
+    should_pan = true;
+  }
+
+  const int top = viewport_rect.y();
+  const int bottom = viewport_rect.bottom();
+
+  int y = top;
+  if (rect.y() < top || bottom < rect.bottom()) {
+    // Panning vertically.
+    y = rect_center.y() - viewport_rect.height() / 2;
+    should_pan = true;
+  }
+
+  if (should_pan) {
+    if (is_on_animation_) {
+      root_window_->layer()->GetAnimator()->StopAnimating();
+      is_on_animation_ = false;
+    }
+    RedrawDIP(gfx::PointF(x, y), scale_,
+              0,  // No animation on panning.
+              kDefaultAnimationTweenType);
+  }
+}
+
+void MagnificationController::OnMoveMagnifierTimer() {
+  MoveMagnifierWindowCenterPoint(caret_point_);
 }
 
 }  // namespace ash
diff --git a/ash/magnifier/magnification_controller.h b/ash/magnifier/magnification_controller.h
index 74b8647..8f5cfeb 100644
--- a/ash/magnifier/magnification_controller.h
+++ b/ash/magnifier/magnification_controller.h
@@ -5,21 +5,47 @@
 #ifndef ASH_MAGNIFIER_MAGNIFICATION_CONTROLLER_H_
 #define ASH_MAGNIFIER_MAGNIFICATION_CONTROLLER_H_
 
+#include <map>
+#include <memory>
+
 #include "ash/ash_export.h"
-#include "base/compiler_specific.h"
-#include "base/gtest_prod_util.h"
-#include "base/logging.h"
 #include "base/macros.h"
+#include "base/timer/timer.h"
+#include "ui/aura/window_observer.h"
+#include "ui/base/ime/input_method_observer.h"
+#include "ui/compositor/layer_animation_observer.h"
+#include "ui/events/event_handler.h"
+#include "ui/events/event_rewriter.h"
+#include "ui/events/gestures/gesture_types.h"
 #include "ui/gfx/geometry/point.h"
+#include "ui/gfx/geometry/point_f.h"
 #include "ui/gfx/geometry/rect.h"
 
 namespace aura {
 class Window;
-}
+}  // namespace aura
+
+namespace ui {
+class GestureProviderAura;
+}  // namespace ui
 
 namespace ash {
 
-class ASH_EXPORT MagnificationController {
+// MagnificationController controls the Fullscreen Magnifier feature.
+// MagnificationController implements GestureConsumer as it has its own
+// GestureProvider to recognize gestures with screen coordinates of touches.
+// Logical coordinates of touches cannot be used as they are changed with
+// viewport change: scroll, zoom.
+// MagnificationController implements EventRewriter to see and rewrite touch
+// events. Once the controller detects two fingers pinch or scroll, it starts
+// consuming all touch events not to confuse an app or a browser on the screen.
+// It needs to rewrite events to dispatch touch cancel events.
+class ASH_EXPORT MagnificationController : public ui::EventHandler,
+                                           public ui::ImplicitAnimationObserver,
+                                           public aura::WindowObserver,
+                                           public ui::InputMethodObserver,
+                                           public ui::GestureConsumer,
+                                           public ui::EventRewriter {
  public:
   enum ScrollDirection {
     SCROLL_NONE,
@@ -29,29 +55,27 @@
     SCROLL_DOWN
   };
 
-  virtual ~MagnificationController() {}
-
-  // Creates a new MagnificationController. The caller takes ownership of the
-  // returned object.
-  static MagnificationController* CreateInstance();
+  MagnificationController();
+  ~MagnificationController() override;
 
   // Enables (or disables if |enabled| is false) screen magnifier feature.
-  virtual void SetEnabled(bool enabled) = 0;
+  void SetEnabled(bool enabled);
 
   // Returns if the screen magnifier is enabled or not.
-  virtual bool IsEnabled() const = 0;
+  bool IsEnabled() const;
 
   // Enables or disables the feature for keeping the text input focus centered.
-  virtual void SetKeepFocusCentered(bool keep_focus_centered) = 0;
+  void SetKeepFocusCentered(bool keep_focus_centered);
 
   // Returns true if magnifier will keep the focus centered in screen for text
   // input.
-  virtual bool KeepFocusCentered() const = 0;
+  bool KeepFocusCentered() const;
 
   // Sets the magnification ratio. 1.0f means no magnification.
-  virtual void SetScale(float scale, bool animate) = 0;
+  void SetScale(float scale, bool animate);
+
   // Returns the current magnification ratio.
-  virtual float GetScale() const = 0;
+  float GetScale() const { return scale_; }
 
   // Maps the current scale value to an index in the range between the minimum
   // and maximum scale values, and steps up or down the scale depending on the
@@ -59,47 +83,221 @@
   void StepToNextScaleValue(int delta_index);
 
   // Set the top-left point of the magnification window.
-  virtual void MoveWindow(int x, int y, bool animate) = 0;
-  virtual void MoveWindow(const gfx::Point& point, bool animate) = 0;
-  // Returns the current top-left point of the magnification window.
-  virtual gfx::Point GetWindowPosition() const = 0;
+  void MoveWindow(int x, int y, bool animate);
+  void MoveWindow(const gfx::Point& point, bool animate);
 
-  virtual void SetScrollDirection(ScrollDirection direction) = 0;
+  // Returns the current top-left point of the magnification window.
+  gfx::Point GetWindowPosition() const;
+
+  void SetScrollDirection(ScrollDirection direction);
 
   // Returns the view port(i.e. the current visible window)'s Rect in root
   // window coordinates.
-  virtual gfx::Rect GetViewportRect() const = 0;
+  gfx::Rect GetViewportRect() const;
 
   // Follows the focus on web page for non-editable controls.
-  virtual void HandleFocusedNodeChanged(
-      bool is_editable_node,
-      const gfx::Rect& node_bounds_in_screen) = 0;
-
-  // Returns |point_of_interest_in_root_| in MagnificationControllerImpl. This
-  // is the internal variable to stores the last mouse cursor (or last touched)
-  // location. This method is only for test purpose.
-  virtual gfx::Point GetPointOfInterestForTesting() = 0;
-
-  // Returns true if magnifier is still on animation for moving viewport.
-  // This is only used for testing purpose.
-  virtual bool IsOnAnimationForTesting() const = 0;
-
-  // Disables the delay for moving magnifier window in testing mode.
-  virtual void DisableMoveMagnifierDelayForTesting() = 0;
+  void HandleFocusedNodeChanged(bool is_editable_node,
+                                const gfx::Rect& node_bounds_in_screen);
 
   // Switch the magnified root window to |new_root_window|. This does following:
   //  - Unzoom the current root_window.
   //  - Zoom the given new root_window |new_root_window|.
   //  - Switch the target window from current window to |new_root_window|.
-  virtual void SwitchTargetRootWindow(aura::Window* new_root_window,
-                                      bool redraw_original_root) = 0;
+  void SwitchTargetRootWindow(aura::Window* new_root_window,
+                              bool redraw_original_root);
 
- protected:
-  MagnificationController() {}
+  // Returns the last mouse cursor (or last touched) location.
+  gfx::Point GetPointOfInterestForTesting() {
+    return point_of_interest_in_root_;
+  }
 
-  FRIEND_TEST_ALL_PREFIXES(MagnificationControllerTest, AdjustScaleFromScroll);
+  // Returns true if magnifier is still on animation for moving viewport.
+  bool IsOnAnimationForTesting() const { return is_on_animation_; }
+
+  // Disables the delay for moving magnifier window.
+  void DisableMoveMagnifierDelayForTesting() {
+    disable_move_magnifier_delay_ = true;
+  }
 
  private:
+  class GestureProviderClient;
+
+  enum LockedGestureType { NO_GESTURE, ZOOM, SCROLL };
+
+  // ui::ImplicitAnimationObserver overrides:
+  void OnImplicitAnimationsCompleted() override;
+
+  // aura::WindowObserver overrides:
+  void OnWindowDestroying(aura::Window* root_window) override;
+  void OnWindowBoundsChanged(aura::Window* window,
+                             const gfx::Rect& old_bounds,
+                             const gfx::Rect& new_bounds,
+                             ui::PropertyChangeReason reason) override;
+
+  // ui::EventHandler overrides:
+  void OnMouseEvent(ui::MouseEvent* event) override;
+  void OnScrollEvent(ui::ScrollEvent* event) override;
+  void OnTouchEvent(ui::TouchEvent* event) override;
+
+  // ui::EventRewriter overrides:
+  ui::EventRewriteStatus RewriteEvent(
+      const ui::Event& event,
+      std::unique_ptr<ui::Event>* new_event) override;
+  ui::EventRewriteStatus NextDispatchEvent(
+      const ui::Event& last_event,
+      std::unique_ptr<ui::Event>* new_event) override;
+
+  // ui::InputMethodObserver:
+  void OnFocus() override {}
+  void OnBlur() override {}
+  void OnCaretBoundsChanged(const ui::TextInputClient* client) override;
+  void OnTextInputStateChanged(const ui::TextInputClient* client) override {}
+  void OnInputMethodDestroyed(const ui::InputMethod* input_method) override {}
+  void OnShowImeIfNeeded() override {}
+
+  // Redraws the magnification window with the given origin position and the
+  // given scale. Returns true if the window is changed; otherwise, false.
+  // These methods should be called internally just after the scale and/or
+  // the position are changed to redraw the window.
+  bool Redraw(const gfx::PointF& position, float scale, bool animate);
+
+  // Redraws the magnification window with the given origin position in dip and
+  // the given scale. Returns true if the window is changed; otherwise, false.
+  // The last two parameters specify the animation duration and tween type.
+  // If |animation_in_ms| is zero, there will be no animation, and |tween_type|
+  // will be ignored.
+  bool RedrawDIP(const gfx::PointF& position_in_dip,
+                 float scale,
+                 int animation_in_ms,
+                 gfx::Tween::Type tween_type);
+
+  // 1) If the screen is scrolling (i.e. animating) and should scroll further,
+  // it does nothing.
+  // 2) If the screen is scrolling (i.e. animating) and the direction is NONE,
+  // it stops the scrolling animation.
+  // 3) If the direction is set to value other than NONE, it starts the
+  // scrolling/ animation towards that direction.
+  void StartOrStopScrollIfNecessary();
+
+  // Redraw with the given zoom scale keeping the mouse cursor location. In
+  // other words, zoom (or unzoom) centering around the cursor.
+  // Ignore mouse position change after redrawing if |ignore_mouse_change| is
+  // true.
+  void RedrawKeepingMousePosition(float scale,
+                                  bool animate,
+                                  bool ignore_mouse_change);
+
+  void OnMouseMove(const gfx::Point& location);
+
+  // Move the mouse cursot to the given point. Actual move will be done when
+  // the animation is completed. This should be called after animation is
+  // started.
+  void AfterAnimationMoveCursorTo(const gfx::Point& location);
+
+  // Returns if the magnification scale is 1.0 or not (larger then 1.0).
+  bool IsMagnified() const;
+
+  // Returns the rect of the magnification window.
+  gfx::RectF GetWindowRectDIP(float scale) const;
+
+  // Returns the size of the root window.
+  gfx::Size GetHostSizeDIP() const;
+
+  // Correct the given scale value if necessary.
+  void ValidateScale(float* scale);
+
+  // Process pending gestures in |gesture_provider_|. This method returns true
+  // if the controller needs to cancel existing touches.
+  bool ProcessGestures();
+
+  // Moves the view port when |point| is located within
+  // |x_panning_margin| and |y_pannin_margin| to the edge of the visible
+  // window region. The view port will be moved so that the |point| will be
+  // moved to the point where it has |x_target_margin| and |y_target_margin|
+  // to the edge of the visible region.
+  void MoveMagnifierWindowFollowPoint(const gfx::Point& point,
+                                      int x_panning_margin,
+                                      int y_panning_margin,
+                                      int x_target_margin,
+                                      int y_target_margin);
+
+  // Moves the view port to center |point| in magnifier screen.
+  void MoveMagnifierWindowCenterPoint(const gfx::Point& point);
+
+  // Moves the viewport so that |rect| is fully visible. If |rect| is larger
+  // than the viewport horizontally or vertically, the viewport will be moved
+  // to center the |rect| in that dimension.
+  void MoveMagnifierWindowFollowRect(const gfx::Rect& rect);
+
+  // Invoked when |move_magnifier_timer_| fires to move the magnifier window to
+  // follow the caret.
+  void OnMoveMagnifierTimer();
+
+  // Target root window. This must not be NULL.
+  aura::Window* root_window_;
+
+  // True if the magnified window is currently animating a change. Otherwise,
+  // false.
+  bool is_on_animation_ = false;
+
+  bool is_enabled_ = false;
+
+  bool keep_focus_centered_ = false;
+
+  // True if the cursor needs to move the given position after the animation
+  // will be finished. When using this, set |position_after_animation_| as well.
+  bool move_cursor_after_animation_ = false;
+
+  // Stores the position of cursor to be moved after animation.
+  gfx::Point position_after_animation_;
+
+  // Stores the last mouse cursor (or last touched) location. This value is
+  // used on zooming to keep this location visible.
+  gfx::Point point_of_interest_in_root_;
+
+  // Current scale, origin (left-top) position of the magnification window.
+  float scale_;
+  gfx::PointF origin_;
+
+  float original_scale_;
+  gfx::PointF original_origin_;
+
+  ScrollDirection scroll_direction_ = SCROLL_NONE;
+
+  // MagnificationController locks gesture once user performs either scroll or
+  // pinch gesture above those thresholds.
+  LockedGestureType locked_gesture_ = NO_GESTURE;
+
+  // If true, MagnificationController consumes all touch events.
+  bool consume_touch_event_ = false;
+
+  // Number of touch points on the screen.
+  int32_t touch_points_ = 0;
+
+  // Map for holding ET_TOUCH_PRESS events. Those events are used to dispatch
+  // ET_TOUCH_CANCELLED events. Events will be removed from this map when press
+  // events are cancelled, i.e. size of this map can be different from number of
+  // touches on the screen. Key is pointer id.
+  std::map<int32_t, std::unique_ptr<ui::TouchEvent>> press_event_map_;
+
+  std::unique_ptr<GestureProviderClient> gesture_provider_client_;
+
+  // MagnificationCotroller owns its GestureProvider to detect gestures with
+  // screen coordinates of touch events. As MagnificationController changes zoom
+  // level and moves viewport, logical coordinates of touches cannot be used for
+  // gesture detection as they are changed if the controller reacts to gestures.
+  std::unique_ptr<ui::GestureProviderAura> gesture_provider_;
+
+  // Timer for moving magnifier window when it fires.
+  base::OneShotTimer move_magnifier_timer_;
+
+  // Most recent caret position in |root_window_| coordinates.
+  gfx::Point caret_point_;
+
+  // Flag for disabling moving magnifier delay. It can only be true in testing
+  // mode.
+  bool disable_move_magnifier_delay_ = false;
+
   DISALLOW_COPY_AND_ASSIGN(MagnificationController);
 };
 
diff --git a/ash/shell.cc b/ash/shell.cc
index 90944c1..442e5b11 100644
--- a/ash/shell.cc
+++ b/ash/shell.cc
@@ -1090,7 +1090,7 @@
   voice_interaction_controller_ =
       std::make_unique<VoiceInteractionController>();
 
-  magnification_controller_.reset(MagnificationController::CreateInstance());
+  magnification_controller_ = std::make_unique<MagnificationController>();
   mru_window_tracker_ = std::make_unique<MruWindowTracker>();
 
   autoclick_controller_.reset(AutoclickController::CreateInstance());
diff --git a/ash/wm/overview/window_selector_item.cc b/ash/wm/overview/window_selector_item.cc
index fe7ff5b..a4757ef5 100644
--- a/ash/wm/overview/window_selector_item.cc
+++ b/ash/wm/overview/window_selector_item.cc
@@ -788,6 +788,15 @@
   // properly use the updated windows bounds.
   UpdateHeaderLayout(mode, animation_type);
 
+  // Shadow is normally set after an animation is finished. In the case of no
+  // animations, manually set the shadow. Shadow relies on both the window
+  // trasnform and |item_widget_|'s new bounds so set it after SetItemBounds
+  // and UpdateHeaderLayout.
+  if (animation_type == OVERVIEW_ANIMATION_NONE) {
+    SetShadowBounds(
+        base::make_optional(transform_window_.GetTransformedBounds()));
+  }
+
   UpdateBackdropBounds();
 }
 
@@ -1009,7 +1018,12 @@
   if (!IsNewOverviewUi())
     return;
 
-  DCHECK(shadow_);
+  // Shadow is normally turned off during animations and reapplied when they
+  // are finished. On destruction, |shadow_| is cleaned up before
+  // |transform_window_|, which may call this function, so early exit if
+  // |shadow_| is nullptr.
+  if (!shadow_)
+    return;
 
   if (bounds_in_screen == base::nullopt) {
     shadow_->layer()->SetVisible(false);
@@ -1017,10 +1031,12 @@
   }
 
   shadow_->layer()->SetVisible(true);
-  gfx::Rect bounds_in_item = caption_container_view_->GetLocalBounds();
+  gfx::Rect bounds_in_item =
+      gfx::Rect(item_widget_->GetNativeWindow()->GetTargetBounds().size());
   bounds_in_item.Inset(kWindowSelectorMargin, kWindowSelectorMargin);
   bounds_in_item.Inset(0, close_button_->GetPreferredSize().height(), 0, 0);
   bounds_in_item.ClampToCenteredSize(bounds_in_screen.value().size());
+
   shadow_->SetContentBounds(bounds_in_item);
 }
 
@@ -1068,6 +1084,13 @@
   return background_view_->layer()->opacity();
 }
 
+gfx::Rect WindowSelectorItem::GetShadowBoundsForTesting() {
+  if (!shadow_ || !shadow_->layer()->visible())
+    return gfx::Rect();
+
+  return shadow_->content_bounds();
+}
+
 gfx::Rect WindowSelectorItem::GetTargetBoundsInScreen() const {
   return transform_window_.GetTargetBoundsInScreen();
 }
diff --git a/ash/wm/overview/window_selector_item.h b/ash/wm/overview/window_selector_item.h
index 68b9a45c..ffdf9bf 100644
--- a/ash/wm/overview/window_selector_item.h
+++ b/ash/wm/overview/window_selector_item.h
@@ -213,6 +213,7 @@
 
   float GetCloseButtonOpacityForTesting();
   float GetTitlebarOpacityForTesting();
+  gfx::Rect GetShadowBoundsForTesting();
 
  private:
   class CaptionContainerView;
diff --git a/ash/wm/overview/window_selector_unittest.cc b/ash/wm/overview/window_selector_unittest.cc
index e946ceda..2606b56 100644
--- a/ash/wm/overview/window_selector_unittest.cc
+++ b/ash/wm/overview/window_selector_unittest.cc
@@ -328,6 +328,10 @@
     return window_selector()->text_filter_widget_.get();
   }
 
+  void SetGridBounds(WindowGrid* grid, const gfx::Rect& bounds) {
+    grid->bounds_ = bounds;
+  }
+
   gfx::Rect GetGridBounds() {
     if (window_selector())
       return window_selector()->grid_list_[0]->bounds_;
@@ -2751,6 +2755,76 @@
   ToggleOverview();
 }
 
+// Tests that the shadows in overview mode are placed correctly.
+TEST_F(WindowSelectorTest, ShadowBounds) {
+  // Helper function to check if the bounds of a shadow owned by |shadow_parent|
+  // is contained within the bounds of |widget|.
+  auto contains = [](views::Widget* widget, WindowSelectorItem* shadow_parent) {
+    return gfx::Rect(widget->GetNativeWindow()->bounds().size())
+        .Contains(shadow_parent->GetShadowBoundsForTesting());
+  };
+
+  // Helper function which returns the ratio of the shadow owned by
+  // |shadow_parent| width and height.
+  auto shadow_ratio = [](WindowSelectorItem* shadow_parent) {
+    gfx::RectF boundsf = gfx::RectF(shadow_parent->GetShadowBoundsForTesting());
+    return boundsf.width() / boundsf.height();
+  };
+
+  // Add three windows which in overview mode will be considered wide, tall and
+  // normal. Set top view insets to 0, so it is easy to check the ratios of
+  // the shadows match the ratios of the untransformed windows.
+  UpdateDisplay("400x400");
+  std::unique_ptr<aura::Window> wide(CreateWindow(gfx::Rect(10, 10, 400, 100)));
+  std::unique_ptr<aura::Window> tall(CreateWindow(gfx::Rect(10, 10, 100, 400)));
+  std::unique_ptr<aura::Window> normal(
+      CreateWindow(gfx::Rect(10, 10, 200, 200)));
+  wide->SetProperty(aura::client::kTopViewInset, 0);
+  tall->SetProperty(aura::client::kTopViewInset, 0);
+  normal->SetProperty(aura::client::kTopViewInset, 0);
+
+  ToggleOverview();
+  RunAllPendingInMessageLoop();
+  WindowSelectorItem* wide_item = GetWindowItemForWindow(0, wide.get());
+  WindowSelectorItem* tall_item = GetWindowItemForWindow(0, tall.get());
+  WindowSelectorItem* normal_item = GetWindowItemForWindow(0, normal.get());
+
+  views::Widget* wide_widget = item_widget(wide_item);
+  views::Widget* tall_widget = item_widget(tall_item);
+  views::Widget* normal_widget = item_widget(normal_item);
+
+  WindowGrid* grid = window_selector()->grid_list_for_testing()[0].get();
+
+  // Verify all the shadows are within the bounds of their respective item
+  // widgets when the overview windows are positioned without animations.
+  SetGridBounds(grid, gfx::Rect(200, 400));
+  grid->PositionWindows(false);
+  EXPECT_TRUE(contains(wide_widget, wide_item));
+  EXPECT_TRUE(contains(tall_widget, tall_item));
+  EXPECT_TRUE(contains(normal_widget, normal_item));
+
+  // Verify the shadows preserve the ratios of the original windows.
+  EXPECT_NEAR(shadow_ratio(wide_item), 4.f, 0.01f);
+  EXPECT_NEAR(shadow_ratio(tall_item), 0.25f, 0.01f);
+  EXPECT_NEAR(shadow_ratio(normal_item), 1.f, 0.01f);
+
+  // Verify all the shadows are within the bounds of their respective item
+  // widgets when the overview windows are positioned with animations.
+  SetGridBounds(grid, gfx::Rect(200, 400));
+  grid->PositionWindows(true);
+  RunAllPendingInMessageLoop();
+  EXPECT_TRUE(contains(wide_widget, wide_item));
+  EXPECT_TRUE(contains(tall_widget, tall_item));
+  EXPECT_TRUE(contains(normal_widget, normal_item));
+
+  EXPECT_NEAR(shadow_ratio(wide_item), 4.f, 0.01f);
+  EXPECT_NEAR(shadow_ratio(tall_item), 0.25f, 0.01f);
+  EXPECT_NEAR(shadow_ratio(normal_item), 1.f, 0.01f);
+
+  // Test that leaving overview mode cleans up properly.
+  ToggleOverview();
+}
+
 class SplitViewWindowSelectorTest : public WindowSelectorTest {
  public:
   SplitViewWindowSelectorTest() = default;
diff --git a/base/android/java/src/org/chromium/base/BuildInfo.java b/base/android/java/src/org/chromium/base/BuildInfo.java
index a1fbaf38..91b02a6 100644
--- a/base/android/java/src/org/chromium/base/BuildInfo.java
+++ b/base/android/java/src/org/chromium/base/BuildInfo.java
@@ -63,6 +63,10 @@
         };
     }
 
+    private static String nullToEmpty(CharSequence seq) {
+        return seq == null ? "" : seq.toString();
+    }
+
     /**
      * @param packageInfo Package for Chrome/WebView (as opposed to host app).
      */
@@ -86,19 +90,16 @@
             if (sBrowserPackageInfo != null) {
                 packageName = sBrowserPackageInfo.packageName;
                 versionCode = sBrowserPackageInfo.versionCode;
-                versionName = sBrowserPackageInfo.versionName;
+                versionName = nullToEmpty(sBrowserPackageInfo.versionName);
                 sBrowserPackageInfo = null;
             } else {
                 packageName = hostPackageName;
                 versionCode = hostVersionCode;
-                versionName = pi.versionName;
+                versionName = nullToEmpty(pi.versionName);
             }
 
-            CharSequence label = pm.getApplicationLabel(pi.applicationInfo);
-            hostPackageLabel = label == null ? "" : label.toString();
-
-            String value = pm.getInstallerPackageName(packageName);
-            installerPackageName = value == null ? "" : value;
+            hostPackageLabel = nullToEmpty(pm.getApplicationLabel(pi.applicationInfo));
+            installerPackageName = nullToEmpty(pm.getInstallerPackageName(packageName));
 
             PackageInfo gmsPackageInfo = null;
             try {
diff --git a/base/android/library_loader/library_loader_hooks.cc b/base/android/library_loader/library_loader_hooks.cc
index 75e0225..fa46d24 100644
--- a/base/android/library_loader/library_loader_hooks.cc
+++ b/base/android/library_loader/library_loader_hooks.cc
@@ -199,12 +199,12 @@
     JNIEnv* env,
     const JavaParamRef<jclass>& clazz) {
 #if BUILDFLAG(SUPPORTS_CODE_ORDERING)
-  // Calling madvise(MADV_RANDOM) and prefetching the same region have the
-  // opposite effects.
-  // TODO(crbug.com/758566): add library prefetching that only prefetches
-  // regions not madvise(MADV_RANDOM)'d.
-  if (!ShouldDoOrderfileMemoryOptimization()) {
-    return NativeLibraryPrefetcher::ForkAndPrefetchNativeLibrary();
+  if (!ShouldDoOrderfileMemoryOptimization() ||
+      CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kForceNativePrefetch)) {
+    return NativeLibraryPrefetcher::ForkAndPrefetchNativeLibrary(
+        CommandLine::ForCurrentProcess()->HasSwitch(
+            switches::kNativePrefetchOrderedOnly));
   }
 #endif
   return false;
diff --git a/base/android/library_loader/library_prefetcher.cc b/base/android/library_loader/library_prefetcher.cc
index fefbb5e..559f7502 100644
--- a/base/android/library_loader/library_prefetcher.cc
+++ b/base/android/library_loader/library_prefetcher.cc
@@ -183,7 +183,7 @@
 }  // namespace
 
 // static
-bool NativeLibraryPrefetcher::ForkAndPrefetchNativeLibrary() {
+bool NativeLibraryPrefetcher::ForkAndPrefetchNativeLibrary(bool ordered_only) {
 #if defined(CYGPROFILE_INSTRUMENTATION)
   // Avoid forking with cygprofile instrumentation because the child process
   // would create a dump as well.
@@ -200,7 +200,12 @@
   // state of its parent thread. It cannot rely on being able to acquire any
   // lock (unless special care is taken in a pre-fork handler), including being
   // able to call malloc().
-  const auto& range = GetTextRange();
+  std::pair<size_t, size_t> range;
+  if (ordered_only) {
+    range = GetOrderedTextRange();
+  } else {
+    range = GetTextRange();
+  }
 
   pid_t pid = fork();
   if (pid == 0) {
diff --git a/base/android/library_loader/library_prefetcher.h b/base/android/library_loader/library_prefetcher.h
index e18dec2..f16e38c 100644
--- a/base/android/library_loader/library_prefetcher.h
+++ b/base/android/library_loader/library_prefetcher.h
@@ -30,9 +30,11 @@
 class BASE_EXPORT NativeLibraryPrefetcher {
  public:
   // Finds the executable code range, forks a low priority process pre-fetching
-  // it wait()s for the process to exit or die.
+  // it wait()s for the process to exit or die. If ordered_only is true, only
+  // the ordered section is prefetched. See GetOrdrderedTextRange() in
+  // library_prefetcher.cc.
   // Returns true for success.
-  static bool ForkAndPrefetchNativeLibrary();
+  static bool ForkAndPrefetchNativeLibrary(bool ordered_only);
 
   // Returns the percentage of the native library code currently resident in
   // memory, or -1 in case of error.
diff --git a/base/base_switches.cc b/base/base_switches.cc
index ab74d6a..9f33d0bf 100644
--- a/base/base_switches.cc
+++ b/base/base_switches.cc
@@ -132,6 +132,12 @@
 // given in base/android/library_loader/anchor_functions.h, via madvise and
 // changing the library prefetch behavior.
 const char kOrderfileMemoryOptimization[] = "orderfile-memory-optimization";
+// Force prefetching of the native library even if otherwise disabled, eg by
+// --orderfile-memory-optimization.
+const char kForceNativePrefetch[] = "force-native-prefetch";
+// If prefetching is enabled, only prefetch the ordered part of the native
+// library. Has no effect if prefetching is disabled.
+const char kNativePrefetchOrderedOnly[] = "native-prefetch-ordered-only";
 #endif
 
 }  // namespace switches
diff --git a/base/base_switches.h b/base/base_switches.h
index 566ecbb..e5b9453 100644
--- a/base/base_switches.h
+++ b/base/base_switches.h
@@ -47,6 +47,8 @@
 
 #if defined(OS_ANDROID)
 extern const char kOrderfileMemoryOptimization[];
+extern const char kForceNativePrefetch[];
+extern const char kNativePrefetchOrderedOnly[];
 #endif
 
 }  // namespace switches
diff --git a/base/files/dir_reader_posix_unittest.cc b/base/files/dir_reader_posix_unittest.cc
index 87ac6b90..1954cb2f 100644
--- a/base/files/dir_reader_posix_unittest.cc
+++ b/base/files/dir_reader_posix_unittest.cc
@@ -5,6 +5,7 @@
 #include "base/files/dir_reader_posix.h"
 
 #include <fcntl.h>
+#include <limits.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
diff --git a/base/files/file.h b/base/files/file.h
index 1b2f6d4..bb46aa0f 100644
--- a/base/files/file.h
+++ b/base/files/file.h
@@ -78,9 +78,9 @@
                                          // See DeleteOnClose() for details.
   };
 
-  // This enum has been recorded in multiple histograms. If the order of the
-  // fields needs to change, please ensure that those histograms are obsolete or
-  // have been moved to a different enum.
+  // This enum has been recorded in multiple histograms using PlatformFileError
+  // enum. If the order of the fields needs to change, please ensure that those
+  // histograms are obsolete or have been moved to a different enum.
   //
   // FILE_ERROR_ACCESS_DENIED is returned when a call fails because of a
   // filesystem restriction. FILE_ERROR_SECURITY is returned when a browser
diff --git a/base/test/OWNERS b/base/test/OWNERS
index 6f374e6..8b59305 100644
--- a/base/test/OWNERS
+++ b/base/test/OWNERS
@@ -8,3 +8,6 @@
 # For Android-specific changes:
 per-file *android*=file://base/test/android/OWNERS
 per-file BUILD.gn=file://base/test/android/OWNERS
+
+# Linux fontconfig changes
+per-file *fontconfig*=file://base/nix/OWNERS
diff --git a/base/test/fontconfig_util_linux.cc b/base/test/fontconfig_util_linux.cc
index 45b43fd3..cebee78 100644
--- a/base/test/fontconfig_util_linux.cc
+++ b/base/test/fontconfig_util_linux.cc
@@ -75,18 +75,6 @@
       <glob>/usr/share/fonts/truetype/msttcorefonts/Courier_New_Italic.ttf</glob>
     </acceptfont>
     <acceptfont>
-      <glob>/usr/share/fonts/truetype/msttcorefonts/Georgia.ttf</glob>
-    </acceptfont>
-    <acceptfont>
-      <glob>/usr/share/fonts/truetype/msttcorefonts/Georgia_Bold.ttf</glob>
-    </acceptfont>
-    <acceptfont>
-      <glob>/usr/share/fonts/truetype/msttcorefonts/Georgia_Bold_Italic.ttf</glob>
-    </acceptfont>
-    <acceptfont>
-      <glob>/usr/share/fonts/truetype/msttcorefonts/Georgia_Italic.ttf</glob>
-    </acceptfont>
-    <acceptfont>
       <glob>/usr/share/fonts/truetype/msttcorefonts/Impact.ttf</glob>
     </acceptfont>
     <acceptfont>
@@ -260,6 +248,15 @@
     </edit>
   </match>
 
+  <match target="pattern">
+    <test qual="any" name="family">
+      <string>Georgia</string>
+    </test>
+    <edit name="family" mode="assign">
+      <string>Gelasio</string>
+    </edit>
+  </match>
+
   <!-- TODO(thomasanderson): Move these configs to be test-specific. -->
   <match target="pattern">
     <test name="family" compare="eq">
@@ -278,7 +275,7 @@
       <string>SlightHintedGeorgia</string>
     </test>
     <edit name="family" mode="assign">
-      <string>Georgia</string>
+      <string>Gelasio</string>
     </edit>
     <edit name="hintstyle" mode="assign">
       <const>hintslight</const>
diff --git a/build/config/linux/BUILD.gn b/build/config/linux/BUILD.gn
index bee0538e..e3488ab 100644
--- a/build/config/linux/BUILD.gn
+++ b/build/config/linux/BUILD.gn
@@ -2,6 +2,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import("//build/config/c++/c++.gni")
 import("//build/config/linux/pkg_config.gni")
 import("//build/config/ui.gni")
 
@@ -26,7 +27,8 @@
     defines = [ "OS_CHROMEOS" ]
   }
 
-  if (current_cpu == "mipsel") {
+  if ((!is_chromeos || default_toolchain != "//build/toolchain/cros:target") &&
+      (!use_custom_libcxx || current_cpu == "mipsel")) {
     libs = [ "atomic" ]
   }
 }
diff --git a/build/sanitizers/tsan_suppressions.cc b/build/sanitizers/tsan_suppressions.cc
index bbc0303..6e50d6d 100644
--- a/build/sanitizers/tsan_suppressions.cc
+++ b/build/sanitizers/tsan_suppressions.cc
@@ -256,7 +256,7 @@
     "race:base::i18n::SetICUDefaultLocale\n"
 
     // https://crbug.com/794920
-    "race:crash_reporter::InitializeCrashKeys\n"
+    "race:base::debug::SetCrashKeyString\n"
 
     // http://crbug.com/795110
     "race:third_party/fontconfig/*\n"
diff --git a/cc/ipc/cc_param_traits.cc b/cc/ipc/cc_param_traits.cc
index c9ad471..c66518e2 100644
--- a/cc/ipc/cc_param_traits.cc
+++ b/cc/ipc/cc_param_traits.cc
@@ -675,7 +675,7 @@
   DCHECK(p.is_valid());
   WriteParam(m, p.parent_sequence_number());
   WriteParam(m, p.child_sequence_number());
-  WriteParam(m, p.nonce());
+  WriteParam(m, p.embed_token());
 }
 
 bool ParamTraits<viz::LocalSurfaceId>::Read(const base::Pickle* m,
@@ -689,12 +689,12 @@
   if (!ReadParam(m, iter, &child_sequence_number))
     return false;
 
-  base::UnguessableToken nonce;
-  if (!ReadParam(m, iter, &nonce))
+  base::UnguessableToken embed_token;
+  if (!ReadParam(m, iter, &embed_token))
     return false;
 
-  *p =
-      viz::LocalSurfaceId(parent_sequence_number, child_sequence_number, nonce);
+  *p = viz::LocalSurfaceId(parent_sequence_number, child_sequence_number,
+                           embed_token);
   return p->is_valid();
 }
 
@@ -705,7 +705,7 @@
   l->append(", ");
   LogParam(p.child_sequence_number(), l);
   l->append(", ");
-  LogParam(p.nonce(), l);
+  LogParam(p.embed_token(), l);
   l->append(")");
 }
 
diff --git a/chrome/android/chrome_public_apk_tmpl.gni b/chrome/android/chrome_public_apk_tmpl.gni
index cd5bb69d..dff3ec1 100644
--- a/chrome/android/chrome_public_apk_tmpl.gni
+++ b/chrome/android/chrome_public_apk_tmpl.gni
@@ -23,10 +23,6 @@
   "enable_vr=$enable_vr",
 ]
 
-if (use_order_profiling) {
-  default_chrome_public_jinja_variables += [ "use_order_profiling=1" ]
-}
-
 template("chrome_public_apk_tmpl") {
   android_apk(target_name) {
     forward_variables_from(invoker, "*")
diff --git a/chrome/android/java/AndroidManifest.xml b/chrome/android/java/AndroidManifest.xml
index 191ebb8..01c7b889 100644
--- a/chrome/android/java/AndroidManifest.xml
+++ b/chrome/android/java/AndroidManifest.xml
@@ -784,20 +784,12 @@
             android:exported="false">
         </service>
 
-        <!-- Service for decoding images in a sandboxed process.  When
-             use_order_profiling is set, all processes need to be able to write
-             profiling information and thus cannot be sandboxed. Order profiling
-             is used only on bots to optimize binary layout, and is never used
-             for a released version of chrome. -->
+        <!-- Service for decoding images in a sandboxed process. -->
         <service
             android:description="@string/decoder_description"
             android:name="org.chromium.chrome.browser.photo_picker.DecoderService"
             android:exported="false"
-            {% if use_order_profiling is defined %}
-            android:isolatedProcess="false"
-            {% else %}
             android:isolatedProcess="true"
-            {% endif %}
             android:process=":decoder_service" />
 
         <!-- Providers for chrome data. -->
@@ -1037,18 +1029,10 @@
             android:value="{{ num_sandboxed_services }}"/>
 
         {% for i in range(num_sandboxed_services) %}
-        <!-- When use_order_profiling is set, the renderer processes need to be
-             able to write profiling information and thus cannot be
-             sandboxed. Order profiling is used only on bots to optimize binary
-             layout, and is never used for a released version of chrome. -->
         <service android:name="org.chromium.content.app.SandboxedProcessService{{ i }}"
             android:process=":sandboxed_process{{ i }}"
             android:permission="{{ manifest_package }}.permission.CHILD_SERVICE"
-            {% if use_order_profiling is defined %}
-            android:isolatedProcess="false"
-            {% else %}
             android:isolatedProcess="true"
-            {% endif %}
             android:exported="{{sandboxed_service_exported|default(false)}}"
             {% if (sandboxed_service_exported|default(false)) == 'true' %}
             android:externalService="true"
diff --git a/chrome/android/java/res/layout/contextual_suggestions_card.xml b/chrome/android/java/res/layout/contextual_suggestions_card.xml
deleted file mode 100644
index 0ea7dca..0000000
--- a/chrome/android/java/res/layout/contextual_suggestions_card.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright 2017 The Chromium Authors. All rights reserved.
-     Use of this source code is governed by a BSD-style license that can be
-     found in the LICENSE file. -->
-
-<RelativeLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
-    xmlns:chrome="http://schemas.android.com/apk/res-auto"
-    xmlns:tools="http://schemas.android.com/tools"
-    android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    android:background="@drawable/card_single"
-    android:foreground="@drawable/button_borderless_compat">
-
-    <org.chromium.chrome.browser.widget.TintedImageView
-        android:id="@+id/article_thumbnail"
-        android:layout_width="@dimen/snippets_thumbnail_size"
-        android:layout_height="@dimen/snippets_thumbnail_size"
-        android:layout_alignParentTop="true"
-        android:layout_alignParentStart="true"
-        android:scaleType="centerCrop"
-        android:contentDescription="@null"
-        android:src="@null" />
-
-    <ImageView
-        android:id="@+id/video_badge"
-        android:layout_width="@dimen/content_suggestions_card_modern_badge_size"
-        android:layout_height="@dimen/content_suggestions_card_modern_badge_size"
-        android:layout_alignTop="@id/article_thumbnail"
-        android:layout_alignStart="@id/article_thumbnail"
-        android:layout_marginStart="@dimen/content_suggestions_card_modern_badge_margin_start"
-        android:layout_marginTop="@dimen/content_suggestions_card_modern_badge_margin_top"
-        android:contentDescription="@string/accessibility_suggestion_with_video_badge"
-        android:visibility="gone"
-        app:srcCompat="@drawable/ic_play_circle_filled"
-        tools:src="@drawable/ic_play_circle_filled"/>
-
-    <LinearLayout
-        android:id="@+id/text_layout"
-        android:layout_height="wrap_content"
-        android:layout_width="wrap_content"
-        android:layout_toEndOf="@id/article_thumbnail"
-        android:layout_alignParentEnd="true"
-        android:layout_alignParentTop="true"
-        android:layout_toStartOf="@id/article_thumbnail"
-        android:layout_alignWithParentIfMissing="true"
-        android:padding="@dimen/snippets_padding"
-        android:orientation="vertical">
-
-        <org.chromium.ui.widget.TextViewWithLeading
-            android:id="@+id/article_headline"
-            android:layout_width="match_parent"
-            android:layout_height="0dp"
-            android:layout_weight="1"
-            android:ellipsize="end"
-            android:textAppearance="@style/BlackTitle1"
-            chrome:leading="22sp" />
-
-        <LinearLayout
-            tools:ignore="UseCompoundDrawables"
-            android:id="@+id/publisher_bar"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_marginTop="@dimen/snippets_publisher_margin_top"
-            android:orientation="horizontal">
-
-            <!-- The following attributes:
-                 - publisher_bar's android:layout_width="wrap_content"
-                 - article_publisher's android:layout_width="0dp"
-                 - article_publisher's android:layout_weight="1"
-                 - article_publisher's android:ellipsize="end"
-                 - article_age's android:layout_width="wrap_content"
-                 All ensure that when the publisher string is long, it starts to ellipsize before
-                 pushing the article age string and the offline icon off the screen.
-                 See: https://crbug.com/625775 and https://crbug.com/678568 -->
-            <TextView
-                android:id="@+id/article_publisher"
-                android:layout_width="0dp"
-                android:layout_weight="1"
-                android:layout_height="wrap_content"
-                android:drawablePadding="8dp"
-                android:maxLines="1"
-                android:singleLine="true"
-                android:ellipsize="end"
-                android:textSize="12sp"
-                android:textColor="@color/snippets_publisher_name_color"
-                android:textDirection="locale" />
-            <TextView
-                android:id="@+id/article_age"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:maxLines="1"
-                android:textSize="12sp"
-                android:textColor="@color/snippets_publisher_name_color"
-                android:textDirection="locale"/>
-
-            <!-- We can't add this ImageView as a CompoundDrawable to the TextView because we want to
-                 have different paddings between the favicon (which is a compound drawable on the
-                 TextView) and the offline icon. -->
-            <org.chromium.chrome.browser.widget.TintedImageView
-                android:id="@+id/offline_icon"
-                android:layout_width="@dimen/snippets_offline_icon_size"
-                android:layout_height="@dimen/snippets_offline_icon_size"
-                android:layout_marginStart="6dp"
-                android:alpha="0.54"
-                android:src="@drawable/offline_pin_round"
-                android:contentDescription="@string/accessibility_ntp_offline_badge"
-                android:visibility="gone"
-                chrome:chrometint="#000" />
-
-        </LinearLayout>
-
-    </LinearLayout>
-
-</RelativeLayout>
diff --git a/chrome/android/java/res/layout/contextual_suggestions_layout.xml b/chrome/android/java/res/layout/contextual_suggestions_layout.xml
new file mode 100644
index 0000000..0839813
--- /dev/null
+++ b/chrome/android/java/res/layout/contextual_suggestions_layout.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-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. -->
+
+<org.chromium.chrome.browser.suggestions.SuggestionsRecyclerView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:scrollbars="vertical"
+    android:paddingTop="@dimen/bottom_control_container_height" />
\ No newline at end of file
diff --git a/chrome/android/java/res/layout/suggestions_bottom_sheet_content.xml b/chrome/android/java/res/layout/suggestions_bottom_sheet_content.xml
deleted file mode 100644
index 76969cd..0000000
--- a/chrome/android/java/res/layout/suggestions_bottom_sheet_content.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright 2017 The Chromium Authors. All rights reserved.
-     Use of this source code is governed by a BSD-style license that can be
-     found in the LICENSE file. -->
-
-<FrameLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent">
-
-    <org.chromium.chrome.browser.suggestions.SuggestionsRecyclerView
-        android:id="@+id/recycler_view"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:scrollbars="vertical"
-        android:paddingTop="@dimen/chrome_home_suggestions_recycler_view_padding_top" />
-
-    <org.chromium.chrome.browser.widget.LoadingView
-        android:id="@+id/loading_view"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_gravity="center_horizontal" />
-
-</FrameLayout>
diff --git a/chrome/android/java/res/values/dimens.xml b/chrome/android/java/res/values/dimens.xml
index cebddf7..febfcc5 100644
--- a/chrome/android/java/res/values/dimens.xml
+++ b/chrome/android/java/res/values/dimens.xml
@@ -363,8 +363,6 @@
     <dimen name="ntp_suggestions_footer_padding_top">40dp</dimen>
     <dimen name="ntp_suggestions_footer_padding_bottom">18dp</dimen>
     <dimen name="chrome_home_logo_minimum_height">1dp</dimen>
-    <!-- bottom_control_container_height - chrome_home_logo_minimum_height -->
-    <dimen name="chrome_home_suggestions_recycler_view_padding_top">55dp</dimen>
     <dimen name="chrome_home_suggestions_footer_padding_top">24dp</dimen>
     <dimen name="chrome_home_suggestions_footer_padding_bottom">24dp</dimen>
     <dimen name="content_suggestions_card_modern_margin">16dp</dimen>
@@ -375,7 +373,6 @@
     <!-- Used to offset content_suggestions_card_modern_margin applied to the bottom of the
          last card. -->
     <dimen name="content_suggestions_action_modern_margin_top">-16dp</dimen>
-    <dimen name="contextual_carousel_space_between_cards">8dp</dimen>
     <dimen name="md_incognito_ntp_line_spacing">6sp</dimen>
     <dimen name="md_incognito_ntp_padding_left">16dp</dimen>
 
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 646684ab..a9d3207 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java
@@ -66,6 +66,7 @@
 import org.chromium.chrome.browser.compositor.layouts.SceneChangeObserver;
 import org.chromium.chrome.browser.compositor.layouts.content.ContentOffsetProvider;
 import org.chromium.chrome.browser.compositor.layouts.content.TabContentManager;
+import org.chromium.chrome.browser.contextual_suggestions.ContextualSuggestionsCoordinator;
 import org.chromium.chrome.browser.contextualsearch.ContextualSearchFieldTrial;
 import org.chromium.chrome.browser.contextualsearch.ContextualSearchManager;
 import org.chromium.chrome.browser.contextualsearch.ContextualSearchManager.ContextualSearchTabPromotionDelegate;
@@ -115,7 +116,6 @@
 import org.chromium.chrome.browser.snackbar.DataUseSnackbarController;
 import org.chromium.chrome.browser.snackbar.SnackbarManager;
 import org.chromium.chrome.browser.snackbar.SnackbarManager.SnackbarManageable;
-import org.chromium.chrome.browser.suggestions.ContextualSuggestionsManager;
 import org.chromium.chrome.browser.sync.ProfileSyncService;
 import org.chromium.chrome.browser.sync.SyncController;
 import org.chromium.chrome.browser.tab.Tab;
@@ -258,7 +258,7 @@
     private ToolbarManager mToolbarManager;
     private FindToolbarManager mFindToolbarManager;
     private BottomSheet mBottomSheet;
-    private ContextualSuggestionsManager mContextualSuggestionsManager;
+    private ContextualSuggestionsCoordinator mContextualSuggestionsCoordinator;
     private FadingBackgroundView mFadingBackgroundView;
 
     // Time in ms that it took took us to inflate the initial layout
@@ -1134,6 +1134,11 @@
             mBottomSheet = null;
         }
 
+        if (mContextualSuggestionsCoordinator != null) {
+            mContextualSuggestionsCoordinator.destroy();
+            mContextualSuggestionsCoordinator = null;
+        }
+
         if (mTabModelsInitialized) {
             TabModelSelector selector = getTabModelSelector();
             if (selector != null) selector.destroy();
@@ -1259,8 +1264,11 @@
             });
             mFadingBackgroundView.addObserver(mBottomSheet);
 
-            mContextualSuggestionsManager = new ContextualSuggestionsManager(
-                    this, mBottomSheet, getTabModelSelector(), getSnackbarManager());
+            if (ChromeFeatureList.isEnabled(
+                        ChromeFeatureList.CONTEXTUAL_SUGGESTIONS_BOTTOM_SHEET)) {
+                mContextualSuggestionsCoordinator = new ContextualSuggestionsCoordinator(
+                        this, mBottomSheet, getTabModelSelector());
+            }
         }
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java
index 1d3cb16..be2a3bb 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java
@@ -191,9 +191,8 @@
     public static final String CONTEXTUAL_SEARCH_SECOND_TAP = "ContextualSearchSecondTap";
     public static final String CONTEXTUAL_SEARCH_TAP_DISABLE_OVERRIDE =
             "ContextualSearchTapDisableOverride";
-    public static final String CONTEXTUAL_SUGGESTIONS_ABOVE_ARTICLES =
-            "ContextualSuggestionsAboveArticles";
-    public static final String CONTEXTUAL_SUGGESTIONS_CAROUSEL = "ContextualSuggestionsCarousel";
+    public static final String CONTEXTUAL_SUGGESTIONS_BOTTOM_SHEET =
+            "ContextualSuggestionsBottomSheet";
     public static final String CUSTOM_CONTEXT_MENU = "CustomContextMenu";
     public static final String CUSTOM_FEEDBACK_UI = "CustomFeedbackUi";
     // Enables the Data Reduction Proxy menu item in the main menu rather than under Settings on
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextual_suggestions/ContentCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/contextual_suggestions/ContentCoordinator.java
new file mode 100644
index 0000000..1098bc68a
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextual_suggestions/ContentCoordinator.java
@@ -0,0 +1,75 @@
+// 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.
+
+package org.chromium.chrome.browser.contextual_suggestions;
+
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import org.chromium.chrome.R;
+import org.chromium.chrome.browser.modelutil.RecyclerViewModelChangeProcessor;
+import org.chromium.chrome.browser.ntp.snippets.SnippetArticle;
+import org.chromium.chrome.browser.profiles.Profile;
+import org.chromium.chrome.browser.suggestions.SuggestionsRecyclerView;
+import org.chromium.chrome.browser.suggestions.SuggestionsUiDelegate;
+import org.chromium.chrome.browser.widget.displaystyle.UiConfig;
+
+/**
+ * Coordinator for the content sub-component. Responsible for communication with the parent
+ * {@link ContextualSuggestionsCoordinator} and lifecycle of component objects.
+ */
+class ContentCoordinator {
+    private final ContextualSuggestionsModel mModel;
+
+    private SuggestionsRecyclerView mRecyclerView;
+    private RecyclerViewModelChangeProcessor<SnippetArticle, ContextualSuggestionCardViewHolder>
+            mModelChangeProcessor;
+
+    /**
+     * Construct a new {@link ContentCoordinator}.
+     * @param context The {@link Context} used to retrieve resources.
+     * @param parentView The parent {@link View} to which the content will eventually be attached.
+     * @param profile The regular {@link Profile}.
+     * @param uiDelegate The {@link SuggestionsUiDelegate} used to help construct items in the
+     *                   content view.
+     * @param model The {@link ContextualSuggestionsModel} for the component.
+     */
+    ContentCoordinator(Context context, ViewGroup parentView, Profile profile,
+            SuggestionsUiDelegate uiDelegate, ContextualSuggestionsModel model) {
+        mModel = model;
+
+        mRecyclerView = (SuggestionsRecyclerView) LayoutInflater.from(context).inflate(
+                R.layout.contextual_suggestions_layout, parentView, false);
+
+        ContextualSuggestionsAdapter adapter = new ContextualSuggestionsAdapter(
+                context, profile, new UiConfig(mRecyclerView), uiDelegate, mModel);
+        mRecyclerView.setAdapter(adapter);
+
+        mModelChangeProcessor = new RecyclerViewModelChangeProcessor<>(adapter);
+        mModel.addObserver(mModelChangeProcessor);
+    }
+
+    /** @return The content {@link View}. */
+    View getView() {
+        return mRecyclerView;
+    }
+
+    /** @return The vertical scroll offset of the content view. */
+    int getVerticalScrollOffset() {
+        return mRecyclerView.computeVerticalScrollOffset();
+    }
+
+    /** Destroy the content component. */
+    void destroy() {
+        if (mRecyclerView == null) return;
+
+        mRecyclerView.setAdapter(null);
+        mRecyclerView = null;
+
+        mModel.removeObserver(mModelChangeProcessor);
+        mModelChangeProcessor = null;
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextual_suggestions/ContextualSuggestionCardViewHolder.java b/chrome/android/java/src/org/chromium/chrome/browser/contextual_suggestions/ContextualSuggestionCardViewHolder.java
new file mode 100644
index 0000000..fd6d78d
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextual_suggestions/ContextualSuggestionCardViewHolder.java
@@ -0,0 +1,26 @@
+// 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.
+
+package org.chromium.chrome.browser.contextual_suggestions;
+
+import org.chromium.chrome.browser.ntp.ContextMenuManager;
+import org.chromium.chrome.browser.ntp.snippets.SnippetArticleViewHolder;
+import org.chromium.chrome.browser.offlinepages.OfflinePageBridge;
+import org.chromium.chrome.browser.suggestions.SuggestionsRecyclerView;
+import org.chromium.chrome.browser.suggestions.SuggestionsUiDelegate;
+import org.chromium.chrome.browser.widget.displaystyle.UiConfig;
+
+/** Holder for a contextual suggestions card. **/
+public class ContextualSuggestionCardViewHolder extends SnippetArticleViewHolder {
+    ContextualSuggestionCardViewHolder(SuggestionsRecyclerView parent,
+            ContextMenuManager contextMenuManager, SuggestionsUiDelegate uiDelegate,
+            UiConfig uiConfig, OfflinePageBridge offlinePageBridge) {
+        super(parent, contextMenuManager, uiDelegate, uiConfig, offlinePageBridge);
+    }
+
+    @Override
+    public boolean isDismissable() {
+        return false;
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextual_suggestions/ContextualSuggestionsAdapter.java b/chrome/android/java/src/org/chromium/chrome/browser/contextual_suggestions/ContextualSuggestionsAdapter.java
new file mode 100644
index 0000000..7d1a5e5a
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextual_suggestions/ContextualSuggestionsAdapter.java
@@ -0,0 +1,101 @@
+// 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.
+
+package org.chromium.chrome.browser.contextual_suggestions;
+
+import android.content.Context;
+import android.support.v7.widget.RecyclerView;
+import android.view.ViewGroup;
+
+import org.chromium.chrome.R;
+import org.chromium.chrome.browser.modelutil.RecyclerViewAdapter;
+import org.chromium.chrome.browser.ntp.cards.ItemViewType;
+import org.chromium.chrome.browser.ntp.cards.SuggestionsCategoryInfo;
+import org.chromium.chrome.browser.ntp.snippets.ContentSuggestionsCardLayout;
+import org.chromium.chrome.browser.ntp.snippets.KnownCategories;
+import org.chromium.chrome.browser.ntp.snippets.SnippetArticle;
+import org.chromium.chrome.browser.offlinepages.OfflinePageBridge;
+import org.chromium.chrome.browser.profiles.Profile;
+import org.chromium.chrome.browser.suggestions.ContentSuggestionsAdditionalAction;
+import org.chromium.chrome.browser.suggestions.SuggestionsRecyclerView;
+import org.chromium.chrome.browser.suggestions.SuggestionsUiDelegate;
+import org.chromium.chrome.browser.widget.displaystyle.UiConfig;
+
+/**
+ * An adapter that contains the view binder for the content component.
+ */
+class ContextualSuggestionsAdapter
+        extends RecyclerViewAdapter<SnippetArticle, ContextualSuggestionCardViewHolder> {
+    private class ContextualSuggestionsViewBinder
+            implements ViewBinder<SnippetArticle, ContextualSuggestionCardViewHolder> {
+        @Override
+        public ContextualSuggestionCardViewHolder onCreateViewHolder(
+                ViewGroup parent, int viewType) {
+            assert viewType == ItemViewType.SNIPPET;
+
+            // TODO(twellington): Hook up ContextMenuManager.
+            return new ContextualSuggestionCardViewHolder(mRecyclerView, null, mUiDelegate,
+                    mUiConfig, OfflinePageBridge.getForProfile(mProfile));
+        }
+
+        @Override
+        public void onBindViewHolder(
+                ContextualSuggestionCardViewHolder holder, SnippetArticle item) {
+            holder.onBindViewHolder(item, mCategoryInfo);
+        }
+    }
+
+    private final Profile mProfile;
+    private final UiConfig mUiConfig;
+    private final SuggestionsUiDelegate mUiDelegate;
+    private final SuggestionsCategoryInfo mCategoryInfo;
+
+    private SuggestionsRecyclerView mRecyclerView;
+
+    /**
+     * Construct a new {@link ContextualSuggestionsAdapter}.
+     * @param context The {@link Context} used to retrieve resources.
+     * @param profile The regular {@link Profile}.
+     * @param uiConfig The {@link UiConfig} used to adjust view display.
+     * @param uiDelegate The {@link SuggestionsUiDelegate} used to help construct items in the
+     *                   content view.
+     * @param model The {@link ContextualSuggestionsModel} for the component.
+     */
+    ContextualSuggestionsAdapter(Context context, Profile profile, UiConfig uiConfig,
+            SuggestionsUiDelegate uiDelegate, ContextualSuggestionsModel model) {
+        super(model);
+
+        setViewBinder(new ContextualSuggestionsViewBinder());
+
+        mProfile = profile;
+        mUiConfig = uiConfig;
+        mUiDelegate = uiDelegate;
+
+        mCategoryInfo = new SuggestionsCategoryInfo(KnownCategories.CONTEXTUAL,
+                context.getString(R.string.contextual_suggestions_title),
+                ContentSuggestionsCardLayout.FULL_CARD, ContentSuggestionsAdditionalAction.NONE,
+                false, "");
+    }
+
+    @Override
+    @ItemViewType
+    public int getItemViewType(int position) {
+        return ItemViewType.SNIPPET;
+    }
+
+    @Override
+    public void onAttachedToRecyclerView(RecyclerView recyclerView) {
+        mRecyclerView = (SuggestionsRecyclerView) recyclerView;
+    }
+
+    @Override
+    public void onDetachedFromRecyclerView(RecyclerView recyclerView) {
+        mRecyclerView = null;
+    }
+
+    @Override
+    public void onViewRecycled(ContextualSuggestionCardViewHolder holder) {
+        holder.recycle();
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextual_suggestions/ContextualSuggestionsBottomSheetContent.java b/chrome/android/java/src/org/chromium/chrome/browser/contextual_suggestions/ContextualSuggestionsBottomSheetContent.java
new file mode 100644
index 0000000..2518a34
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextual_suggestions/ContextualSuggestionsBottomSheetContent.java
@@ -0,0 +1,48 @@
+// 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.
+
+package org.chromium.chrome.browser.contextual_suggestions;
+
+import android.view.View;
+
+import org.chromium.chrome.browser.widget.bottomsheet.BottomSheet.BottomSheetContent;
+
+/** A {@link BottomSheetContent} that displays contextual suggestions. */
+public class ContextualSuggestionsBottomSheetContent implements BottomSheetContent {
+    private ContentCoordinator mContentCoordinator;
+
+    /**
+     * Construct a new {@link ContextualSuggestionsBottomSheetContent}.
+     * @param contentCoordinator The {@link ContentCoordinator} that manages content to be
+     *                           displayed.
+     */
+    ContextualSuggestionsBottomSheetContent(ContentCoordinator contentCoordinator) {
+        mContentCoordinator = contentCoordinator;
+    }
+
+    @Override
+    public View getContentView() {
+        return mContentCoordinator.getView();
+    }
+
+    @Override
+    public View getToolbarView() {
+        return null;
+    }
+
+    @Override
+    public int getVerticalScrollOffset() {
+        return mContentCoordinator.getVerticalScrollOffset();
+    }
+
+    @Override
+    public void destroy() {
+        mContentCoordinator = null;
+    }
+
+    @Override
+    public boolean applyDefaultTopPadding() {
+        return false;
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextual_suggestions/ContextualSuggestionsCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/contextual_suggestions/ContextualSuggestionsCoordinator.java
new file mode 100644
index 0000000..38bb44ab
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextual_suggestions/ContextualSuggestionsCoordinator.java
@@ -0,0 +1,96 @@
+// 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.
+
+package org.chromium.chrome.browser.contextual_suggestions;
+
+import org.chromium.chrome.browser.ChromeActivity;
+import org.chromium.chrome.browser.ntp.snippets.SuggestionsSource;
+import org.chromium.chrome.browser.profiles.Profile;
+import org.chromium.chrome.browser.suggestions.SuggestionsNavigationDelegate;
+import org.chromium.chrome.browser.suggestions.SuggestionsNavigationDelegateImpl;
+import org.chromium.chrome.browser.suggestions.SuggestionsUiDelegateImpl;
+import org.chromium.chrome.browser.tabmodel.TabModelSelector;
+import org.chromium.chrome.browser.widget.bottomsheet.BottomSheet;
+
+/**
+ * The coordinator for the contextual suggestions UI component. Manages communication with other
+ * parts of the UI-layer and lifecycle of shared component objects.
+ *
+ * This parent coordinator manages two sub-components, controlled by {@link ContentCoordinator}
+ * and {@link ToolbarCoordinator}. These sub-components each have their own views and view binders.
+ * They share a {@link ContextualSuggestionsMediator} and {@link ContextualSuggestionsModel}.
+ */
+public class ContextualSuggestionsCoordinator {
+    private ChromeActivity mActivity;
+    private BottomSheet mBottomSheet;
+    private Profile mProfile;
+
+    private ContextualSuggestionsModel mModel;
+    private ContextualSuggestionsMediator mMediator;
+    private ContentCoordinator mContentCoordinator;
+
+    private SuggestionsUiDelegateImpl mUiDelegate;
+
+    private ContextualSuggestionsBottomSheetContent mBottomSheetContent;
+
+    /**
+     * Construct a new {@link ContextualSuggestionsCoordinator}.
+     * @param activity The containing {@link ChromeActivity}.
+     * @param bottomSheet The {@link BottomSheet} where contextual suggestions will be displayed.
+     * @param tabModelSelector The {@link TabModelSelector} for the activity.
+     */
+    public ContextualSuggestionsCoordinator(
+            ChromeActivity activity, BottomSheet bottomSheet, TabModelSelector tabModelSelector) {
+        mActivity = activity;
+        mBottomSheet = bottomSheet;
+        mProfile = Profile.getLastUsedProfile().getOriginalProfile();
+
+        mModel = new ContextualSuggestionsModel();
+        mMediator = new ContextualSuggestionsMediator(mProfile, tabModelSelector, this, mModel);
+
+        SuggestionsSource suggestionsSource = mMediator.getSuggestionsSource();
+        SuggestionsNavigationDelegate navigationDelegate = new SuggestionsNavigationDelegateImpl(
+                mActivity, mProfile, mBottomSheet, tabModelSelector);
+        mUiDelegate = new SuggestionsUiDelegateImpl(suggestionsSource, new DummyEventReporter(),
+                navigationDelegate, mProfile, mBottomSheet,
+                mActivity.getChromeApplication().getReferencePool(),
+                mActivity.getSnackbarManager());
+    }
+
+    /** Called when the containing activity is destroyed. */
+    public void destroy() {
+        mMediator.destroy();
+
+        if (mContentCoordinator != null) mContentCoordinator.destroy();
+        if (mBottomSheetContent != null) mBottomSheetContent.destroy();
+    }
+
+    /**
+     * Displays contextual suggestions in the {@link BottomSheet}.
+     */
+    void displaySuggestions() {
+        // TODO(twellington): Introduce another method that creates bottom sheet content with only
+        // a toolbar view when suggestions are fist available, and use this method to construct the
+        // content view when the sheet is opened.
+        mContentCoordinator =
+                new ContentCoordinator(mActivity, mBottomSheet, mProfile, mUiDelegate, mModel);
+        mBottomSheetContent = new ContextualSuggestionsBottomSheetContent(mContentCoordinator);
+        mBottomSheet.showContent(mBottomSheetContent);
+    }
+
+    /** Removes contextual suggestions from the {@link BottomSheet}. */
+    void removeSuggestions() {
+        if (mContentCoordinator != null) {
+            mContentCoordinator.destroy();
+            mContentCoordinator = null;
+        }
+
+        if (mBottomSheetContent == null) return;
+
+        mBottomSheet.showContent(null);
+
+        mBottomSheetContent.destroy();
+        mBottomSheetContent = null;
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextual_suggestions/ContextualSuggestionsMediator.java b/chrome/android/java/src/org/chromium/chrome/browser/contextual_suggestions/ContextualSuggestionsMediator.java
new file mode 100644
index 0000000..f42db7b4
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextual_suggestions/ContextualSuggestionsMediator.java
@@ -0,0 +1,152 @@
+// 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.
+
+package org.chromium.chrome.browser.contextual_suggestions;
+
+import android.support.annotation.Nullable;
+import android.text.TextUtils;
+import android.webkit.URLUtil;
+
+import org.chromium.base.ContextUtils;
+import org.chromium.chrome.browser.ntp.snippets.SnippetArticle;
+import org.chromium.chrome.browser.ntp.snippets.SnippetsBridge;
+import org.chromium.chrome.browser.ntp.snippets.SuggestionsSource;
+import org.chromium.chrome.browser.profiles.Profile;
+import org.chromium.chrome.browser.tab.EmptyTabObserver;
+import org.chromium.chrome.browser.tab.Tab;
+import org.chromium.chrome.browser.tab.TabObserver;
+import org.chromium.chrome.browser.tabmodel.TabModel.TabSelectionType;
+import org.chromium.chrome.browser.tabmodel.TabModelSelector;
+import org.chromium.chrome.browser.tabmodel.TabModelSelectorTabModelObserver;
+import org.chromium.chrome.browser.util.UrlUtilities;
+import org.chromium.ui.widget.Toast;
+
+import java.util.ArrayList;
+
+/**
+ * A mediator for the contextual suggestions UI component responsible for interacting with
+ * the contextual suggestions backend, updating the model, and communicating with the
+ * component coordinator(s).
+ */
+class ContextualSuggestionsMediator {
+    private ContextualSuggestionsCoordinator mCoordinator;
+    private ContextualSuggestionsModel mModel;
+
+    private SnippetsBridge mBridge;
+
+    private final TabModelSelectorTabModelObserver mTabModelObserver;
+    private final TabObserver mTabObserver;
+    private Tab mLastTab;
+
+    @Nullable
+    private String mCurrentContextUrl;
+
+    /**
+     * Construct a new {@link ContextualSuggestionsMediator}.
+     * @param profile The regular {@link Profile}.
+     * @param tabModelSelector The {@link TabModelSelector} for the containing activity.
+     * @param coordinator The {@link ContextualSuggestionsCoordinator} for the component.
+     * @param model The {@link ContextualSuggestionsModel} for the component.
+     */
+    ContextualSuggestionsMediator(Profile profile, TabModelSelector tabModelSelector,
+            ContextualSuggestionsCoordinator coordinator, ContextualSuggestionsModel model) {
+        mCoordinator = coordinator;
+        mModel = model;
+
+        mBridge = new SnippetsBridge(Profile.getLastUsedProfile());
+
+        // TODO(twellington): Remove the following code for tab observing after triggering logic
+        // moves to the C++ layer.
+        mTabObserver = new EmptyTabObserver() {
+            @Override
+            public void onUpdateUrl(Tab tab, String url) {
+                refresh(url);
+            }
+        };
+
+        mTabModelObserver = new TabModelSelectorTabModelObserver(tabModelSelector) {
+            @Override
+            public void didSelectTab(Tab tab, TabSelectionType type, int lastId) {
+                updateCurrentTab(tab);
+            }
+        };
+
+        updateCurrentTab(tabModelSelector.getCurrentTab());
+    }
+
+    /**
+     * @return The {@link SuggestionsSource} used to fetch suggestions.
+     *
+     * TODO(twellington): This method is needed to construct {@link SuggestionsUiDelegateImpl} in
+     * the coordinator. Try to remove this dependency.
+     */
+    SuggestionsSource getSuggestionsSource() {
+        return mBridge;
+    }
+
+    /** Destroys the mediator. */
+    void destroy() {
+        if (mLastTab != null) {
+            mLastTab.removeObserver(mTabObserver);
+            mLastTab = null;
+        }
+        mTabModelObserver.destroy();
+    }
+
+    // TODO(twellington): Remove this method after triggering logic moves to the C++ layer.
+    private void refresh(@Nullable final String newUrl) {
+        if (!URLUtil.isNetworkUrl(newUrl)) {
+            clearSuggestions();
+            return;
+        }
+
+        // Do nothing if there are already suggestions in the suggestions list for the new context.
+        if (isContextTheSame(newUrl)) return;
+
+        // Context has changed, so we want to remove any old suggestions from the section.
+        clearSuggestions();
+        mCurrentContextUrl = newUrl;
+
+        Toast.makeText(ContextUtils.getApplicationContext(), "Fetching suggestions...",
+                     Toast.LENGTH_SHORT)
+                .show();
+
+        mBridge.fetchContextualSuggestions(newUrl, (suggestions) -> {
+            // Avoiding double fetches causing suggestions for incorrect context.
+            if (!TextUtils.equals(newUrl, mCurrentContextUrl)) return;
+
+            Toast.makeText(ContextUtils.getApplicationContext(),
+                         suggestions.size() + " suggestions fetched", Toast.LENGTH_SHORT)
+                    .show();
+
+            if (suggestions.size() > 0) {
+                mModel.setSuggestions(suggestions);
+                mCoordinator.displaySuggestions();
+            };
+        });
+    }
+
+    private void clearSuggestions() {
+        mModel.setSuggestions(new ArrayList<SnippetArticle>());
+        mCoordinator.removeSuggestions();
+    }
+
+    private boolean isContextTheSame(String newUrl) {
+        return UrlUtilities.urlsMatchIgnoringFragments(newUrl, mCurrentContextUrl);
+    }
+
+    /**
+     * Update the current tab and refresh suggestions.
+     * @param tab The current {@link Tab}.
+     */
+    private void updateCurrentTab(Tab tab) {
+        if (mLastTab != null) mLastTab.removeObserver(mTabObserver);
+
+        mLastTab = tab;
+        if (mLastTab == null) return;
+
+        mLastTab.addObserver(mTabObserver);
+        refresh(mLastTab.getUrl());
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextual_suggestions/ContextualSuggestionsModel.java b/chrome/android/java/src/org/chromium/chrome/browser/contextual_suggestions/ContextualSuggestionsModel.java
new file mode 100644
index 0000000..3abeb49
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextual_suggestions/ContextualSuggestionsModel.java
@@ -0,0 +1,51 @@
+// 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.
+
+package org.chromium.chrome.browser.contextual_suggestions;
+
+import org.chromium.chrome.browser.modelutil.ListObservable;
+import org.chromium.chrome.browser.ntp.snippets.SnippetArticle;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/** A model for the contextual suggestions UI component. */
+class ContextualSuggestionsModel extends ListObservable<SnippetArticle> {
+    private List<SnippetArticle> mSuggestions = new ArrayList<>();
+
+    /**
+     * @param suggestions The list of current suggestions. May be an empty list if no
+     *                    suggestions are available.
+     */
+    void setSuggestions(List<SnippetArticle> suggestions) {
+        assert suggestions != null;
+
+        if (suggestions.size() == 0 && mSuggestions.size() == 0) return;
+
+        int oldLength = getItemCount();
+        mSuggestions = suggestions;
+
+        if (oldLength != 0) notifyItemRangeRemoved(0, oldLength);
+        if (mSuggestions.size() != 0) {
+            notifyItemRangeInserted(0, mSuggestions.size());
+        }
+    }
+
+    /** @return The list of current suggestions. */
+    List<SnippetArticle> getSuggestions() {
+        return mSuggestions;
+    }
+
+    @Override
+    public int getItemCount() {
+        return mSuggestions.size();
+    }
+
+    @Override
+    public SnippetArticle getItem(int position) {
+        assert position < mSuggestions.size();
+
+        return mSuggestions.get(position);
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextual_suggestions/DummyEventReporter.java b/chrome/android/java/src/org/chromium/chrome/browser/contextual_suggestions/DummyEventReporter.java
new file mode 100644
index 0000000..292040e
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextual_suggestions/DummyEventReporter.java
@@ -0,0 +1,36 @@
+// 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.
+
+package org.chromium.chrome.browser.contextual_suggestions;
+
+import org.chromium.chrome.browser.ntp.cards.ActionItem;
+import org.chromium.chrome.browser.ntp.snippets.SnippetArticle;
+import org.chromium.chrome.browser.suggestions.SuggestionsEventReporter;
+import org.chromium.chrome.browser.suggestions.SuggestionsRanker;
+
+/** A dummy {@link SuggestionsEventReporter} to use until a real one replaces it. */
+class DummyEventReporter implements SuggestionsEventReporter {
+    @Override
+    public void onSurfaceOpened() {}
+
+    @Override
+    public void onPageShown(
+            int[] categories, int[] suggestionsPerCategory, boolean[] isCategoryVisible) {}
+
+    @Override
+    public void onSuggestionShown(SnippetArticle suggestion) {}
+
+    @Override
+    public void onSuggestionOpened(SnippetArticle suggestion, int windowOpenDisposition,
+            SuggestionsRanker suggestionsRanker) {}
+
+    @Override
+    public void onSuggestionMenuOpened(SnippetArticle suggestion) {}
+
+    @Override
+    public void onMoreButtonShown(ActionItem category) {}
+
+    @Override
+    public void onMoreButtonClicked(ActionItem category) {}
+}
\ No newline at end of file
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextual_suggestions/OWNERS b/chrome/android/java/src/org/chromium/chrome/browser/contextual_suggestions/OWNERS
new file mode 100644
index 0000000..9037c57
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextual_suggestions/OWNERS
@@ -0,0 +1,5 @@
+file://chrome/android/java/src/org/chromium/chrome/browser/ntp/OWNERS
+
+fgorski@chromium.org
+
+# COMPONENT: UI>Browser>ContentSuggestions>Explore
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/modelutil/ListObservable.java b/chrome/android/java/src/org/chromium/chrome/browser/modelutil/ListObservable.java
new file mode 100644
index 0000000..0653cc2
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/modelutil/ListObservable.java
@@ -0,0 +1,121 @@
+// 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.
+
+package org.chromium.chrome.browser.modelutil;
+
+import android.support.annotation.Nullable;
+
+import org.chromium.base.ObserverList;
+
+/**
+ * A base class for models maintaining a list of items. Note that ListObservable models do not need
+ * to be implemented as a list. Internally they may use any structure to organize their items.
+ *
+ * @param <E> The type of items held by the model.
+ */
+public abstract class ListObservable<E> {
+    /**
+     * An observer to be notified of changes to a {@link ListObservable}.
+     *
+     * @param <E> The type of items held by the observed model.
+     */
+    public interface ListObserver<E> {
+        /**
+         * Notifies that {@code count} items starting at position {@code index} under the
+         * {@code source} have been added.
+         *
+         * @param source The list to which items have been added.
+         * @param index The starting position of the range of added items.
+         * @param count The number of added items.
+         */
+        void onItemRangeInserted(ListObservable<E> source, int index, int count);
+
+        /**
+         * Notifies that {@code count} items starting at position {@code index} under the
+         * {@code source} have been removed.
+         *
+         * @param source The list from which items have been removed.
+         * @param index The starting position of the range of removed items.
+         * @param count The number of removed items.
+         */
+        void onItemRangeRemoved(ListObservable<E> source, int index, int count);
+
+        /**
+         * Notifies that {@code count} items starting at position {@code index} under the
+         * {@code source} have changed, with an optional payload object.
+         *
+         * @param source The list whose items have changed.
+         * @param index The starting position of the range of changed items.
+         * @param count The number of changed items.
+         * @param payload Optional parameter, use {@code null} to identify a "full" update.
+         */
+        void onItemRangeChanged(
+                ListObservable<E> source, int index, int count, @Nullable Object payload);
+    }
+
+    private final ObserverList<ListObserver<E>> mObservers = new ObserverList<>();
+
+    /** @return The total number of items held by the model. */
+    public abstract int getItemCount();
+
+    /**
+     * Retrieve the item at the specified {@code position}.
+     *
+     * @param position The position of the item to retrieve.
+     * @return The item at the specified {@code position}.
+     */
+    public abstract E getItem(int position);
+
+    /**
+     * @param observer An observer to be notified of changes to the model.
+     */
+    public void addObserver(ListObserver<E> observer) {
+        mObservers.addObserver(observer);
+    }
+
+    /** @param observer The observer to remove. */
+    public void removeObserver(ListObserver<E> observer) {
+        mObservers.removeObserver(observer);
+    }
+
+    /**
+     * Notifies observers that {@code count} items starting at position {@code index} have been
+     * added.
+     *
+     * @param index The starting position of the range of added items.
+     * @param count The number of added items.
+     */
+    protected void notifyItemRangeInserted(int index, int count) {
+        for (ListObserver<E> observer : mObservers) {
+            observer.onItemRangeInserted(this, index, count);
+        }
+    }
+
+    /**
+     * Notifies observes that {@code count} items starting at position {@code index} have been
+     * removed.
+     *
+     * @param index The starting position of the range of removed items.
+     * @param count The number of removed items.
+     */
+    protected void notifyItemRangeRemoved(int index, int count) {
+        for (ListObserver<E> observer : mObservers) {
+            observer.onItemRangeRemoved(this, index, count);
+        }
+    }
+
+    /**
+     * Notifies observers that {@code count} items starting at position {@code index} under the
+     * {@code source} have changed, with an optional payload object.
+     *
+     * @param index The starting position of the range of changed items.
+     * @param count The number of changed items.
+     * @param payload Optional parameter, use {@code null} to identify a "full" update.
+     */
+    protected void notifyItemRangeChanged(int index, int count, @Nullable Object payload) {
+        for (ListObserver<E> observer : mObservers) {
+            observer.onItemRangeChanged(this, index, count, payload);
+        }
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/modelutil/OWNERS b/chrome/android/java/src/org/chromium/chrome/browser/modelutil/OWNERS
new file mode 100644
index 0000000..86d8a9b8
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/modelutil/OWNERS
@@ -0,0 +1,2 @@
+bauerb@chromium.org
+twellington@chromium.org
\ No newline at end of file
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/modelutil/RecyclerViewAdapter.java b/chrome/android/java/src/org/chromium/chrome/browser/modelutil/RecyclerViewAdapter.java
new file mode 100644
index 0000000..ee9bde1a
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/modelutil/RecyclerViewAdapter.java
@@ -0,0 +1,83 @@
+// 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.
+
+package org.chromium.chrome.browser.modelutil;
+
+import android.support.v7.widget.RecyclerView;
+import android.support.v7.widget.RecyclerView.ViewHolder;
+import android.view.ViewGroup;
+
+/**
+ * An adapter that uses a {@link ViewBinder} to bind items in a {@link ListObservable} model to
+ * {@link ViewHolder}s.
+ *
+ * @param <E> The type of items held by the {@link ListObservable} model.
+ * @param <VH> The {@link ViewHolder} type for the {@link RecyclerView}.
+ */
+public class RecyclerViewAdapter<E, VH extends ViewHolder> extends RecyclerView.Adapter<VH> {
+    /**
+     * A view binder used to bind items in the {@link ListObservable} model to {@link ViewHolder}s.
+     *
+     * @param <E> The type of items held by the {@link ListObservable} model.
+     * @param <VH> The {@link ViewHolder} type for the {@link RecyclerView}.
+     */
+    public interface ViewBinder<E, VH> {
+        /**
+         * Called when the {@link RecyclerView} needs a new {@link ViewHolder} of the given
+         * {@code viewType} to represent an item.
+         *
+         * @param parent The {@link ViewGroup} into which the new {@link View} will be added after
+         *               it's bound to an adapter position.
+         * @param viewType The view type of the new {@link View}.
+         * @return A new {@link ViewHolder} that holds a {@link View} of the given view type.
+         */
+        VH onCreateViewHolder(ViewGroup parent, int viewType);
+
+        /**
+         * Called to display the {@code item} in the provided {@code holder}.
+         *
+         * @param holder The {@link ViewHolder} which should be updated to represent {@code item}.
+         * @param item The item to be bound.
+         */
+        void onBindViewHolder(VH holder, E item);
+    }
+
+    protected final ListObservable<E> mModel;
+
+    private ViewBinder<E, VH> mViewBinder;
+
+    /**
+     * Construct a new {@link RecyclerViewAdapter}.
+     * @param model The {@link ListObservable} model used to retrieve items to display in the
+     *              {@link RecyclerView}.
+     */
+    public RecyclerViewAdapter(ListObservable<E> model) {
+        mModel = model;
+    }
+
+    /**
+     * Set the {@link ViewBinder} to use with this adapter.
+     *
+     * @param viewBinder The {@link ViewBinder} used to bind items in the {@link ListObservable}
+     *                   model to {@link ViewHolder}s.
+     */
+    public void setViewBinder(ViewBinder<E, VH> viewBinder) {
+        mViewBinder = viewBinder;
+    }
+
+    @Override
+    public int getItemCount() {
+        return mModel.getItemCount();
+    }
+
+    @Override
+    public VH onCreateViewHolder(ViewGroup parent, int viewType) {
+        return mViewBinder.onCreateViewHolder(parent, viewType);
+    }
+
+    @Override
+    public void onBindViewHolder(VH holder, int position) {
+        mViewBinder.onBindViewHolder(holder, mModel.getItem(position));
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/modelutil/RecyclerViewModelChangeProcessor.java b/chrome/android/java/src/org/chromium/chrome/browser/modelutil/RecyclerViewModelChangeProcessor.java
new file mode 100644
index 0000000..9d53c95d
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/modelutil/RecyclerViewModelChangeProcessor.java
@@ -0,0 +1,47 @@
+// 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.
+
+package org.chromium.chrome.browser.modelutil;
+
+import android.support.v7.widget.RecyclerView;
+import android.support.v7.widget.RecyclerView.ViewHolder;
+
+import org.chromium.chrome.browser.modelutil.ListObservable.ListObserver;
+
+/**
+ * A model change processor for use with a {@link RecyclerView}. The
+ * {@link RecyclerViewModelChangeProcessor} should be registered as an observer of a
+ * {@link ListObservable} model. Notifies the associated {@link RecyclerViewAdapter<E, VH>} of
+ * changes to the model.
+ *
+ * @param <E> The type of items held by the {@link ListObservable} model.
+ * @param <VH> The {@link ViewHolder} type for the RecyclerView.
+ */
+public class RecyclerViewModelChangeProcessor<E, VH extends ViewHolder> implements ListObserver<E> {
+    private RecyclerViewAdapter<E, VH> mAdapter;
+
+    /**
+     * Constructs a new {@link RecyclerViewModelChangeProcessor}.
+     * @param adapter The {@link RecyclerViewAdapter<E, VH>} to be notified of changes to a
+     *                {@link ListObservable} model.
+     */
+    public RecyclerViewModelChangeProcessor(RecyclerViewAdapter<E, VH> adapter) {
+        mAdapter = adapter;
+    }
+
+    @Override
+    public void onItemRangeInserted(ListObservable<E> source, int index, int count) {
+        mAdapter.notifyItemRangeInserted(index, count);
+    }
+
+    @Override
+    public void onItemRangeRemoved(ListObservable<E> source, int index, int count) {
+        mAdapter.notifyItemRangeRemoved(index, count);
+    }
+
+    @Override
+    public void onItemRangeChanged(ListObservable<E> source, int index, int count, Object payload) {
+        mAdapter.notifyItemRangeChanged(index, count, payload);
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageView.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageView.java
index 21fe777..0f91d89 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageView.java
@@ -317,8 +317,7 @@
         // Set up snippets
         NewTabPageAdapter newTabPageAdapter =
                 new NewTabPageAdapter(mManager, mNewTabPageLayout, /* logoView = */ null, mUiConfig,
-                        offlinePageBridge, mContextMenuManager, /* tileGroupDelegate = */ null,
-                        /* suggestionsCarousel = */ null);
+                        offlinePageBridge, mContextMenuManager, /* tileGroupDelegate = */ null);
         newTabPageAdapter.refreshSuggestions();
         mRecyclerView.setAdapter(newTabPageAdapter);
         mRecyclerView.getLinearLayoutManager().scrollToPosition(scrollPosition);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/CardViewHolder.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/CardViewHolder.java
index e3f2f38e..8c775f17 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/CardViewHolder.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/CardViewHolder.java
@@ -332,7 +332,6 @@
             case ItemViewType.PROGRESS:
             case ItemViewType.FOOTER:
             case ItemViewType.ALL_DISMISSED:
-            case ItemViewType.CAROUSEL:
                 return false;
             default:
                 assert false;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/ItemViewType.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/ItemViewType.java
index eaf25ec..4026642 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/ItemViewType.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/ItemViewType.java
@@ -7,8 +7,6 @@
 import android.support.annotation.IntDef;
 import android.support.v7.widget.RecyclerView.Adapter;
 
-import org.chromium.chrome.browser.suggestions.SuggestionsCarousel;
-
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 
@@ -20,7 +18,7 @@
 @IntDef({ItemViewType.ABOVE_THE_FOLD, ItemViewType.LOGO, ItemViewType.SITE_SECTION,
         ItemViewType.HEADER, ItemViewType.SNIPPET, ItemViewType.SPACING, ItemViewType.STATUS,
         ItemViewType.PROGRESS, ItemViewType.ACTION, ItemViewType.FOOTER, ItemViewType.PROMO,
-        ItemViewType.ALL_DISMISSED, ItemViewType.CAROUSEL})
+        ItemViewType.ALL_DISMISSED})
 @Retention(RetentionPolicy.SOURCE)
 public @interface ItemViewType {
     /**
@@ -95,11 +93,4 @@
      * @see Adapter#getItemViewType(int)
      */
     int ALL_DISMISSED = 12;
-
-    /**
-     * View type for a {@link SuggestionsCarousel}.
-     *
-     * @see Adapter#getItemViewType(int)
-     */
-    int CAROUSEL = 13;
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapter.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapter.java
index 6e4fdeb..da80fca 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapter.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapter.java
@@ -24,11 +24,9 @@
 import org.chromium.chrome.browser.ntp.snippets.SnippetsBridge;
 import org.chromium.chrome.browser.ntp.snippets.SuggestionsSource;
 import org.chromium.chrome.browser.offlinepages.OfflinePageBridge;
-import org.chromium.chrome.browser.suggestions.ContextualSuggestionsSection;
 import org.chromium.chrome.browser.suggestions.DestructionObserver;
 import org.chromium.chrome.browser.suggestions.LogoItem;
 import org.chromium.chrome.browser.suggestions.SiteSection;
-import org.chromium.chrome.browser.suggestions.SuggestionsCarousel;
 import org.chromium.chrome.browser.suggestions.SuggestionsConfig;
 import org.chromium.chrome.browser.suggestions.SuggestionsRecyclerView;
 import org.chromium.chrome.browser.suggestions.SuggestionsUiDelegate;
@@ -60,8 +58,6 @@
     private final @Nullable AboveTheFoldItem mAboveTheFold;
     private final @Nullable LogoItem mLogo;
     private final @Nullable SiteSection mSiteSection;
-    private final SuggestionsCarousel mSuggestionsCarousel;
-    private final ContextualSuggestionsSection mContextualSuggestions;
     private final SectionList mSections;
     private final @Nullable SignInPromo mSigninPromo;
     private final AllDismissedItem mAllDismissed;
@@ -81,40 +77,10 @@
      * @param offlinePageBridge used to determine if articles are available.
      * @param contextMenuManager used to build context menus.
      * @param tileGroupDelegate if not null this is used to build a {@link SiteSection}.
-     * @param suggestionsCarousel if not null this is used to build a carousel showing contextual
-     *         suggestions.
      */
     public NewTabPageAdapter(SuggestionsUiDelegate uiDelegate, @Nullable View aboveTheFoldView,
             @Nullable LogoView logoView, UiConfig uiConfig, OfflinePageBridge offlinePageBridge,
-            ContextMenuManager contextMenuManager, @Nullable TileGroup.Delegate tileGroupDelegate,
-            @Nullable SuggestionsCarousel suggestionsCarousel) {
-        this(uiDelegate, aboveTheFoldView, logoView, uiConfig, offlinePageBridge,
-                contextMenuManager, tileGroupDelegate, suggestionsCarousel, null);
-    }
-
-    /**
-     * Creates the adapter that will manage all the cards to display on the NTP.
-     * @param uiDelegate used to interact with the rest of the system.
-     * @param aboveTheFoldView the layout encapsulating all the above-the-fold elements
-     *         (logo, search box, most visited tiles), or null if only suggestions should
-     *         be displayed.
-     * @param logoView the view for the logo, which may be provided when {@code aboveTheFoldView} is
-     *         null. They are not expected to be both non-null as that would lead to showing the
-     *         logo twice.
-     * @param uiConfig the NTP UI configuration, to be passed to created views.
-     * @param offlinePageBridge used to determine if articles are available.
-     * @param contextMenuManager used to build context menus.
-     * @param tileGroupDelegate if not null this is used to build a {@link SiteSection}.
-     * @param suggestionsCarousel if not null this is used to build a carousel showing contextual
-     *         suggestions.
-     * @param suggestionsSection if not null this is used to build a section showing contextual
-     *         suggestions.
-     */
-    public NewTabPageAdapter(SuggestionsUiDelegate uiDelegate, @Nullable View aboveTheFoldView,
-            @Nullable LogoView logoView, UiConfig uiConfig, OfflinePageBridge offlinePageBridge,
-            ContextMenuManager contextMenuManager, @Nullable TileGroup.Delegate tileGroupDelegate,
-            @Nullable SuggestionsCarousel suggestionsCarousel,
-            @Nullable ContextualSuggestionsSection suggestionsSection) {
+            ContextMenuManager contextMenuManager, @Nullable TileGroup.Delegate tileGroupDelegate) {
         assert !(aboveTheFoldView != null && logoView != null);
 
         mUiDelegate = uiDelegate;
@@ -142,14 +108,7 @@
             mRoot.addChild(mLogo);
         }
 
-        mContextualSuggestions = suggestionsSection;
-        mSuggestionsCarousel = suggestionsCarousel;
-        if (suggestionsCarousel != null) {
-            assert ChromeFeatureList.isEnabled(ChromeFeatureList.CONTEXTUAL_SUGGESTIONS_CAROUSEL);
-            mRoot.addChild(mSuggestionsCarousel);
-        }
-
-        if (tileGroupDelegate == null || mContextualSuggestions != null) {
+        if (tileGroupDelegate == null) {
             mSiteSection = null;
         } else {
             mSiteSection = new SiteSection(uiDelegate, mContextMenuManager, tileGroupDelegate,
@@ -157,23 +116,9 @@
             mRoot.addChild(mSiteSection);
         }
 
-        if (FeatureUtilities.isChromeDuplexEnabled()) {
-            if (mSigninPromo != null) mRoot.addChild(mSigninPromo);
-            mRoot.addChildren(mAllDismissed);
-
-            if (mContextualSuggestions != null) {
-                assert ChromeFeatureList.isEnabled(
-                        ChromeFeatureList.CONTEXTUAL_SUGGESTIONS_ABOVE_ARTICLES);
-                mRoot.addChildren(mContextualSuggestions);
-                mSections.setHasExternalSections(true);
-            }
-
-            mRoot.addChildren(mSections);
-        } else {
-            mRoot.addChild(mSections);
-            if (mSigninPromo != null) mRoot.addChild(mSigninPromo);
-            mRoot.addChild(mAllDismissed);
-        }
+        mRoot.addChild(mSections);
+        if (mSigninPromo != null) mRoot.addChild(mSigninPromo);
+        mRoot.addChild(mAllDismissed);
 
         mFooter = new Footer();
         mRoot.addChild(mFooter);
@@ -244,9 +189,6 @@
 
             case ItemViewType.ALL_DISMISSED:
                 return new AllDismissedItem.ViewHolder(mRecyclerView, mSections);
-
-            case ItemViewType.CAROUSEL:
-                return new SuggestionsCarousel.ViewHolder(mRecyclerView);
         }
 
         assert false : viewType;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NodeVisitor.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NodeVisitor.java
index 8304efd..4874937 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NodeVisitor.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NodeVisitor.java
@@ -6,7 +6,6 @@
 
 import org.chromium.chrome.browser.ntp.snippets.SnippetArticle;
 import org.chromium.chrome.browser.suggestions.ContentSuggestionsAdditionalAction;
-import org.chromium.chrome.browser.suggestions.SuggestionsCarouselAdapter;
 
 /**
  * Allows implementing a visitor pattern to iterate over all items under a (sub-)tree.
@@ -70,12 +69,6 @@
     public void visitTileGrid() {}
 
     /**
-     * Visits the contextual suggestions carousel.
-     * @param adapter The adapter that holds all information displayed in the carousel.
-     */
-    public void visitCarouselItem(SuggestionsCarouselAdapter adapter) {}
-
-    /**
      * Visits a logo.
      */
     public void visitLogo() {}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/DialogManager.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/DialogManager.java
index b684a1c..ba7f2c70 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/DialogManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/DialogManager.java
@@ -6,10 +6,14 @@
 
 import android.app.DialogFragment;
 import android.app.FragmentManager;
+import android.support.annotation.IntDef;
 import android.support.annotation.Nullable;
 
 import org.chromium.base.ThreadUtils;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
 /**
  * This class manages a {@link DialogFragment}.
  * In particular, it ensures that the dialog stays visible for a minimum time period, so that
@@ -50,6 +54,33 @@
     @Nullable
     private Runnable mCallback;
 
+    /** Possible actions taken on the dialog during {@link #hide}. */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({ACTION_NO_OP, ACTION_HIDDEN_IMMEDIATELY, ACTION_HIDING_DELAYED})
+    public @interface HideActions {}
+    /** The dialog has not been shown, so it is not being hidden. */
+    public static final int ACTION_NO_OP = 0;
+    /** {@link #mBarrierClosure} was signalled so the dialog is hidden now. */
+    public static final int ACTION_HIDDEN_IMMEDIATELY = 1;
+    /** The hiding is being delayed until {@link #mBarrierClosure} is signalled further. */
+    public static final int ACTION_HIDING_DELAYED = 2;
+
+    /** Interface to notify, during @{link #hide}, which action was taken. */
+    public interface ActionsConsumer { void consume(@HideActions int action); }
+
+    /** The callback called everytime {@link #hide} is executed. */
+    @Nullable
+    private final ActionsConsumer mActionsConsumer;
+
+    /**
+     * Constructs a DialogManager, optionally with a callback to report which action was taken on
+     * hiding.
+     * @param actionsConsumer The callback called everytime {@link #hide} is executed.
+     */
+    public DialogManager(@Nullable ActionsConsumer actionsConsumer) {
+        mActionsConsumer = actionsConsumer;
+    }
+
     /**
      * Shows the dialog.
      * @param dialog to be shown.
@@ -76,6 +107,18 @@
      * @param callback is asynchronously called as soon as the dialog is no longer visible.
      */
     public void hide(Runnable callback) {
+        if (mActionsConsumer != null) {
+            @HideActions
+            final int action;
+            if (mBarrierClosure == null) {
+                action = ACTION_NO_OP;
+            } else if (mBarrierClosure.isReady()) {
+                action = ACTION_HIDDEN_IMMEDIATELY;
+            } else {
+                action = ACTION_HIDING_DELAYED;
+            }
+            mActionsConsumer.consume(action);
+        }
         mCallback = callback;
         // The barrier closure is null if the dialog was not shown. In that case don't wait before
         // confirming the hidden state.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/SavePasswordsPreferences.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/SavePasswordsPreferences.java
index afbbbdc..43a3b7e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/SavePasswordsPreferences.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/SavePasswordsPreferences.java
@@ -184,9 +184,44 @@
     private boolean mSearchRecorded;
     private Menu mMenuForTesting;
 
+    // Histogram values for "PasswordManager.Android.ExportPasswordsProgressBarUsage". Never remove
+    // or reuse them, only add new ones if needed (and update PROGRESS_COUNT), to keep past and
+    // future UMA reports compatible.
+    @VisibleForTesting
+    public static final int PROGRESS_NOT_SHOWN = 0;
+    @VisibleForTesting
+    public static final int PROGRESS_HIDDEN_DIRECTLY = 1;
+    @VisibleForTesting
+    public static final int PROGRESS_HIDDEN_DELAYED = 2;
+    // The number of the other PROGRESS_* constants.
+    private static final int PROGRESS_COUNT = 3;
+
+    /**
+     * Converts a {@link DialogManager.HideActions} value to a value for the
+     * "PasswordManager.Android.ExportPasswordsProgressBarUsage" histogram.
+     */
+    private int actionToHistogramValue(@DialogManager.HideActions int action) {
+        switch (action) {
+            case DialogManager.ACTION_NO_OP:
+                return PROGRESS_NOT_SHOWN;
+            case DialogManager.ACTION_HIDDEN_IMMEDIATELY:
+                return PROGRESS_HIDDEN_DIRECTLY;
+            case DialogManager.ACTION_HIDING_DELAYED:
+                return PROGRESS_HIDDEN_DELAYED;
+        }
+        // All cases should be covered by the above switch statement.
+        assert false;
+        return PROGRESS_NOT_SHOWN;
+    }
+
     // Takes care of displaying and hiding the progress bar for exporting, while avoiding
     // flickering.
-    private DialogManager mProgressBarManager = new DialogManager();
+    private final DialogManager mProgressBarManager =
+            new DialogManager((@DialogManager.HideActions int action) -> {
+                RecordHistogram.recordEnumeratedHistogram(
+                        "PasswordManager.Android.ExportPasswordsProgressBarUsage",
+                        actionToHistogramValue(action), PROGRESS_COUNT);
+            });
 
     // If an error dialog should be shown, this contains the arguments for it, such as the error
     // message. If no error dialog should be shown, this is null.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/SingleThreadBarrierClosure.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/SingleThreadBarrierClosure.java
index 753a81d..247f23d4 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/SingleThreadBarrierClosure.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/SingleThreadBarrierClosure.java
@@ -35,4 +35,12 @@
         --mRemainingRuns;
         if (mRemainingRuns == 0) mCallback.run();
     }
+
+    /**
+     * Whether the next call to {@link #run} runs {@link #mCallback}.
+     * @return True if the next call to {@link #run} runs {@link #mCallback}, false otherwise.
+     */
+    public boolean isReady() {
+        return mRemainingRuns == 1;
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/ContextualSuggestionsCardViewHolder.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/ContextualSuggestionsCardViewHolder.java
deleted file mode 100644
index 14af45fa..0000000
--- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/ContextualSuggestionsCardViewHolder.java
+++ /dev/null
@@ -1,149 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.chrome.browser.suggestions;
-
-import android.util.DisplayMetrics;
-import android.view.ContextMenu;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-
-import org.chromium.base.ApiCompatibilityUtils;
-import org.chromium.chrome.R;
-import org.chromium.chrome.browser.ntp.ContextMenuManager;
-import org.chromium.chrome.browser.ntp.cards.NewTabPageViewHolder;
-import org.chromium.chrome.browser.ntp.snippets.SnippetArticle;
-import org.chromium.chrome.browser.widget.displaystyle.DisplayStyleObserverAdapter;
-import org.chromium.chrome.browser.widget.displaystyle.HorizontalDisplayStyle;
-import org.chromium.chrome.browser.widget.displaystyle.UiConfig;
-import org.chromium.ui.mojom.WindowOpenDisposition;
-
-/**
- * ViewHolder used to show contextual suggestions. The card will be used in the
- * {@link SuggestionsCarouselAdapter} to populate the {@link SuggestionsCarousel} in Chrome Home in
- * the bottom sheet.
- */
-public class ContextualSuggestionsCardViewHolder extends NewTabPageViewHolder {
-    private static final double CARD_WIDTH_TO_WINDOW_SIZE_RATIO = 0.9;
-    private final SuggestionsBinder mSuggestionsBinder;
-    private final SuggestionsUiDelegate mUiDelegate;
-    private final DisplayStyleObserverAdapter mDisplayStyleObserver;
-    private SnippetArticle mSuggestion;
-
-    public ContextualSuggestionsCardViewHolder(ViewGroup recyclerView, UiConfig uiConfig,
-            SuggestionsUiDelegate uiDelegate, ContextMenuManager contextMenuManager) {
-        super(getCardView(recyclerView));
-
-        mUiDelegate = uiDelegate;
-        mSuggestionsBinder = new SuggestionsBinder(itemView, uiDelegate);
-        InteractionsDelegate interactionsDelegate = new InteractionsDelegate(contextMenuManager);
-
-        itemView.setOnClickListener(interactionsDelegate);
-        itemView.setOnCreateContextMenuListener(interactionsDelegate);
-
-        int startMargin = itemView.getResources().getDimensionPixelOffset(
-                R.dimen.contextual_carousel_space_between_cards);
-        ApiCompatibilityUtils.setMarginStart(
-                (ViewGroup.MarginLayoutParams) itemView.getLayoutParams(), startMargin);
-
-        mDisplayStyleObserver =
-                new DisplayStyleObserverAdapter(itemView, uiConfig, this::updateCardWidth);
-        mSuggestionsBinder.updateFieldsVisibility(/* showHeadline = */ true,
-                /* showThumbnail = */ true, /* showThumbnailVideoBadge = */ false);
-    }
-
-    public void onBindViewHolder(SnippetArticle suggestion) {
-        mSuggestion = suggestion;
-        mDisplayStyleObserver.attach();
-        mSuggestionsBinder.updateViewInformation(mSuggestion);
-        refreshOfflineBadgeVisibility();
-    }
-
-    @Override
-    public void recycle() {
-        mDisplayStyleObserver.detach();
-        mSuggestionsBinder.recycle();
-        super.recycle();
-    }
-
-    private static View getCardView(ViewGroup recyclerView) {
-        int res = SuggestionsConfig.useModernLayout() ? R.layout.content_suggestions_card_modern
-                                                      : R.layout.contextual_suggestions_card;
-
-        return LayoutInflater.from(recyclerView.getContext()).inflate(res, recyclerView, false);
-    }
-
-    private void updateCardWidth(UiConfig.DisplayStyle displayStyle) {
-        @HorizontalDisplayStyle
-        int horizontalStyle = displayStyle.horizontal;
-
-        ViewGroup.LayoutParams params = itemView.getLayoutParams();
-        DisplayMetrics displayMetrics = itemView.getContext().getResources().getDisplayMetrics();
-
-        // We choose the window side that we want to align the card width to. In portrait and split
-        // screen we use the width of the window. In landscape, however, the width becomes
-        // unnecessarily large. Therefore, we choose the height of the window, which allows to show
-        // more suggestions in reasonably sized cards.
-        int screenSizePx = horizontalStyle == HorizontalDisplayStyle.WIDE
-                ? displayMetrics.heightPixels
-                : displayMetrics.widthPixels;
-
-        params.width = (int) (screenSizePx * CARD_WIDTH_TO_WINDOW_SIZE_RATIO);
-        itemView.setLayoutParams(params);
-    }
-
-    public void refreshOfflineBadgeVisibility() {
-        boolean visible = mSuggestion.getOfflinePageOfflineId() != null;
-        mSuggestionsBinder.updateOfflineBadgeVisibility(visible);
-    }
-
-    private class InteractionsDelegate implements ContextMenuManager.Delegate, View.OnClickListener,
-                                                  View.OnCreateContextMenuListener {
-        private final ContextMenuManager mContextMenuManager;
-
-        InteractionsDelegate(ContextMenuManager contextMenuManager) {
-            mContextMenuManager = contextMenuManager;
-        }
-
-        @Override
-        public void openItem(int windowDisposition) {
-            mUiDelegate.getNavigationDelegate().navigateToSuggestionUrl(
-                    windowDisposition, mSuggestion.getUrl());
-
-            SuggestionsMetrics.recordContextualSuggestionOpened();
-        }
-
-        @Override
-        public void removeItem() {
-            // Unsupported.
-            assert false;
-        }
-
-        @Override
-        public String getUrl() {
-            return mSuggestion.getUrl();
-        }
-
-        @Override
-        public boolean isItemSupported(@ContextMenuManager.ContextMenuItemId int menuItemId) {
-            return menuItemId != ContextMenuManager.ID_REMOVE
-                    && menuItemId != ContextMenuManager.ID_LEARN_MORE;
-        }
-
-        @Override
-        public void onContextMenuCreated() {}
-
-        @Override
-        public void onCreateContextMenu(
-                ContextMenu contextMenu, View view, ContextMenu.ContextMenuInfo contextMenuInfo) {
-            mContextMenuManager.createContextMenu(contextMenu, view, this);
-        }
-
-        @Override
-        public void onClick(View view) {
-            openItem(WindowOpenDisposition.CURRENT_TAB);
-        }
-    }
-}
\ No newline at end of file
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/ContextualSuggestionsManager.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/ContextualSuggestionsManager.java
deleted file mode 100644
index fcdf00f..0000000
--- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/ContextualSuggestionsManager.java
+++ /dev/null
@@ -1,26 +0,0 @@
-// 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.
-
-package org.chromium.chrome.browser.suggestions;
-
-import org.chromium.chrome.browser.ChromeActivity;
-import org.chromium.chrome.browser.snackbar.SnackbarManager;
-import org.chromium.chrome.browser.tabmodel.TabModelSelector;
-import org.chromium.chrome.browser.widget.bottomsheet.BottomSheet;
-
-/**
- * Manages showing contextual suggestions in the {@link BottomSheet}.
- */
-public class ContextualSuggestionsManager {
-    SuggestionsBottomSheetContent mBottomSheetContent;
-
-    public ContextualSuggestionsManager(final ChromeActivity activity, final BottomSheet sheet,
-            TabModelSelector tabModelSelector, SnackbarManager snackbarManager) {
-        // TODO(twellington): Replace with bottom sheet content that only shows contextual
-        // suggestions.
-        mBottomSheetContent = new SuggestionsBottomSheetContent(
-                activity, sheet, tabModelSelector, snackbarManager);
-        sheet.showContent(mBottomSheetContent);
-    }
-}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/ContextualSuggestionsSection.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/ContextualSuggestionsSection.java
deleted file mode 100644
index 0783f72..0000000
--- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/ContextualSuggestionsSection.java
+++ /dev/null
@@ -1,157 +0,0 @@
-// 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.
-
-package org.chromium.chrome.browser.suggestions;
-
-import android.content.Context;
-import android.support.annotation.Nullable;
-import android.text.TextUtils;
-import android.webkit.URLUtil;
-
-import org.chromium.chrome.R;
-import org.chromium.chrome.browser.ntp.cards.InnerNode;
-import org.chromium.chrome.browser.ntp.cards.SuggestionsCategoryInfo;
-import org.chromium.chrome.browser.ntp.cards.SuggestionsSection;
-import org.chromium.chrome.browser.ntp.snippets.CategoryStatus;
-import org.chromium.chrome.browser.ntp.snippets.ContentSuggestionsCardLayout;
-import org.chromium.chrome.browser.ntp.snippets.KnownCategories;
-import org.chromium.chrome.browser.offlinepages.OfflinePageBridge;
-import org.chromium.chrome.browser.tab.EmptyTabObserver;
-import org.chromium.chrome.browser.tab.Tab;
-import org.chromium.chrome.browser.tab.TabObserver;
-import org.chromium.chrome.browser.tabmodel.TabModel.TabSelectionType;
-import org.chromium.chrome.browser.tabmodel.TabModelSelector;
-import org.chromium.chrome.browser.tabmodel.TabModelSelectorTabModelObserver;
-import org.chromium.chrome.browser.util.UrlUtilities;
-
-/**
- * Displays a {@link SuggestionsSection} containing contextual article suggestions.
- */
-public class ContextualSuggestionsSection extends InnerNode implements SuggestionsSection.Delegate {
-    private final SuggestionsUiDelegate mUiDelegate;
-    private final SuggestionsSection mSection;
-    private final TabModelSelectorTabModelObserver mTabModelObserver;
-    private final TabObserver mTabObserver;
-
-    private Tab mLastTab;
-
-    @Nullable
-    private String mCurrentContextUrl;
-
-    public ContextualSuggestionsSection(SuggestionsUiDelegate uiDelegate,
-            OfflinePageBridge offlinePageBridge, Context context,
-            TabModelSelector tabModelSelector) {
-        mUiDelegate = uiDelegate;
-
-        SuggestionsCategoryInfo info = new SuggestionsCategoryInfo(KnownCategories.CONTEXTUAL,
-                context.getString(R.string.contextual_suggestions_title),
-                ContentSuggestionsCardLayout.FULL_CARD, ContentSuggestionsAdditionalAction.NONE,
-                true, "");
-        mSection = new SuggestionsSection(
-                this, mUiDelegate, mUiDelegate.getSuggestionsRanker(), offlinePageBridge, info);
-        mUiDelegate.getSuggestionsRanker().registerCategory(KnownCategories.CONTEXTUAL);
-        addChild(mSection);
-
-        mTabObserver = new EmptyTabObserver() {
-            @Override
-            public void onUpdateUrl(Tab tab, String url) {
-                refresh(url);
-            }
-        };
-
-        mTabModelObserver = new TabModelSelectorTabModelObserver(tabModelSelector) {
-            @Override
-            public void didSelectTab(Tab tab, TabSelectionType type, int lastId) {
-                updateCurrentTab(tab);
-            }
-        };
-
-        updateCurrentTab(tabModelSelector.getCurrentTab());
-    }
-
-    /** Destroys the section. */
-    public void destroy() {
-        if (mLastTab != null) {
-            mLastTab.removeObserver(mTabObserver);
-            mLastTab = null;
-        }
-        mTabModelObserver.destroy();
-    }
-
-    /**
-     * Fetches new suggestions if the context URL was changed from the last time that the carousel
-     * was shown.
-     */
-    public void refresh(@Nullable final String newUrl) {
-        if (!URLUtil.isNetworkUrl(newUrl)) {
-            clearSuggestions();
-            return;
-        }
-
-        // Do nothing if there are already suggestions in the suggestions list for the new context.
-        if (isContextTheSame(newUrl)) return;
-
-        mSection.setStatus(CategoryStatus.INITIALIZING);
-
-        // Context has changed, so we want to remove any old suggestions from the section.
-        clearSuggestions();
-        mCurrentContextUrl = newUrl;
-
-        mUiDelegate.getSuggestionsSource().fetchContextualSuggestions(newUrl, (suggestions) -> {
-            // Avoiding double fetches causing suggestions for incorrect context.
-            if (!TextUtils.equals(newUrl, mCurrentContextUrl)) return;
-
-            if (suggestions.size() > 0) {
-                mSection.appendSuggestions(suggestions, false, false);
-            }
-
-            mSection.setStatus(CategoryStatus.AVAILABLE);
-        });
-    }
-
-    /**
-     * @param visible Whether the section should be visible. If false, all suggestions are cleared.
-     */
-    public void setSectionVisiblity(boolean visible) {
-        mSection.setHeaderVisibility(visible);
-        if (!visible) clearSuggestions();
-    }
-
-    private boolean isContextTheSame(String newUrl) {
-        return UrlUtilities.urlsMatchIgnoringFragments(newUrl, mCurrentContextUrl);
-    }
-
-    /**
-     * Removes any suggestions that might be present in the section.
-     */
-    private void clearSuggestions() {
-        mCurrentContextUrl = null;
-        mSection.clearData();
-    }
-
-    /**
-     * Update the current tab and refresh suggestions.
-     * @param tab The current {@link Tab}.
-     */
-    private void updateCurrentTab(Tab tab) {
-        if (mLastTab != null) mLastTab.removeObserver(mTabObserver);
-
-        mLastTab = tab;
-        if (mLastTab == null) return;
-
-        mLastTab.addObserver(mTabObserver);
-        refresh(mLastTab.getUrl());
-    }
-
-    @Override
-    public void dismissSection(SuggestionsSection section) {
-        // This section should not be dismissed.
-        assert false;
-    }
-
-    @Override
-    public boolean isResetAllowed() {
-        return false;
-    }
-}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsBinder.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsBinder.java
index ce308db4..78f97955 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsBinder.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsBinder.java
@@ -178,9 +178,7 @@
         mThumbnailView.setBackground(null);
         if (SuggestionsConfig.useModernLayout()
                 && ChromeFeatureList.isEnabled(
-                           ChromeFeatureList.CONTENT_SUGGESTIONS_THUMBNAIL_DOMINANT_COLOR)
-                && !ChromeFeatureList.isEnabled(
-                           ChromeFeatureList.CONTEXTUAL_SUGGESTIONS_ABOVE_ARTICLES)) {
+                           ChromeFeatureList.CONTENT_SUGGESTIONS_THUMBNAIL_DOMINANT_COLOR)) {
             ColorDrawable colorDrawable =
                     new ColorDrawable(mSuggestion.getThumbnailDominantColor() != null
                                     ? mSuggestion.getThumbnailDominantColor()
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsBottomSheetContent.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsBottomSheetContent.java
deleted file mode 100644
index 7180d46..0000000
--- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsBottomSheetContent.java
+++ /dev/null
@@ -1,245 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.chrome.browser.suggestions;
-
-import android.content.res.Resources;
-import android.support.annotation.Nullable;
-import android.view.LayoutInflater;
-import android.view.View;
-
-import org.chromium.base.library_loader.LibraryProcessType;
-import org.chromium.chrome.R;
-import org.chromium.chrome.browser.ChromeActivity;
-import org.chromium.chrome.browser.ChromeFeatureList;
-import org.chromium.chrome.browser.ntp.ContextMenuManager;
-import org.chromium.chrome.browser.ntp.ContextMenuManager.TouchEnabledDelegate;
-import org.chromium.chrome.browser.ntp.cards.NewTabPageAdapter;
-import org.chromium.chrome.browser.offlinepages.OfflinePageBridge;
-import org.chromium.chrome.browser.profiles.Profile;
-import org.chromium.chrome.browser.snackbar.SnackbarManager;
-import org.chromium.chrome.browser.tab.Tab;
-import org.chromium.chrome.browser.tabmodel.TabModelSelector;
-import org.chromium.chrome.browser.widget.LoadingView;
-import org.chromium.chrome.browser.widget.bottomsheet.BottomSheet;
-import org.chromium.chrome.browser.widget.bottomsheet.BottomSheet.StateChangeReason;
-import org.chromium.chrome.browser.widget.displaystyle.UiConfig;
-import org.chromium.content.browser.BrowserStartupController;
-
-/**
- * Provides content to be displayed inside of the Home tab of bottom sheet.
- */
-public class SuggestionsBottomSheetContent implements BottomSheet.BottomSheetContent {
-    private final View mView;
-    private final SuggestionsRecyclerView mRecyclerView;
-    private final ChromeActivity mActivity;
-    private final BottomSheet mSheet;
-
-    private NewTabPageAdapter mAdapter;
-    private ContextMenuManager mContextMenuManager;
-    private SuggestionsUiDelegateImpl mSuggestionsUiDelegate;
-    private TileGroup.Delegate mTileGroupDelegate;
-    private SuggestionsSheetVisibilityChangeObserver mBottomSheetObserver;
-
-    @Nullable
-    private SuggestionsCarousel mSuggestionsCarousel;
-    @Nullable
-    private ContextualSuggestionsSection mContextualSuggestions;
-
-    private boolean mSuggestionsInitialized;
-    private boolean mIsDestroyed;
-
-    public SuggestionsBottomSheetContent(final ChromeActivity activity, final BottomSheet sheet,
-            TabModelSelector tabModelSelector, SnackbarManager snackbarManager) {
-        mActivity = activity;
-        mSheet = sheet;
-
-        mView = LayoutInflater.from(activity).inflate(
-                R.layout.suggestions_bottom_sheet_content, null);
-        Resources resources = mView.getResources();
-        int backgroundColor = SuggestionsConfig.getBackgroundColor(resources);
-        mView.setBackgroundColor(backgroundColor);
-        mRecyclerView = mView.findViewById(R.id.recycler_view);
-        mRecyclerView.setBackgroundColor(backgroundColor);
-
-        LoadingView loadingView = mView.findViewById(R.id.loading_view);
-
-        if (mActivity.didFinishNativeInitialization()) {
-            loadingView.setVisibility(View.GONE);
-            initializeWithNative(tabModelSelector, snackbarManager);
-        } else {
-            mRecyclerView.setVisibility(View.GONE);
-            loadingView.showLoadingUI();
-            // Only add a StartupCompletedObserver if native is not initialized to avoid
-            // #initializeWithNative() being called twice.
-            BrowserStartupController.get(LibraryProcessType.PROCESS_BROWSER)
-                    .addStartupCompletedObserver(new BrowserStartupController.StartupCallback() {
-                        @Override
-                        public void onSuccess(boolean alreadyStarted) {
-                            // If this is destroyed before native initialization is finished, don't
-                            // do anything. Otherwise this will be initialized based on out-of-date
-                            // #mSheet and #mActivity, which causes a crash.
-                            // See https://crbug.com/804296.
-                            if (mIsDestroyed) return;
-
-                            mRecyclerView.setVisibility(View.VISIBLE);
-                            loadingView.hideLoadingUI();
-                            initializeWithNative(tabModelSelector, snackbarManager);
-                        }
-
-                        @Override
-                        public void onFailure() {}
-                    });
-        }
-    }
-
-    private void initializeWithNative(
-            TabModelSelector tabModelSelector, SnackbarManager snackbarManager) {
-        assert !mSuggestionsInitialized;
-        mSuggestionsInitialized = true;
-
-        SuggestionsDependencyFactory depsFactory = SuggestionsDependencyFactory.getInstance();
-        Profile profile = Profile.getLastUsedProfile();
-        SuggestionsNavigationDelegate navigationDelegate =
-                new SuggestionsNavigationDelegateImpl(mActivity, profile, mSheet, tabModelSelector);
-
-        mTileGroupDelegate =
-                new TileGroupDelegateImpl(mActivity, profile, navigationDelegate, snackbarManager);
-        mSuggestionsUiDelegate = new SuggestionsUiDelegateImpl(
-                depsFactory.createSuggestionSource(profile), depsFactory.createEventReporter(),
-                navigationDelegate, profile, mSheet, mActivity.getReferencePool(), snackbarManager);
-
-        TouchEnabledDelegate touchEnabledDelegate = mActivity.getBottomSheet()::setTouchEnabled;
-        mContextMenuManager = new ContextMenuManager(
-                navigationDelegate, touchEnabledDelegate, mActivity::closeContextMenu);
-        mActivity.getWindowAndroid().addContextMenuCloseListener(mContextMenuManager);
-        mSuggestionsUiDelegate.addDestructionObserver(() -> {
-            mActivity.getWindowAndroid().removeContextMenuCloseListener(mContextMenuManager);
-        });
-
-        UiConfig uiConfig = new UiConfig(mRecyclerView);
-        mRecyclerView.init(uiConfig, mContextMenuManager);
-
-        OfflinePageBridge offlinePageBridge = depsFactory.getOfflinePageBridge(profile);
-
-        if (ChromeFeatureList.isEnabled(ChromeFeatureList.CONTEXTUAL_SUGGESTIONS_CAROUSEL)) {
-            mSuggestionsCarousel = new SuggestionsCarousel(
-                    uiConfig, mSuggestionsUiDelegate, mContextMenuManager, offlinePageBridge);
-        }
-
-        if (ChromeFeatureList.isEnabled(ChromeFeatureList.CONTEXTUAL_SUGGESTIONS_ABOVE_ARTICLES)) {
-            mContextualSuggestions = new ContextualSuggestionsSection(mSuggestionsUiDelegate,
-                    offlinePageBridge, mActivity, mActivity.getTabModelSelector());
-        }
-
-        mAdapter = new NewTabPageAdapter(mSuggestionsUiDelegate,
-                /* aboveTheFoldView = */ null, /* logoView = */ null, uiConfig, offlinePageBridge,
-                mContextMenuManager, mTileGroupDelegate, mSuggestionsCarousel,
-                mContextualSuggestions);
-
-        mBottomSheetObserver = new SuggestionsSheetVisibilityChangeObserver(this, mActivity) {
-            @Override
-            public void onContentShown(boolean isFirstShown) {
-                // TODO(dgn): Temporary workaround to trigger an event in the backend when the
-                // sheet is opened following inactivity. See https://crbug.com/760974. Should be
-                // moved back to the "new opening of the sheet" path once we are able to trigger it
-                // in that case.
-                mSuggestionsUiDelegate.getEventReporter().onSurfaceOpened();
-                SuggestionsMetrics.recordSurfaceVisible();
-
-                if (isFirstShown) {
-                    mAdapter.refreshSuggestions();
-
-                    maybeUpdateContextualSuggestions();
-
-                    // Set the adapter on the RecyclerView after updating it, to avoid sending
-                    // notifications that might confuse its internal state.
-                    // See https://crbug.com/756514.
-                    mRecyclerView.setAdapter(mAdapter);
-                    mRecyclerView.scrollToPosition(0);
-                    mRecyclerView.getScrollEventReporter().reset();
-                }
-            }
-
-            @Override
-            public void onContentHidden() {
-                SuggestionsMetrics.recordSurfaceHidden();
-            }
-
-            @Override
-            public void onContentStateChanged(@BottomSheet.SheetState int contentState) {
-                if (contentState == BottomSheet.SHEET_STATE_HALF) {
-                    SuggestionsMetrics.recordSurfaceHalfVisible();
-                    mRecyclerView.setScrollEnabled(false);
-                } else if (contentState == BottomSheet.SHEET_STATE_FULL) {
-                    SuggestionsMetrics.recordSurfaceFullyVisible();
-                    mRecyclerView.setScrollEnabled(true);
-                }
-            }
-
-            @Override
-            public void onSheetClosed(@StateChangeReason int reason) {
-                super.onSheetClosed(reason);
-
-                if (ChromeFeatureList.isEnabled(
-                            ChromeFeatureList.CHROME_HOME_DROP_ALL_BUT_FIRST_THUMBNAIL)) {
-                    mAdapter.dropAllButFirstNArticleThumbnails(1);
-                }
-                mRecyclerView.setAdapter(null);
-            }
-        };
-    }
-
-    @Override
-    public View getContentView() {
-        return mView;
-    }
-
-    @Override
-    public View getToolbarView() {
-        return null;
-    }
-
-    @Override
-    public int getVerticalScrollOffset() {
-        return mRecyclerView.computeVerticalScrollOffset();
-    }
-
-    @Override
-    public void destroy() {
-        mIsDestroyed = true;
-
-        if (mSuggestionsInitialized) {
-            mBottomSheetObserver.onDestroy();
-            mSuggestionsUiDelegate.onDestroy();
-            mTileGroupDelegate.destroy();
-
-            if (mContextualSuggestions != null) mContextualSuggestions.destroy();
-        }
-    }
-
-    @Override
-    public boolean applyDefaultTopPadding() {
-        return false;
-    }
-
-    private void maybeUpdateContextualSuggestions() {
-        if (mSuggestionsCarousel == null && mContextualSuggestions == null) return;
-
-        Tab activeTab = mSheet.getActiveTab();
-        final String currentUrl = activeTab == null ? null : activeTab.getUrl();
-
-        if (mSuggestionsCarousel != null) {
-            assert ChromeFeatureList.isEnabled(ChromeFeatureList.CONTEXTUAL_SUGGESTIONS_CAROUSEL);
-            mSuggestionsCarousel.refresh(mSheet.getContext(), currentUrl);
-        }
-
-        if (mContextualSuggestions != null) {
-            assert ChromeFeatureList.isEnabled(
-                    ChromeFeatureList.CONTEXTUAL_SUGGESTIONS_ABOVE_ARTICLES);
-            mContextualSuggestions.setSectionVisiblity(true);
-            mContextualSuggestions.refresh(currentUrl);
-        }
-    }
-}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsCarousel.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsCarousel.java
deleted file mode 100644
index 8937f40..0000000
--- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsCarousel.java
+++ /dev/null
@@ -1,218 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.chrome.browser.suggestions;
-
-import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
-import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
-
-import android.content.Context;
-import android.support.annotation.Nullable;
-import android.support.v7.widget.LinearLayoutManager;
-import android.support.v7.widget.RecyclerView;
-import android.text.TextUtils;
-import android.view.ViewGroup;
-import android.webkit.URLUtil;
-
-import org.chromium.base.ApiCompatibilityUtils;
-import org.chromium.base.VisibleForTesting;
-import org.chromium.chrome.R;
-import org.chromium.chrome.browser.metrics.ImpressionTracker.Listener;
-import org.chromium.chrome.browser.metrics.OneShotImpressionListener;
-import org.chromium.chrome.browser.ntp.ContextMenuManager;
-import org.chromium.chrome.browser.ntp.cards.ItemViewType;
-import org.chromium.chrome.browser.ntp.cards.NewTabPageViewHolder;
-import org.chromium.chrome.browser.ntp.cards.NodeVisitor;
-import org.chromium.chrome.browser.ntp.cards.OptionalLeaf;
-import org.chromium.chrome.browser.ntp.snippets.SnippetArticle;
-import org.chromium.chrome.browser.offlinepages.OfflinePageBridge;
-import org.chromium.chrome.browser.util.UrlUtilities;
-import org.chromium.chrome.browser.widget.displaystyle.UiConfig;
-import org.chromium.ui.widget.Toast;
-
-import java.util.Collections;
-import java.util.Locale;
-
-/**
- * This is an optional item in Chrome Home in the bottom sheet. The carousel is a {@link
- * RecyclerView} which is used to display contextual suggestions to the user according to the
- * website they are currently looking at. The carousel uses a {@link SuggestionsCarouselAdapter} to
- * populate information in {@link ContextualSuggestionsCardViewHolder} instances.
- *
- * When there is no context, i.e. the user is on a native page, the carousel will not be shown.
- */
-public class SuggestionsCarousel extends OptionalLeaf {
-    private final SuggestionsCarouselAdapter mAdapter;
-    private final SuggestionsUiDelegate mUiDelegate;
-    private final OneShotImpressionListener mImpressionFilter;
-    @Nullable
-    private String mCurrentContextUrl;
-
-    /**
-     * Necessary flag to record correct UMA metrics and avoid possible inconsistencies caused by the
-     * {@link ViewHolder}. We record that the carousel was scrolled in the view holder, but want to
-     * make sure that this is recorded only once per carousel shown. */
-    private boolean mWasScrolledSinceShown;
-
-    public SuggestionsCarousel(UiConfig uiConfig, SuggestionsUiDelegate uiDelegate,
-            ContextMenuManager contextMenuManager, OfflinePageBridge offlinePageBridge) {
-        mAdapter = new SuggestionsCarouselAdapter(
-                uiConfig, uiDelegate, contextMenuManager, offlinePageBridge);
-        mUiDelegate = uiDelegate;
-
-        // The impression tracker will record metrics only once per bottom sheet opened.
-        mImpressionFilter = new OneShotImpressionListener(
-                SuggestionsMetrics::recordContextualSuggestionsCarouselShown);
-
-        // TODO(dgn): Handle this case properly. Also enable test in ContextualSuggestionsTest.
-        // We need to keep the carousel always internally visible because it is the first item in
-        // the SuggestionsRecyclerView. Otherwise, if we setVisibilityInternal() as we receive
-        // suggestions in the ContextualFetchCallback, there is a problem. When the suggestions
-        // arrive late, the SuggestionsRecyclerView has already laid out its children and will not
-        // automatically scroll up to show the carousel. (See crbug.com/758179).
-        // This way the carousel is always a child in the NewTabPageAdapter data structure but is
-        // only shown when there are suggestions.
-        setVisibilityInternal(true);
-    }
-
-    /**
-     * Fetches new suggestions if the context URL was changed from the last time that the carousel
-     * was shown.
-     */
-    public void refresh(final Context context, @Nullable final String newUrl) {
-        if (!URLUtil.isNetworkUrl(newUrl)) {
-            clearSuggestions();
-            return;
-        }
-
-        // Reset the impression tracker to record if the carousel is shown. We do this once per
-        // bottom sheet opened.
-        mImpressionFilter.reset();
-
-        // Reset that the carousel has not been scrolled in this impression yet.
-        mWasScrolledSinceShown = false;
-
-        // Do nothing if there are already suggestions in the carousel for the new context.
-        if (isContextTheSame(newUrl)) return;
-
-        String text = "Fetching contextual suggestions...";
-        Toast.makeText(context, text, Toast.LENGTH_SHORT).show();
-
-        // Context has changed, so we want to remove any old suggestions from the carousel.
-        clearSuggestions();
-        mCurrentContextUrl = newUrl;
-
-        mUiDelegate.getSuggestionsSource().fetchContextualSuggestions(newUrl, (suggestions) -> {
-            // Avoiding double fetches causing suggestions for incorrect context.
-            if (!TextUtils.equals(newUrl, mCurrentContextUrl)) return;
-
-            mAdapter.setSuggestions(suggestions);
-
-            String toastText = String.format(
-                    Locale.US, "Fetched %d contextual suggestions.", suggestions.size());
-            Toast.makeText(context, toastText, Toast.LENGTH_SHORT).show();
-        });
-    }
-
-    @Override
-    protected void onBindViewHolder(NewTabPageViewHolder holder) {
-        RecyclerView carouselRecyclerView = (RecyclerView) holder.itemView;
-
-        carouselRecyclerView.setAdapter(mAdapter);
-
-        // We want to record only once that the carousel was shown after the bottom sheet was
-        // opened. The first time that the carousel is shown, the mImpressionTracker will be
-        // triggered and we don't want it to track any views anymore.
-        ((ViewHolder) holder).setListener(mImpressionFilter);
-
-        // If we have recorded a scroll since the carousel was shown, we don't want to register a
-        // scroll listener again.
-        if (mWasScrolledSinceShown) return;
-
-        carouselRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
-            @Override
-            public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
-                // The dragging state guarantees that the scroll event was caused by the user.
-                if (newState != RecyclerView.SCROLL_STATE_DRAGGING) return;
-
-                SuggestionsMetrics.recordContextualSuggestionsCarouselScrolled();
-                mWasScrolledSinceShown = true;
-
-                // We are not interested in scrolls after the first one, so we can safely remove
-                // the listener.
-                recyclerView.removeOnScrollListener(this);
-            }
-        });
-    }
-
-    @Override
-    protected int getItemViewType() {
-        return ItemViewType.CAROUSEL;
-    }
-
-    @Override
-    protected void visitOptionalItem(NodeVisitor visitor) {
-        visitor.visitCarouselItem(mAdapter);
-    }
-
-    @VisibleForTesting
-    boolean isContextTheSame(String newUrl) {
-        // The call to UrlUtilities is wrapped to be able to mock it and skip the native call in
-        // unit tests.
-        return UrlUtilities.urlsMatchIgnoringFragments(newUrl, mCurrentContextUrl);
-    }
-
-    /**
-     * Removes any suggestions that might be present in the carousel.
-     */
-    private void clearSuggestions() {
-        mCurrentContextUrl = null;
-        mAdapter.setSuggestions(Collections.<SnippetArticle>emptyList());
-    }
-
-    /**
-     * View holder for the {@link SuggestionsCarousel}.
-     */
-    public static class ViewHolder extends NewTabPageViewHolder {
-        private final RecyclerView mRecyclerView;
-        public ViewHolder(ViewGroup parentView) {
-            super(new RecyclerView(parentView.getContext()));
-
-            mRecyclerView = (RecyclerView) itemView;
-
-            setUpRecyclerView();
-        }
-
-        /**
-         * @param listener The impression tracker's listener.
-         */
-        public void setListener(Listener listener) {
-            setImpressionListener(listener);
-        }
-
-        private void setUpRecyclerView() {
-            ViewGroup.LayoutParams params =
-                    new RecyclerView.LayoutParams(MATCH_PARENT, WRAP_CONTENT);
-            mRecyclerView.setLayoutParams(params);
-
-            // Make the recycler view scroll horizontally.
-            LinearLayoutManager layoutManager = new LinearLayoutManager(mRecyclerView.getContext());
-            layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
-            mRecyclerView.setLayoutManager(layoutManager);
-            mRecyclerView.setClipToPadding(false);
-
-            float spaceBetweenCards = mRecyclerView.getContext().getResources().getDimension(
-                    R.dimen.contextual_carousel_space_between_cards);
-            int recyclerViewMarginEnd = (int) Math.floor(spaceBetweenCards);
-            ApiCompatibilityUtils.setPaddingRelative(mRecyclerView, 0, 0, recyclerViewMarginEnd, 0);
-        }
-
-        @Override
-        public void recycle() {
-            mRecyclerView.setAdapter(null);
-            mRecyclerView.clearOnScrollListeners();
-            super.recycle();
-        }
-    }
-}
\ No newline at end of file
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsCarouselAdapter.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsCarouselAdapter.java
deleted file mode 100644
index d1698bf5..0000000
--- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsCarouselAdapter.java
+++ /dev/null
@@ -1,115 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.chrome.browser.suggestions;
-
-import android.support.v7.widget.RecyclerView;
-import android.view.ViewGroup;
-
-import org.chromium.chrome.browser.ntp.ContextMenuManager;
-import org.chromium.chrome.browser.ntp.snippets.SnippetArticle;
-import org.chromium.chrome.browser.offlinepages.OfflinePageBridge;
-import org.chromium.chrome.browser.offlinepages.OfflinePageItem;
-import org.chromium.chrome.browser.widget.displaystyle.UiConfig;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Adapter for a horizontal list of suggestions. The individual suggestions are held
- * in {@link ContextualSuggestionsCardViewHolder} instances.
- */
-public class SuggestionsCarouselAdapter
-        extends RecyclerView.Adapter<ContextualSuggestionsCardViewHolder> {
-    private final SuggestionsUiDelegate mUiDelegate;
-    private final UiConfig mUiConfig;
-
-    /** Manager for creating a context menu for a contextual suggestions card. */
-    private final ContextMenuManager mContextMenuManager;
-
-    /** The list of suggestions held in the carousel currently. */
-    private final List<SnippetArticle> mSuggestionsList;
-
-    /** Access point to offline related features. */
-    private final OfflineModelObserver mObserver;
-
-    public SuggestionsCarouselAdapter(UiConfig uiConfig, SuggestionsUiDelegate uiDelegate,
-            ContextMenuManager contextMenuManager, OfflinePageBridge offlinePageBridge) {
-        mUiDelegate = uiDelegate;
-        mUiConfig = uiConfig;
-        mContextMenuManager = contextMenuManager;
-        mSuggestionsList = new ArrayList<>();
-        mObserver = new OfflineModelObserver(offlinePageBridge);
-        mUiDelegate.addDestructionObserver(mObserver);
-    }
-
-    @Override
-    public ContextualSuggestionsCardViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
-        return new ContextualSuggestionsCardViewHolder(
-                viewGroup, mUiConfig, mUiDelegate, mContextMenuManager);
-    }
-
-    @Override
-    public void onBindViewHolder(ContextualSuggestionsCardViewHolder holder, int i) {
-        holder.onBindViewHolder(mSuggestionsList.get(i));
-    }
-
-    @Override
-    public void onViewRecycled(ContextualSuggestionsCardViewHolder holder) {
-        holder.recycle();
-    }
-
-    @Override
-    public int getItemCount() {
-        return mSuggestionsList.size();
-    }
-
-    /**
-     * Set the new contextual suggestions to be shown in the suggestions carousel and update the UI.
-     *
-     * @param suggestions The new suggestions to be shown in the suggestions carousel.
-     */
-    public void setSuggestions(List<SnippetArticle> suggestions) {
-        mSuggestionsList.clear();
-        mSuggestionsList.addAll(suggestions);
-
-        mObserver.updateAllSuggestionsOfflineAvailability(
-                /* reportPrefetchedSuggestionsCount = */ false);
-
-        notifyDataSetChanged();
-    }
-
-    private class OfflineModelObserver extends SuggestionsOfflineModelObserver<SnippetArticle> {
-        /**
-         * Constructor for an offline model observer. It registers itself with the bridge, but the
-         * unregistration will have to be done by the caller, either directly or by registering the
-         * created observer as {@link DestructionObserver}.
-         *
-         * @param bridge source of the offline state data.
-         */
-        public OfflineModelObserver(OfflinePageBridge bridge) {
-            super(bridge);
-        }
-
-        @Override
-        public void onSuggestionOfflineIdChanged(SnippetArticle suggestion, OfflinePageItem item) {
-            Long newId = item == null ? null : item.getOfflineId();
-
-            int index = mSuggestionsList.indexOf(suggestion);
-            // The suggestions could have been removed / replaced in the meantime.
-            if (index == -1) return;
-
-            Long oldId = suggestion.getOfflinePageOfflineId();
-            suggestion.setOfflinePageOfflineId(newId);
-
-            if ((oldId == null) == (newId == null)) return;
-            notifyItemChanged(index);
-        }
-
-        @Override
-        public Iterable<SnippetArticle> getOfflinableSuggestions() {
-            return mSuggestionsList;
-        }
-    }
-}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellImpl.java
index dc7e69f0..d8b4957f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellImpl.java
@@ -117,6 +117,7 @@
     private VrViewContainer mVrUiViewContainer;
     private FrameLayout mUiView;
     private ModalDialogManager mNonVrModalDialogManager;
+    private ModalDialogManager mVrModalDialogManager;
     private VrModalPresenter mVrModalPresenter;
 
     public VrShellImpl(
@@ -280,8 +281,9 @@
         mNonVrModalDialogManager = mActivity.getModalDialogManager();
         mNonVrModalDialogManager.cancelAllDialogs();
         mVrModalPresenter = new VrModalPresenter(this);
-        mActivity.setModalDialogManager(
-                new ModalDialogManager(mVrModalPresenter, ModalDialogManager.APP_MODAL));
+        mVrModalDialogManager =
+                new ModalDialogManager(mVrModalPresenter, ModalDialogManager.APP_MODAL);
+        mActivity.setModalDialogManager(mVrModalDialogManager);
 
         ViewGroup decor = (ViewGroup) mActivity.getWindow().getDecorView();
         mUiView = new FrameLayout(decor.getContext());
@@ -655,6 +657,11 @@
     @Override
     public void shutdown() {
         if (mVrBrowsingEnabled) {
+            if (mVrModalDialogManager != null) {
+                mVrModalDialogManager.cancelAllDialogs();
+                mActivity.setModalDialogManager(mNonVrModalDialogManager);
+                mVrModalDialogManager = null;
+            }
             mNonVrViews.destroy();
             if (mVrUiViewContainer != null) mVrUiViewContainer.destroy();
             removeVrRootView();
@@ -690,10 +697,6 @@
         ChromeFullscreenManager manager = mActivity.getFullscreenManager();
         manager.getBrowserVisibilityDelegate().showControlsTransient();
 
-        if (ChromeFeatureList.isEnabled(ChromeFeatureList.VR_BROWSING_NATIVE_ANDROID_UI)) {
-            mActivity.getModalDialogManager().cancelAllDialogs();
-            mActivity.setModalDialogManager(mNonVrModalDialogManager);
-        }
 
         FrameLayout decor = (FrameLayout) mActivity.getWindow().getDecorView();
         decor.removeView(mUiView);
diff --git a/chrome/android/java_sources.gni b/chrome/android/java_sources.gni
index 7756401..831035d 100644
--- a/chrome/android/java_sources.gni
+++ b/chrome/android/java_sources.gni
@@ -289,6 +289,14 @@
   "java/src/org/chromium/chrome/browser/contextualsearch/TapSuppressionHeuristics.java",
   "java/src/org/chromium/chrome/browser/contextualsearch/TapWordEdgeSuppression.java",
   "java/src/org/chromium/chrome/browser/contextualsearch/TapWordLengthSuppression.java",
+  "java/src/org/chromium/chrome/browser/contextual_suggestions/ContentCoordinator.java",
+  "java/src/org/chromium/chrome/browser/contextual_suggestions/ContextualSuggestionsAdapter.java",
+  "java/src/org/chromium/chrome/browser/contextual_suggestions/ContextualSuggestionsBottomSheetContent.java",
+  "java/src/org/chromium/chrome/browser/contextual_suggestions/ContextualSuggestionCardViewHolder.java",
+  "java/src/org/chromium/chrome/browser/contextual_suggestions/ContextualSuggestionsCoordinator.java",
+  "java/src/org/chromium/chrome/browser/contextual_suggestions/ContextualSuggestionsMediator.java",
+  "java/src/org/chromium/chrome/browser/contextual_suggestions/ContextualSuggestionsModel.java",
+  "java/src/org/chromium/chrome/browser/contextual_suggestions/DummyEventReporter.java",
   "java/src/org/chromium/chrome/browser/cookies/CanonicalCookie.java",
   "java/src/org/chromium/chrome/browser/cookies/CookiesFetcher.java",
   "java/src/org/chromium/chrome/browser/coordinator/CoordinatorLayoutForPointer.java",
@@ -651,6 +659,9 @@
   "java/src/org/chromium/chrome/browser/modaldialog/ModalDialogView.java",
   "java/src/org/chromium/chrome/browser/modaldialog/TabModalLifetimeHandler.java",
   "java/src/org/chromium/chrome/browser/modaldialog/TabModalPresenter.java",
+  "java/src/org/chromium/chrome/browser/modelutil/ListObservable.java",
+  "java/src/org/chromium/chrome/browser/modelutil/RecyclerViewModelChangeProcessor.java",
+  "java/src/org/chromium/chrome/browser/modelutil/RecyclerViewAdapter.java",
   "java/src/org/chromium/chrome/browser/mojo/ChromeInterfaceRegistrar.java",
   "java/src/org/chromium/chrome/browser/multiwindow/MultiInstanceChromeTabbedActivity.java",
   "java/src/org/chromium/chrome/browser/multiwindow/MultiWindowUtils.java",
@@ -1136,9 +1147,6 @@
   "java/src/org/chromium/chrome/browser/snackbar/undo/UndoBarController.java",
   "java/src/org/chromium/chrome/browser/ssl/CaptivePortalHelper.java",
   "java/src/org/chromium/chrome/browser/ssl/SecurityStateModel.java",
-  "java/src/org/chromium/chrome/browser/suggestions/ContextualSuggestionsCardViewHolder.java",
-  "java/src/org/chromium/chrome/browser/suggestions/ContextualSuggestionsManager.java",
-  "java/src/org/chromium/chrome/browser/suggestions/ContextualSuggestionsSection.java",
   "java/src/org/chromium/chrome/browser/suggestions/DestructionObserver.java",
   "java/src/org/chromium/chrome/browser/suggestions/ImageFetcher.java",
   "java/src/org/chromium/chrome/browser/suggestions/LogoItem.java",
@@ -1147,10 +1155,7 @@
   "java/src/org/chromium/chrome/browser/suggestions/SiteSection.java",
   "java/src/org/chromium/chrome/browser/suggestions/SiteSectionViewHolder.java",
   "java/src/org/chromium/chrome/browser/suggestions/SiteSuggestion.java",
-  "java/src/org/chromium/chrome/browser/suggestions/SuggestionsCarousel.java",
-  "java/src/org/chromium/chrome/browser/suggestions/SuggestionsCarouselAdapter.java",
   "java/src/org/chromium/chrome/browser/suggestions/SuggestionsBinder.java",
-  "java/src/org/chromium/chrome/browser/suggestions/SuggestionsBottomSheetContent.java",
   "java/src/org/chromium/chrome/browser/suggestions/SuggestionsConfig.java",
   "java/src/org/chromium/chrome/browser/suggestions/ThumbnailGradient.java",
   "java/src/org/chromium/chrome/browser/suggestions/Tile.java",
@@ -1808,7 +1813,6 @@
   "javatests/src/org/chromium/chrome/browser/snackbar/SnackbarTest.java",
   "javatests/src/org/chromium/chrome/browser/snackbar/undo/UndoBarControllerTest.java",
   "javatests/src/org/chromium/chrome/browser/suggestions/ContentSuggestionsTest.java",
-  "javatests/src/org/chromium/chrome/browser/suggestions/ContextualSuggestionsTest.java",
   "javatests/src/org/chromium/chrome/browser/suggestions/HomeSheetCardsUiCaptureTest.java",
   "javatests/src/org/chromium/chrome/browser/suggestions/HomeSheetNoTilesUiCaptureTest.java",
   "javatests/src/org/chromium/chrome/browser/suggestions/HomeSheetTilesUiCaptureTest.java",
@@ -2013,7 +2017,6 @@
   "junit/src/org/chromium/chrome/browser/signin/SigninPromoUtilTest.java",
   "junit/src/org/chromium/chrome/browser/snackbar/SnackbarCollectionUnitTest.java",
   "junit/src/org/chromium/chrome/browser/suggestions/ImageFetcherTest.java",
-  "junit/src/org/chromium/chrome/browser/suggestions/SuggestionsCarouselTest.java",
   "junit/src/org/chromium/chrome/browser/suggestions/TileGroupUnitTest.java",
   "junit/src/org/chromium/chrome/browser/superviseduser/SupervisedUserContentProviderUnitTest.java",
   "junit/src/org/chromium/chrome/browser/survey/ChromeHomeSurveyControllerTest.java",
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadNotificationServiceTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadNotificationServiceTest.java
index 55697b01..2ef756a 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadNotificationServiceTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadNotificationServiceTest.java
@@ -24,6 +24,7 @@
 import org.chromium.base.ContextUtils;
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.test.util.AdvancedMockContext;
+import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.Feature;
 import org.chromium.components.background_task_scheduler.BackgroundTaskScheduler;
 import org.chromium.components.background_task_scheduler.BackgroundTaskSchedulerFactory;
@@ -173,6 +174,7 @@
     @Test
     @SmallTest
     @Feature({"Download"})
+    @DisabledTest(message = "crbug.com/773346")
     public void testPausingWithoutOngoingDownloads() {
         setupService();
         startNotificationService();
@@ -193,6 +195,7 @@
     @Test
     @SmallTest
     @Feature({"Download"})
+    @DisabledTest(message = "crbug.com/773346")
     public void testResumptionScheduledWithoutDownloadOperationIntent() throws Exception {
         MockBackgroundTaskScheduler scheduler = new MockBackgroundTaskScheduler();
         BackgroundTaskSchedulerFactory.setSchedulerForTesting(scheduler);
@@ -216,6 +219,7 @@
     @Test
     @SmallTest
     @Feature({"Download"})
+    @DisabledTest(message = "crbug.com/653609")
     public void testResumptionNotScheduledWithDownloadOperationIntent() {
         MockBackgroundTaskScheduler scheduler = new MockBackgroundTaskScheduler();
         BackgroundTaskSchedulerFactory.setSchedulerForTesting(scheduler);
@@ -238,6 +242,7 @@
     @Test
     @SmallTest
     @Feature({"Download"})
+    @DisabledTest(message = "crbug.com/773346")
     public void testResumptionNotScheduledWithoutAutoResumableDownload() throws Exception {
         MockBackgroundTaskScheduler scheduler = new MockBackgroundTaskScheduler();
         BackgroundTaskSchedulerFactory.setSchedulerForTesting(scheduler);
@@ -259,6 +264,7 @@
     @Test
     @SmallTest
     @Feature({"Download"})
+    @DisabledTest(message = "crbug.com/773346")
     public void testPausingWithOngoingDownloads() {
         setupService();
         Context mockContext = new AdvancedMockContext(InstrumentationRegistry.getTargetContext());
@@ -292,6 +298,7 @@
     @Test
     @SmallTest
     @Feature({"Download"})
+    @DisabledTest(message = "crbug.com/773346")
     public void testAddingAndCancelingNotifications() {
         setupService();
         Context mockContext = new AdvancedMockContext(InstrumentationRegistry.getTargetContext());
@@ -361,6 +368,7 @@
     @Test
     @SmallTest
     @Feature({"Download"})
+    @DisabledTest(message = "crbug.com/773346")
     public void testDownloadSuccessNotification() {
         setupService();
         startNotificationService();
@@ -377,6 +385,7 @@
     @Test
     @SmallTest
     @Feature({"Download"})
+    @DisabledTest(message = "crbug.com/773346")
     public void testResumeAllPendingDownloads() throws Exception {
         setupService();
         Context mockContext = new AdvancedMockContext(InstrumentationRegistry.getTargetContext());
@@ -425,6 +434,7 @@
     @Test
     @SmallTest
     @Feature({"Download"})
+    @DisabledTest(message = "crbug.com/773346")
     public void testIncognitoDownloadCanceledOnServiceShutdown() throws Exception {
         setupService();
         Context mockContext = new AdvancedMockContext(InstrumentationRegistry.getTargetContext());
@@ -454,6 +464,7 @@
     @Test
     @SmallTest
     @Feature({"Download"})
+    @DisabledTest(message = "crbug.com/773346")
     public void testServiceWillStopOnCompletedDownload() throws Exception {
         // On versions of Android that use a foreground service, the service will currently die with
         // the notifications.
@@ -474,6 +485,7 @@
     @Test
     @SmallTest
     @Feature({"Download"})
+    @DisabledTest(message = "crbug.com/773346")
     public void testServiceWillStopOnFailedDownload() throws Exception {
         // On versions of Android that use a foreground service, the service will currently die with
         // the notifications.
@@ -493,6 +505,7 @@
     @Test
     @SmallTest
     @Feature({"Download"})
+    @DisabledTest(message = "crbug.com/773346")
     public void testServiceWillStopOnCancelledDownload() throws Exception {
         // On versions of Android that use a foreground service, the service will currently die with
         // the notifications.
@@ -531,6 +544,7 @@
     @Test
     @SmallTest
     @Feature({"Download"})
+    @DisabledTest(message = "crbug.com/773346")
     public void testServiceWillNotStopOnPausedDownload() throws Exception {
         // On versions of Android that use a foreground service, the service will currently die with
         // the notifications.
@@ -550,6 +564,7 @@
     @Test
     @SmallTest
     @Feature({"Download"})
+    @DisabledTest(message = "crbug.com/773346")
     public void testServiceWillNotStopWithOneOngoingDownload() throws Exception {
         // On versions of Android that use a foreground service, the service will currently die with
         // the notifications.
@@ -579,6 +594,7 @@
     @Test
     @SmallTest
     @Feature({"Download"})
+    @DisabledTest(message = "crbug.com/773346")
     public void testForegroundServiceStopsIfCancelIsCalledWhenServiceIsStopped() {
         // On versions of Android that use a foreground service, the service will currently die with
         // the notifications.
@@ -604,6 +620,7 @@
     @Test
     @SmallTest
     @Feature({"Download"})
+    @DisabledTest(message = "crbug.com/773346")
     public void testForegroundServiceStopsIfPauseIsCalledWhenServiceIsStopped() {
         // This only applies to versions that uses the foreground service.
         if (!DownloadNotificationService.useForegroundService()) return;
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/password/SavePasswordsPreferencesTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/password/SavePasswordsPreferencesTest.java
index 925ccc7..bed29ee6e 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/password/SavePasswordsPreferencesTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/password/SavePasswordsPreferencesTest.java
@@ -859,6 +859,10 @@
         MetricsUtils.HistogramDelta countDelta = new MetricsUtils.HistogramDelta(
                 "PasswordManager.ExportedPasswordsPerUserInCSV", 123);
 
+        MetricsUtils.HistogramDelta progressBarDelta = new MetricsUtils.HistogramDelta(
+                "PasswordManager.Android.ExportPasswordsProgressBarUsage",
+                SavePasswordsPreferences.PROGRESS_NOT_SHOWN);
+
         // Confirm the export warning to fire the sharing intent.
         Espresso.onView(withText(R.string.save_password_preferences_export_action_title))
                 .perform(click());
@@ -871,6 +875,7 @@
 
         Assert.assertEquals(1, successDelta.getDelta());
         Assert.assertEquals(1, countDelta.getDelta());
+        Assert.assertEquals(1, progressBarDelta.getDelta());
     }
 
     /**
@@ -1121,6 +1126,10 @@
         Espresso.onView(withText(R.string.settings_passwords_preparing_export))
                 .check(matches(isDisplayed()));
 
+        MetricsUtils.HistogramDelta progressBarDelta = new MetricsUtils.HistogramDelta(
+                "PasswordManager.Android.ExportPasswordsProgressBarUsage",
+                SavePasswordsPreferences.PROGRESS_HIDDEN_DELAYED);
+
         // Now pretend that passwords have been serialized.
         mHandler.getExportCallback().onResult(new byte[] {5, 6, 7}, 12);
 
@@ -1139,6 +1148,7 @@
                         allOf(hasAction(equalTo(Intent.ACTION_SEND)), hasType("text/csv"))))));
 
         Intents.release();
+        Assert.assertEquals(1, progressBarDelta.getDelta());
     }
 
     /**
@@ -1178,6 +1188,10 @@
         Espresso.onView(withText(R.string.settings_passwords_preparing_export))
                 .check(matches(isDisplayed()));
 
+        MetricsUtils.HistogramDelta progressBarDelta = new MetricsUtils.HistogramDelta(
+                "PasswordManager.Android.ExportPasswordsProgressBarUsage",
+                SavePasswordsPreferences.PROGRESS_HIDDEN_DIRECTLY);
+
         // Now pretend that passwords have been serialized.
         allowProgressBarToBeHidden(preferences);
         mHandler.getExportCallback().onResult(new byte[] {5, 6, 7}, 12);
@@ -1192,6 +1206,7 @@
                         allOf(hasAction(equalTo(Intent.ACTION_SEND)), hasType("text/csv"))))));
 
         Intents.release();
+        Assert.assertEquals(1, progressBarDelta.getDelta());
     }
 
     /**
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/suggestions/ContextualSuggestionsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/suggestions/ContextualSuggestionsTest.java
deleted file mode 100644
index b1fb8bd1..0000000
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/suggestions/ContextualSuggestionsTest.java
+++ /dev/null
@@ -1,205 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.chrome.browser.suggestions;
-
-import static org.chromium.chrome.test.util.browser.Features.EnableFeatures;
-
-import android.support.annotation.Nullable;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.MediumTest;
-import android.support.test.filters.SmallTest;
-import android.support.v7.widget.RecyclerView;
-import android.view.View;
-
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TestRule;
-import org.junit.runner.RunWith;
-
-import org.chromium.base.test.util.DisabledTest;
-import org.chromium.base.test.util.Feature;
-import org.chromium.base.test.util.Restriction;
-import org.chromium.chrome.browser.ChromeFeatureList;
-import org.chromium.chrome.browser.ntp.cards.ItemViewType;
-import org.chromium.chrome.browser.ntp.snippets.KnownCategories;
-import org.chromium.chrome.browser.ntp.snippets.SnippetArticle;
-import org.chromium.chrome.browser.util.FeatureUtilities;
-import org.chromium.chrome.browser.widget.bottomsheet.BottomSheet;
-import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
-import org.chromium.chrome.test.util.RenderTestRule;
-import org.chromium.chrome.test.util.browser.ChromeHome;
-import org.chromium.chrome.test.util.browser.Features;
-import org.chromium.chrome.test.util.browser.suggestions.FakeSuggestionsSource;
-import org.chromium.chrome.test.util.browser.suggestions.SuggestionsDependenciesRule;
-import org.chromium.net.test.EmbeddedTestServerRule;
-import org.chromium.ui.test.util.UiRestriction;
-
-import java.io.IOException;
-import java.util.Arrays;
-import java.util.List;
-import java.util.concurrent.TimeoutException;
-
-/**
- * Integration tests for Contextual suggestions.
- */
-@DisabledTest(message = "https://crbug.com/805160")
-@RunWith(ChromeJUnit4ClassRunner.class)
-@Restriction(UiRestriction.RESTRICTION_TYPE_PHONE)
-public class ContextualSuggestionsTest {
-    private static final String TEST_PAGE = "/chrome/test/data/android/test.html";
-
-    private static final List<SnippetArticle> FAKE_CONTEXTUAL_SUGGESTIONS = Arrays.asList(
-            new SnippetArticle(KnownCategories.CONTEXTUAL, // category
-                    "suggestion0", // idWithinCategory
-                    "James Roderick to step down as conductor for Laville orchestra", // title
-                    "The Curious One", // publisher
-                    "http://example.com", // url
-                    0, // publishTimestamp
-                    0.0f, // score
-                    0L, // fetchTimestamp
-                    false, // isVideoSuggestion
-                    null), // thumbnailDominantColor
-            new SnippetArticle(KnownCategories.CONTEXTUAL, // category
-                    "suggestion1", // idWithinCategory
-                    "Boy raises orphaned goat", // title
-                    "Meme feed", // publisher
-                    "http://example.com", // url
-                    0, // publishTimestamp
-                    0.0f, // score
-                    0L, // fetchTimestamp
-                    false, // isVideoSuggestion
-                    null), // thumbnailDominantColor
-            new SnippetArticle(KnownCategories.CONTEXTUAL, // category
-                    "suggestion2", // idWithinCategory
-                    "Top gigs this week", // title
-                    "Hello World", // publisher
-                    "http://example.com", // url
-                    0, // publishTimestamp
-                    0.0f, // score
-                    0L, // fetchTimestamp
-                    false, // isVideoSuggestion
-                    null)); // thumbnailDominantColor
-    @Rule
-    public TestRule mChromeHomeStateRule = new ChromeHome.Processor();
-    @Rule
-    public TestRule mProcessor = new Features.InstrumentationProcessor();
-    @Rule
-    public SuggestionsDependenciesRule mSuggestionsDeps = new SuggestionsDependenciesRule();
-    @Rule
-    public SuggestionsBottomSheetTestRule mActivityRule = new SuggestionsBottomSheetTestRule();
-    @Rule
-    public EmbeddedTestServerRule mTestServerRule = new EmbeddedTestServerRule();
-    @Rule
-    public RenderTestRule mRenderTestRule = new RenderTestRule();
-
-    private FakeSuggestionsSource mSuggestionsSource;
-
-    @Before
-    public void setUp() throws Exception {
-        mSuggestionsSource = new FakeSuggestionsSource();
-        mSuggestionsSource.setThumbnailForId("suggestion0", "/android/UiCapture/conductor.jpg");
-        mSuggestionsSource.setThumbnailForId("suggestion1", "/android/UiCapture/goat.jpg");
-        mSuggestionsSource.setThumbnailForId("suggestion2", "/android/UiCapture/gig.jpg");
-
-        mSuggestionsDeps.getFactory().suggestionsSource = mSuggestionsSource;
-
-        mActivityRule.startMainActivityOnBottomSheet(BottomSheet.SHEET_STATE_PEEK);
-
-        Assert.assertTrue(FeatureUtilities.isChromeHomeEnabled());
-    }
-
-    @Test
-    @SmallTest
-    @Feature({"ContextualSuggestions"})
-    @ChromeHome.Enable
-    public void testCarouselIsNotShownWhenFlagIsDisabled() {
-        Assert.assertFalse(
-                ChromeFeatureList.isEnabled(ChromeFeatureList.CONTEXTUAL_SUGGESTIONS_CAROUSEL));
-
-        mActivityRule.setSheetState(BottomSheet.SHEET_STATE_HALF, false);
-        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
-
-        View carouselRecyclerView = getCarouselRecyclerView();
-        Assert.assertNull(carouselRecyclerView);
-    }
-
-    @Test
-    @SmallTest
-    @DisabledTest(message = "See crbug.com/758179. The fix there involves setting the"
-                    + "SuggestionsCarousel to always be visible inside the NewTabPageAdapter."
-                    + "However, the desired behaviour is that it is only visible when there are"
-                    + "suggestions to show. This test covers the desired behaviour and should be"
-                    + "enabled when this is handled properly.")
-    @Feature({"ContextualSuggestions"})
-    @ChromeHome.Enable
-    @EnableFeatures(ChromeFeatureList.CONTEXTUAL_SUGGESTIONS_CAROUSEL)
-    public void testCarouselIsNotShownWhenFlagsEnabledButNoSuggestions() {
-        Assert.assertTrue(
-                ChromeFeatureList.isEnabled(ChromeFeatureList.CONTEXTUAL_SUGGESTIONS_CAROUSEL));
-
-        mActivityRule.setSheetState(BottomSheet.SHEET_STATE_HALF, false);
-        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
-
-        View carouselRecyclerView = getCarouselRecyclerView();
-        Assert.assertNull(carouselRecyclerView);
-    }
-
-    @Test
-    @SmallTest
-    @Feature({"ContextualSuggestions"})
-    @ChromeHome.Enable
-    @EnableFeatures(ChromeFeatureList.CONTEXTUAL_SUGGESTIONS_CAROUSEL)
-    public void testCarouselIsShownWhenItReceivedSuggestions()
-            throws InterruptedException, TimeoutException {
-        mSuggestionsSource.setContextualSuggestions(FAKE_CONTEXTUAL_SUGGESTIONS);
-
-        String testUrl = mTestServerRule.getServer().getURL(TEST_PAGE);
-        mActivityRule.loadUrl(testUrl);
-        mActivityRule.setSheetState(BottomSheet.SHEET_STATE_HALF, false);
-
-        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
-        mActivityRule.getObserver().mOpenedCallbackHelper.waitForCallback(0);
-
-        View carouselRecyclerView = getCarouselRecyclerView();
-        Assert.assertNotNull(carouselRecyclerView);
-
-        RecyclerView.Adapter<?> carouselAdapter =
-                ((RecyclerView) carouselRecyclerView).getAdapter();
-
-        Assert.assertEquals(FAKE_CONTEXTUAL_SUGGESTIONS.size(), carouselAdapter.getItemCount());
-    }
-
-    @Test
-    @MediumTest
-    @Feature({"ContextualSuggestions", "RenderTest"})
-    @ChromeHome.Enable
-    @EnableFeatures(ChromeFeatureList.CONTEXTUAL_SUGGESTIONS_CAROUSEL)
-    public void testCardAppearance() throws InterruptedException, TimeoutException, IOException {
-        mSuggestionsSource.setContextualSuggestions(FAKE_CONTEXTUAL_SUGGESTIONS);
-
-        String testUrl = mTestServerRule.getServer().getURL(TEST_PAGE);
-        mActivityRule.loadUrl(testUrl);
-        mActivityRule.setSheetState(BottomSheet.SHEET_STATE_HALF, false);
-
-        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
-        mActivityRule.getObserver().mOpenedCallbackHelper.waitForCallback(0);
-
-        RecyclerView recyclerView = getCarouselRecyclerView();
-
-        mRenderTestRule.render(recyclerView.getChildAt(0), "contextual_suggestions_card");
-    }
-
-    @Nullable
-    private RecyclerView getCarouselRecyclerView() {
-        SuggestionsRecyclerView mainRecyclerView = mActivityRule.getRecyclerView();
-        int position = mainRecyclerView.getNewTabPageAdapter().getFirstPositionForType(
-                ItemViewType.CAROUSEL);
-        if (position == RecyclerView.NO_POSITION) return null;
-
-        return (RecyclerView) mainRecyclerView.getChildAt(position);
-    }
-}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/WebVrInputTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/WebVrInputTest.java
index db16e93..25947c5 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/WebVrInputTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/WebVrInputTest.java
@@ -33,6 +33,7 @@
 import org.chromium.base.test.params.ParameterizedRunner;
 import org.chromium.base.test.util.CommandLineFlags;
 import org.chromium.base.test.util.DisableIf;
+import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.MinAndroidSdkLevel;
 import org.chromium.base.test.util.Restriction;
 import org.chromium.base.test.util.RetryOnFailure;
@@ -208,6 +209,7 @@
     @CommandLineFlags.Remove({"enable-webvr"})
     @CommandLineFlags.Add({"enable-features=WebXR"})
     @VrActivityRestriction({VrActivityRestriction.SupportedActivity.ALL})
+    @DisabledTest(message = "crbug.com/824194")
     public void testControllerClicksRegisteredOnDaydream_WebXr() throws InterruptedException {
         EmulatedVrController controller = new EmulatedVrController(mTestRule.getActivity());
         mXrTestFramework.loadUrlAndAwaitInitialization(
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapterTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapterTest.java
index ec69ef5..49ccb4a 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapterTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapterTest.java
@@ -1344,7 +1344,7 @@
         mSource.removeObservers();
         mAdapter = new NewTabPageAdapter(mUiDelegate, mock(View.class), /* logoView = */ null,
                 makeUiConfig(), mOfflinePageBridge, mock(ContextMenuManager.class),
-                /* tileGroupDelegate = */ null, /* suggestionsCarousel = */ null);
+                /* tileGroupDelegate = */ null);
         mAdapter.refreshSuggestions();
     }
 
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/preferences/password/DialogManagerTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/preferences/password/DialogManagerTest.java
index d4ae8d27..5a101be 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/preferences/password/DialogManagerTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/preferences/password/DialogManagerTest.java
@@ -76,8 +76,12 @@
     /** Used to detect showing and hiding without actually triggering any UI. */
     private final FakeDialogFragment mDialogFragment = new FakeDialogFragment();
 
+    /** Used to test reporting from DialogManager. */
+    private final DialogManager.ActionsConsumer mMockActionsConsumer =
+            mock(DialogManager.ActionsConsumer.class);
+
     /** The object under test. */
-    private final DialogManager mDialogManager = new DialogManager();
+    private final DialogManager mDialogManager = new DialogManager(mMockActionsConsumer);
 
     /**
      * Delayer to replace the timed one in the tested class. This gives exact control over hiding
@@ -105,6 +109,23 @@
         mManualDelayer.runCallbacksSynchronously();
         verify(callback, times(1)).run();
         assertEquals(FakeDialogFragment.DISMISSED, mDialogFragment.getState());
+        verify(mMockActionsConsumer, times(1)).consume(DialogManager.ACTION_HIDING_DELAYED);
+    }
+
+    /**
+     * Check that immediate hiding is notified properly.
+     */
+    @Test
+    public void testNotification() {
+        mDialogManager.show(mDialogFragment, null);
+
+        Runnable callback = mock(Runnable.class);
+        mManualDelayer.runCallbacksSynchronously();
+        mDialogManager.hide(callback);
+        Robolectric.getForegroundThreadScheduler().advanceToLastPostedRunnable();
+        verify(callback, times(1)).run();
+        assertEquals(FakeDialogFragment.DISMISSED, mDialogFragment.getState());
+        verify(mMockActionsConsumer, times(1)).consume(DialogManager.ACTION_HIDDEN_IMMEDIATELY);
     }
 
     /**
@@ -117,5 +138,6 @@
         Robolectric.getForegroundThreadScheduler().advanceToLastPostedRunnable();
         verify(callback, times(1)).run();
         assertEquals(FakeDialogFragment.NEW, mDialogFragment.getState());
+        verify(mMockActionsConsumer, times(1)).consume(DialogManager.ACTION_NO_OP);
     }
 }
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/suggestions/SuggestionsCarouselTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/suggestions/SuggestionsCarouselTest.java
deleted file mode 100644
index 85a479e..0000000
--- a/chrome/android/junit/src/org/chromium/chrome/browser/suggestions/SuggestionsCarouselTest.java
+++ /dev/null
@@ -1,85 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.chrome.browser.suggestions;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.content.Context;
-
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TestRule;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.robolectric.RuntimeEnvironment;
-import org.robolectric.annotation.Config;
-
-import org.chromium.base.CommandLine;
-import org.chromium.base.test.BaseRobolectricTestRunner;
-import org.chromium.chrome.browser.ChromeFeatureList;
-import org.chromium.chrome.browser.ntp.ContextMenuManager;
-import org.chromium.chrome.browser.ntp.snippets.SuggestionsSource;
-import org.chromium.chrome.browser.offlinepages.OfflinePageBridge;
-import org.chromium.chrome.browser.widget.displaystyle.UiConfig;
-import org.chromium.chrome.test.util.browser.Features;
-import org.chromium.chrome.test.util.browser.Features.EnableFeatures;
-
-/**
- * Unit tests for {@link SuggestionsCarousel}.
- */
-@RunWith(BaseRobolectricTestRunner.class)
-@Config(manifest = Config.NONE)
-@EnableFeatures({ChromeFeatureList.CHROME_HOME, ChromeFeatureList.CONTEXTUAL_SUGGESTIONS_CAROUSEL})
-public class SuggestionsCarouselTest {
-    private static final String URL_STRING = "http://www.test.com";
-    private static final String INVALID_URL = "file://URL";
-
-    @Rule
-    public TestRule processor = new Features.JUnitProcessor();
-
-    @Mock
-    private SuggestionsSource mSuggestionsSource;
-    private SuggestionsCarousel mCarousel;
-    private Context mContext;
-
-    @Before
-    public void setUp() {
-        MockitoAnnotations.initMocks(this);
-        CommandLine.init(null);
-
-        SuggestionsUiDelegate uiDelegate = mock(SuggestionsUiDelegate.class);
-        when(uiDelegate.getSuggestionsSource()).thenReturn(mSuggestionsSource);
-
-        mCarousel = spy(new SuggestionsCarousel(mock(UiConfig.class), uiDelegate,
-                mock(ContextMenuManager.class), mock(OfflinePageBridge.class)));
-
-        mContext = RuntimeEnvironment.application;
-    }
-
-    @Test
-    public void testInvalidUrl() {
-        mCarousel.refresh(mContext, /* newURL = */ null);
-        mCarousel.refresh(mContext, /* newURL = */ "");
-        mCarousel.refresh(mContext, INVALID_URL);
-        verify(mSuggestionsSource, never()).fetchContextualSuggestions(anyString(), any());
-    }
-
-    @Test
-    public void testValidUrlInitiatesSuggestionsFetch() {
-        doReturn(false).when(mCarousel).isContextTheSame(any());
-
-        mCarousel.refresh(mContext, URL_STRING);
-        verify(mSuggestionsSource).fetchContextualSuggestions(anyString(), any());
-    }
-}
diff --git a/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/BookmarksTest.java b/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/BookmarksTest.java
index 9a0c1db..81841f8 100644
--- a/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/BookmarksTest.java
+++ b/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/BookmarksTest.java
@@ -17,8 +17,8 @@
 
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.test.util.CommandLineFlags;
+import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.Feature;
-import org.chromium.base.test.util.FlakyTest;
 import org.chromium.chrome.browser.ChromeSwitches;
 import org.chromium.chrome.browser.bookmarks.BookmarkBridge;
 import org.chromium.chrome.browser.profiles.Profile;
@@ -315,7 +315,7 @@
     @Test
     @LargeTest
     @Feature({"Sync"})
-    @FlakyTest(message = "crbug.com/823484")
+    @DisabledTest(message = "crbug.com/823484")
     public void testUploadMovedBookmark() throws Exception {
         // Add the entity to test moving.
         BookmarkId bookmarkId = addClientBookmark(TITLE, URL);
diff --git a/chrome/app/chrome_main_delegate.cc b/chrome/app/chrome_main_delegate.cc
index 39ea4c2..efcb4b9 100644
--- a/chrome/app/chrome_main_delegate.cc
+++ b/chrome/app/chrome_main_delegate.cc
@@ -332,10 +332,9 @@
 #endif
 
   if (command_line.HasSwitch(switches::kVersion)) {
-    printf("%s %s %s\n",
-           version_info::GetProductName().c_str(),
+    printf("%s %s %s\n", version_info::GetProductName().c_str(),
            version_info::GetVersionNumber().c_str(),
-           chrome::GetChannelString().c_str());
+           chrome::GetChannelName().c_str());
     return true;
   }
 
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index af8f692..9e541eb 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -2509,15 +2509,11 @@
      flag_descriptions::kEnableNtpSnippetsVisibilityName,
      flag_descriptions::kEnableNtpSnippetsVisibilityDescription, kOsAndroid,
      FEATURE_VALUE_TYPE(ntp_snippets::kIncreasedVisibility)},
-    {"enable-contextual-suggestions-above-articles",
-     flag_descriptions::kContextualSuggestionsAboveArticlesName,
-     flag_descriptions::kContextualSuggestionsAboveArticlesDescription,
+    {"enable-contextual-suggestions-bottom-sheet",
+     flag_descriptions::kContextualSuggestionsBottomSheetName,
+     flag_descriptions::kContextualSuggestionsBottomSheetDescription,
      kOsAndroid,
-     FEATURE_VALUE_TYPE(chrome::android::kContextualSuggestionsAboveArticles)},
-    {"enable-contextual-suggestions-carousel",
-     flag_descriptions::kContextualSuggestionsCarouselName,
-     flag_descriptions::kContextualSuggestionsCarouselDescription, kOsAndroid,
-     FEATURE_VALUE_TYPE(chrome::android::kContextualSuggestionsCarousel)},
+     FEATURE_VALUE_TYPE(chrome::android::kContextualSuggestionsBottomSheet)},
     {"enable-content-suggestions-new-favicon-server",
      flag_descriptions::kEnableContentSuggestionsNewFaviconServerName,
      flag_descriptions::kEnableContentSuggestionsNewFaviconServerDescription,
diff --git a/chrome/browser/android/chrome_feature_list.cc b/chrome/browser/android/chrome_feature_list.cc
index 143808f..128296b 100644
--- a/chrome/browser/android/chrome_feature_list.cc
+++ b/chrome/browser/android/chrome_feature_list.cc
@@ -68,7 +68,6 @@
     &kCCTPostMessageAPI,
     &kCCTRedirectPreconnect,
     &kChromeDuplexFeature,
-    &kChromeHomeDropAllButFirstThumbnail,
     &kChromeHomeInactivitySheetExpansion,
     &kChromeHomeMenuItemsExpandSheet,
     &kChromeHomePersistentIph,
@@ -86,8 +85,7 @@
     &kContextualSearchMlTapSuppression,
     &kContextualSearchSecondTap,
     &kContextualSearchTapDisableOverride,
-    &kContextualSuggestionsAboveArticles,
-    &kContextualSuggestionsCarousel,
+    &kContextualSuggestionsBottomSheet,
     &kCustomContextMenu,
     &kCustomFeedbackUi,
     &kDontPrefetchLibraries,
@@ -196,9 +194,6 @@
 const base::Feature kChromeDuplexFeature{"ChromeDuplex",
                                          base::FEATURE_DISABLED_BY_DEFAULT};
 
-const base::Feature kChromeHomeDropAllButFirstThumbnail{
-    "ChromeHomeDropAllButFirstThumbnail", base::FEATURE_DISABLED_BY_DEFAULT};
-
 const base::Feature kChromeHomeInactivitySheetExpansion{
     "ChromeHomeInactivitySheetExpansion", base::FEATURE_DISABLED_BY_DEFAULT};
 
@@ -251,11 +246,8 @@
 const base::Feature kContextualSearchTapDisableOverride{
     "ContextualSearchTapDisableOverride", base::FEATURE_DISABLED_BY_DEFAULT};
 
-const base::Feature kContextualSuggestionsCarousel{
-    "ContextualSuggestionsCarousel", base::FEATURE_DISABLED_BY_DEFAULT};
-
-const base::Feature kContextualSuggestionsAboveArticles{
-    "ContextualSuggestionsAboveArticles", base::FEATURE_DISABLED_BY_DEFAULT};
+const base::Feature kContextualSuggestionsBottomSheet{
+    "ContextualSuggestionsBottomSheet", base::FEATURE_DISABLED_BY_DEFAULT};
 
 const base::Feature kCustomContextMenu{"CustomContextMenu",
                                        base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/chrome/browser/android/chrome_feature_list.h b/chrome/browser/android/chrome_feature_list.h
index b877cb49..91c660f 100644
--- a/chrome/browser/android/chrome_feature_list.h
+++ b/chrome/browser/android/chrome_feature_list.h
@@ -23,7 +23,6 @@
 extern const base::Feature kCCTPostMessageAPI;
 extern const base::Feature kCCTRedirectPreconnect;
 extern const base::Feature kChromeDuplexFeature;
-extern const base::Feature kChromeHomeDropAllButFirstThumbnail;
 extern const base::Feature kChromeHomeInactivitySheetExpansion;
 extern const base::Feature kChromeHomeMenuItemsExpandSheet;
 extern const base::Feature kChromeHomePersistentIph;
@@ -41,8 +40,7 @@
 extern const base::Feature kContextualSearchMlTapSuppression;
 extern const base::Feature kContextualSearchSecondTap;
 extern const base::Feature kContextualSearchTapDisableOverride;
-extern const base::Feature kContextualSuggestionsAboveArticles;
-extern const base::Feature kContextualSuggestionsCarousel;
+extern const base::Feature kContextualSuggestionsBottomSheet;
 extern const base::Feature kCustomContextMenu;
 extern const base::Feature kCustomFeedbackUi;
 extern const base::Feature kDontPrefetchLibraries;
diff --git a/chrome/browser/android/customtabs/detached_resource_request.cc b/chrome/browser/android/customtabs/detached_resource_request.cc
index 45dcb14..65d6e97 100644
--- a/chrome/browser/android/customtabs/detached_resource_request.cc
+++ b/chrome/browser/android/customtabs/detached_resource_request.cc
@@ -49,7 +49,10 @@
     const GURL& site_for_cookies,
     net::URLRequest::ReferrerPolicy referrer_policy,
     DetachedResourceRequest::OnResultCallback cb)
-    : url_(url), site_for_cookies_(site_for_cookies), cb_(std::move(cb)) {
+    : url_(url),
+      site_for_cookies_(site_for_cookies),
+      cb_(std::move(cb)),
+      redirects_(0) {
   net::NetworkTrafficAnnotationTag traffic_annotation =
       net::DefineNetworkTrafficAnnotation("customtabs_parallel_request",
                                           R"(
@@ -97,6 +100,11 @@
   request->start_time_ = base::TimeTicks::Now();
   auto* storage_partition =
       content::BrowserContext::GetStoragePartition(browser_context, nullptr);
+
+  request->url_loader_->SetOnRedirectCallback(
+      base::BindRepeating(&DetachedResourceRequest::OnRedirectCallback,
+                          base::Unretained(request.get())));
+
   // |url_loader_| is owned by the request, and must be kept alive to not cancel
   // the request. Pass the ownership of the request to the response callback,
   // ensuring that it stays alive, yet is freed upon completion or failure.
@@ -110,15 +118,28 @@
       kMaxResponseSize);
 }
 
+void DetachedResourceRequest::OnRedirectCallback(
+    const net::RedirectInfo& redirect_info,
+    const network::ResourceResponseHead& response_head) {
+  redirects_++;
+}
+
 void DetachedResourceRequest::OnResponseCallback(
     std::unique_ptr<std::string> response_body) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   bool success = url_loader_->NetError() == net::OK;
   auto duration = base::TimeTicks::Now() - start_time_;
   if (success) {
+    // Max 20 redirects, 21 would be a bug.
+    UMA_HISTOGRAM_CUSTOM_COUNTS(
+        "CustomTabs.DetachedResourceRequest.RedirectsCount.Success", redirects_,
+        1, 21, 21);
     UMA_HISTOGRAM_MEDIUM_TIMES(
         "CustomTabs.DetachedResourceRequest.Duration.Success", duration);
   } else {
+    UMA_HISTOGRAM_CUSTOM_COUNTS(
+        "CustomTabs.DetachedResourceRequest.RedirectsCount.Failure", redirects_,
+        1, 21, 21);
     UMA_HISTOGRAM_MEDIUM_TIMES(
         "CustomTabs.DetachedResourceRequest.Duration.Failure", duration);
   }
diff --git a/chrome/browser/android/customtabs/detached_resource_request.h b/chrome/browser/android/customtabs/detached_resource_request.h
index 469f1148..5b90ac1 100644
--- a/chrome/browser/android/customtabs/detached_resource_request.h
+++ b/chrome/browser/android/customtabs/detached_resource_request.h
@@ -14,14 +14,19 @@
 #include "net/url_request/url_request.h"
 #include "url/gurl.h"
 
-namespace network {
-class SimpleURLLoader;
-}
-
 namespace content {
 class BrowserContext;
 }
 
+namespace net {
+struct RedirectInfo;
+}
+
+namespace network {
+class SimpleURLLoader;
+struct ResourceResponseHead;
+}  // namespace network
+
 namespace customtabs {
 
 // Detached resource request, that is a resource request initiated from the
@@ -54,6 +59,8 @@
 
   static void Start(std::unique_ptr<DetachedResourceRequest> request,
                     content::BrowserContext* browser_context);
+  void OnRedirectCallback(const net::RedirectInfo& redirect_info,
+                          const network::ResourceResponseHead& response_head);
   void OnResponseCallback(std::unique_ptr<std::string> response_body);
 
   const GURL url_;
@@ -61,6 +68,7 @@
   base::TimeTicks start_time_;
   OnResultCallback cb_;
   std::unique_ptr<network::SimpleURLLoader> url_loader_;
+  int redirects_;
 
   DISALLOW_COPY_AND_ASSIGN(DetachedResourceRequest);
 };
diff --git a/chrome/browser/android/customtabs/detached_resource_request_unittest.cc b/chrome/browser/android/customtabs/detached_resource_request_unittest.cc
index a8f2593..fa6a6fb 100644
--- a/chrome/browser/android/customtabs/detached_resource_request_unittest.cc
+++ b/chrome/browser/android/customtabs/detached_resource_request_unittest.cc
@@ -8,6 +8,7 @@
 
 #include "base/files/file_path.h"
 #include "base/run_loop.h"
+#include "base/strings/string_number_conversions.h"
 #include "base/test/bind_test_util.h"
 #include "base/test/histogram_tester.h"
 #include "chrome/browser/android/customtabs/detached_resource_request.h"
@@ -26,8 +27,8 @@
 #include "url/gurl.h"
 
 namespace customtabs {
-
 namespace {
+
 using net::test_server::HttpRequest;
 using net::test_server::HttpResponse;
 using net::test_server::RequestQuery;
@@ -36,14 +37,17 @@
 constexpr const char kSetCookieAndNoContent[] = "/set-cookie-and-no-content";
 constexpr const char kHttpNoContent[] = "/nocontent";
 constexpr const char kEchoTitle[] = "/echotitle";
+constexpr const char kManyRedirects[] = "/many-redirects";
 constexpr const char kCookieKey[] = "cookie";
 constexpr const char kUrlKey[] = "url";
 constexpr const char kCookieFromNoContent[] = "no-content-cookie";
+constexpr const char kIndexKey[] = "index";
+constexpr const char kMaxKey[] = "max";
 
 // /set-cookie-and-redirect?cookie=bla&url=https://redictected-url
 // Sets a cookies, then responds with HTTP code 302.
 std::unique_ptr<HttpResponse> SetCookieAndRedirect(const HttpRequest& request) {
-  const auto& url = request.GetURL();
+  const GURL& url = request.GetURL();
   if (url.path() != kSetCookieAndRedirect || !url.has_query())
     return nullptr;
 
@@ -66,11 +70,49 @@
   return response;
 }
 
+// /many-redirects?index=0&max=10
+// Redirects a given amount of times, then responds with HTTP code 204.
+std::unique_ptr<HttpResponse> ManyRedirects(const HttpRequest& request) {
+  const GURL& url = request.GetURL();
+  if (url.path() != kManyRedirects || !url.has_query())
+    return nullptr;
+
+  auto response = std::make_unique<net::test_server::BasicHttpResponse>();
+  RequestQuery query = net::test_server::ParseQuery(url);
+  int index, max;
+  if (query.find(kIndexKey) == query.end() ||
+      query.find(kMaxKey) == query.end() ||
+      !base::StringToInt(query[kIndexKey][0], &index) ||
+      !base::StringToInt(query[kMaxKey][0], &max)) {
+    return nullptr;
+  }
+
+  if (index == max) {
+    response->set_code(net::HTTP_NO_CONTENT);
+    return response;
+  }
+
+  GURL::Replacements replacements;
+  std::string new_query =
+      base::StringPrintf("%s=%d&%s=%d", kIndexKey, index + 1, kMaxKey, max);
+  replacements.SetQuery(new_query.c_str(),
+                        url::Component(0, new_query.length()));
+  GURL redirected_url = url.ReplaceComponents(replacements);
+
+  response->AddCustomHeader("Location", redirected_url.spec());
+  response->set_code(net::HTTP_FOUND);
+  response->set_content_type("text/html");
+  response->set_content(base::StringPrintf(
+      "<html><head></head><body>Redirecting to %s</body></html>",
+      redirected_url.spec().c_str()));
+  return response;
+}
+
 // /set-cookie-and-no-content
 // Sets a cookies, and replies with HTTP code 204.
 std::unique_ptr<HttpResponse> SetCookieAndNoContent(
     const HttpRequest& request) {
-  const auto& url = request.GetURL();
+  const GURL& url = request.GetURL();
   if (url.path() != kSetCookieAndNoContent)
     return nullptr;
 
@@ -112,6 +154,8 @@
         base::BindRepeating(&SetCookieAndRedirect));
     embedded_test_server()->RegisterRequestHandler(
         base::BindRepeating(&SetCookieAndNoContent));
+    embedded_test_server()->RegisterRequestHandler(
+        base::BindRepeating(&ManyRedirects));
     embedded_test_server()->AddDefaultHandlers(
         base::FilePath("chrome/test/data"));
     host_resolver_ = std::make_unique<content::TestHostResolver>();
@@ -180,12 +224,10 @@
 
     DetachedResourceRequest::CreateAndStart(
         browser_context(), url, site_for_cookies, policy,
-        base::BindOnce(
-            [](base::OnceClosure closure, bool success) {
-              EXPECT_TRUE(success);
-              std::move(closure).Run();
-            },
-            request_completion_waiter.QuitClosure()));
+        base::BindLambdaForTesting([&](bool success) {
+          EXPECT_TRUE(success);
+          request_completion_waiter.Quit();
+        }));
     server_request_waiter.Run();
     EXPECT_EQ(expected_referrer, headers["referer"]);
     request_completion_waiter.Run();
@@ -214,15 +256,15 @@
   DetachedResourceRequest::CreateAndStart(
       browser_context(), url, site_for_cookies,
       content::Referrer::GetDefaultReferrerPolicy(),
-      base::BindOnce(
-          [](base::OnceClosure closure, bool success) {
-            EXPECT_TRUE(success);
-            std::move(closure).Run();
-          },
-          request_completion_waiter.QuitClosure()));
+      base::BindLambdaForTesting([&](bool success) {
+        EXPECT_TRUE(success);
+        request_completion_waiter.Quit();
+      }));
   server_request_waiter.Run();
   EXPECT_EQ(site_for_cookies.spec(), headers["referer"]);
   request_completion_waiter.Run();
+  histogram_tester.ExpectUniqueSample(
+      "CustomTabs.DetachedResourceRequest.RedirectsCount.Success", 0, 1);
   histogram_tester.ExpectTotalCount(
       "CustomTabs.DetachedResourceRequest.Duration.Success", 1);
 }
@@ -237,13 +279,13 @@
   DetachedResourceRequest::CreateAndStart(
       browser_context(), url, site_for_cookies,
       content::Referrer::GetDefaultReferrerPolicy(),
-      base::BindOnce(
-          [](base::OnceClosure closure, bool success) {
-            EXPECT_FALSE(success);
-            std::move(closure).Run();
-          },
-          request_waiter.QuitClosure()));
+      base::BindLambdaForTesting([&](bool success) {
+        EXPECT_FALSE(success);
+        request_waiter.Quit();
+      }));
   request_waiter.Run();
+  histogram_tester.ExpectUniqueSample(
+      "CustomTabs.DetachedResourceRequest.RedirectsCount.Failure", 0, 1);
   histogram_tester.ExpectTotalCount(
       "CustomTabs.DetachedResourceRequest.Duration.Failure", 1);
 }
@@ -339,12 +381,10 @@
   DetachedResourceRequest::CreateAndStart(
       browser_context(), url, site_for_cookies,
       content::Referrer::GetDefaultReferrerPolicy(),
-      base::BindOnce(
-          [](base::OnceClosure closure, bool success) {
-            EXPECT_TRUE(success);
-            std::move(closure).Run();
-          },
-          request_completion_waiter.QuitClosure()));
+      base::BindLambdaForTesting([&](bool success) {
+        EXPECT_TRUE(success);
+        request_completion_waiter.Quit();
+      }));
 
   request_completion_waiter.Run();
   cookie = content::GetCookies(browser_context(), url);
@@ -371,6 +411,7 @@
 }
 
 TEST_F(DetachedResourceRequestTest, MultipleOrigins) {
+  base::HistogramTester histogram_tester;
   base::RunLoop first_request_waiter;
   base::RunLoop second_request_waiter;
   base::RunLoop detached_request_waiter;
@@ -398,13 +439,12 @@
   cookie = content::GetCookies(browser_context(), redirected_origin);
   ASSERT_EQ("", cookie);
 
-  auto quit_closure = detached_request_waiter.QuitClosure();
   DetachedResourceRequest::CreateAndStart(
       browser_context(), url, site_for_cookies,
       content::Referrer::GetDefaultReferrerPolicy(),
-      base::BindLambdaForTesting([=](bool success) {
+      base::BindLambdaForTesting([&](bool success) {
         EXPECT_TRUE(success);
-        quit_closure.Run();
+        detached_request_waiter.Quit();
       }));
   first_request_waiter.Run();
   second_request_waiter.Run();
@@ -414,6 +454,52 @@
   ASSERT_EQ("acookie", cookie);
   cookie = content::GetCookies(browser_context(), redirected_origin);
   ASSERT_EQ(kCookieFromNoContent, cookie);
+  histogram_tester.ExpectUniqueSample(
+      "CustomTabs.DetachedResourceRequest.RedirectsCount.Success", 1, 1);
+}
+
+TEST_F(DetachedResourceRequestTest, ManyRedirects) {
+  base::HistogramTester histogram_tester;
+  base::RunLoop request_waiter;
+  ASSERT_TRUE(embedded_test_server()->Start());
+
+  auto relative_url = base::StringPrintf("%s?%s=%d&%s=%d", kManyRedirects,
+                                         kIndexKey, 1, kMaxKey, 10);
+  GURL url(embedded_test_server()->GetURL(relative_url));
+  GURL site_for_cookies(embedded_test_server()->base_url());
+
+  DetachedResourceRequest::CreateAndStart(
+      browser_context(), url, site_for_cookies,
+      content::Referrer::GetDefaultReferrerPolicy(),
+      base::BindLambdaForTesting([&](bool success) {
+        EXPECT_TRUE(success);
+        request_waiter.Quit();
+      }));
+  request_waiter.Run();
+  histogram_tester.ExpectUniqueSample(
+      "CustomTabs.DetachedResourceRequest.RedirectsCount.Success", 9, 1);
+}
+
+TEST_F(DetachedResourceRequestTest, TooManyRedirects) {
+  base::HistogramTester histogram_tester;
+  base::RunLoop request_waiter;
+  ASSERT_TRUE(embedded_test_server()->Start());
+
+  auto relative_url = base::StringPrintf("%s?%s=%d&%s=%d", kManyRedirects,
+                                         kIndexKey, 1, kMaxKey, 40);
+  GURL url(embedded_test_server()->GetURL(relative_url));
+  GURL site_for_cookies(embedded_test_server()->base_url());
+
+  DetachedResourceRequest::CreateAndStart(
+      browser_context(), url, site_for_cookies,
+      content::Referrer::GetDefaultReferrerPolicy(),
+      base::BindLambdaForTesting([&](bool success) {
+        EXPECT_FALSE(success);
+        request_waiter.Quit();
+      }));
+  request_waiter.Run();
+  histogram_tester.ExpectUniqueSample(
+      "CustomTabs.DetachedResourceRequest.RedirectsCount.Failure", 20, 1);
 }
 
 }  // namespace customtabs
diff --git a/chrome/browser/android/ntp/ntp_snippets_bridge.cc b/chrome/browser/android/ntp/ntp_snippets_bridge.cc
index ec6cd64..79fb6e2 100644
--- a/chrome/browser/android/ntp/ntp_snippets_bridge.cc
+++ b/chrome/browser/android/ntp/ntp_snippets_bridge.cc
@@ -306,9 +306,7 @@
     const JavaParamRef<jstring>& j_url,
     const JavaParamRef<jobject>& j_callback) {
   DCHECK(base::FeatureList::IsEnabled(
-             chrome::android::kContextualSuggestionsCarousel) ||
-         base::FeatureList::IsEnabled(
-             chrome::android::kContextualSuggestionsAboveArticles));
+      chrome::android::kContextualSuggestionsBottomSheet));
   GURL url(ConvertJavaStringToUTF8(env, j_url));
   contextual_content_suggestions_service_->FetchContextualSuggestions(
       url, base::Bind(&NTPSnippetsBridge::OnContextualSuggestionsFetched,
diff --git a/chrome/browser/browser_process_impl.cc b/chrome/browser/browser_process_impl.cc
index 696e3b2..1cb4066 100644
--- a/chrome/browser/browser_process_impl.cc
+++ b/chrome/browser/browser_process_impl.cc
@@ -423,7 +423,7 @@
   icon_manager_.reset();
 
 #if BUILDFLAG(ENABLE_WEBRTC)
-  // Must outlive the file thread.
+  // Must outlive the worker threads.
   webrtc_log_uploader_.reset();
 #endif
 
@@ -1102,7 +1102,7 @@
     }
     net_log_->StartWritingToFile(
         log_file, GetNetCaptureModeFromCommandLine(command_line),
-        command_line.GetCommandLineString(), chrome::GetChannelString());
+        command_line.GetCommandLineString(), chrome::GetChannelName());
   }
 
   // Must be created before the IOThread.
@@ -1167,15 +1167,8 @@
   }
 
 #if BUILDFLAG(ENABLE_WEBRTC)
-  // WebRtcEventLogManager is instaniated before anything that needs it, then
-  // lives "forever"; it and its sub-objects are allowed to leak when Chrome
-  // shuts down. This allows us to be confident that messages posted to
-  // WebRtcEventLogManager's internal task queue with base::Unretained(this),
-  // are never referencing a dangling pointer, and that sub-objects are
-  // similarly always alive.
-  WebRtcEventLogManager* const webrtc_event_log_manager =
-      WebRtcEventLogManager::CreateSingletonInstance();
-  content::WebRtcEventLogger::Set(webrtc_event_log_manager);
+  DCHECK(!webrtc_event_log_manager_);
+  webrtc_event_log_manager_ = WebRtcEventLogManager::CreateSingletonInstance();
 #endif
 }
 
diff --git a/chrome/browser/browser_process_impl.h b/chrome/browser/browser_process_impl.h
index 7b54688e..4d72c39 100644
--- a/chrome/browser/browser_process_impl.h
+++ b/chrome/browser/browser_process_impl.h
@@ -44,6 +44,10 @@
 class PluginsResourceService;
 #endif
 
+#if BUILDFLAG(ENABLE_WEBRTC)
+class WebRtcEventLogManager;
+#endif
+
 namespace base {
 class CommandLine;
 class SequencedTaskRunner;
@@ -344,6 +348,12 @@
 #if BUILDFLAG(ENABLE_WEBRTC)
   // Lazily initialized.
   std::unique_ptr<WebRtcLogUploader> webrtc_log_uploader_;
+
+  // WebRtcEventLogManager is a singleton which is instaniated before anything
+  // that needs it, and lives until ~BrowserProcessImpl(). This allows it to
+  // safely post base::Unretained(this) references to an internally owned task
+  // queue, since after ~BrowserProcessImpl(), those tasks would no longer run.
+  std::unique_ptr<WebRtcEventLogManager> webrtc_event_log_manager_;
 #endif
 
   std::unique_ptr<network_time::NetworkTimeTracker> network_time_tracker_;
diff --git a/chrome/browser/chrome_browser_main.cc b/chrome/browser/chrome_browser_main.cc
index 6ec57d73..3ff7098 100644
--- a/chrome/browser/chrome_browser_main.cc
+++ b/chrome/browser/chrome_browser_main.cc
@@ -1344,7 +1344,7 @@
 
 #if defined(OS_LINUX) || defined(OS_OPENBSD)
   // Set the product channel for crash reports.
-  breakpad::SetChannelCrashKey(chrome::GetChannelString());
+  breakpad::SetChannelCrashKey(chrome::GetChannelName());
 #endif  // defined(OS_LINUX) || defined(OS_OPENBSD)
 
 #if defined(OS_MACOSX)
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index 4aa708e..7392684 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -597,6 +597,49 @@
   return false;
 }
 
+#if !defined(OS_ANDROID)
+// Check if the current url is whitelisted based on a list of whitelisted urls.
+bool IsURLWhitelisted(const GURL& current_url,
+                      const base::Value::ListStorage& whitelisted_urls) {
+  // Only check on HTTP and HTTPS pages.
+  if (!current_url.SchemeIsHTTPOrHTTPS())
+    return false;
+
+  for (auto const& value : whitelisted_urls) {
+    ContentSettingsPattern pattern =
+        ContentSettingsPattern::FromString(value.GetString());
+    if (pattern == ContentSettingsPattern::Wildcard() || !pattern.IsValid())
+      continue;
+    if (pattern.Matches(current_url))
+      return true;
+  }
+
+  return false;
+}
+
+// Check if autoplay is allowed by policy configuration.
+bool IsAutoplayAllowedByPolicy(content::WebContents* contents,
+                               PrefService* prefs) {
+  DCHECK(prefs);
+
+  // Check if we have globally allowed autoplay by policy.
+  if (prefs->GetBoolean(prefs::kAutoplayAllowed) &&
+      prefs->IsManagedPreference(prefs::kAutoplayAllowed)) {
+    return true;
+  }
+
+  if (!contents)
+    return false;
+
+  // Check if the current URL matches a URL pattern on the whitelist.
+  const base::ListValue* autoplay_whitelist =
+      prefs->GetList(prefs::kAutoplayWhitelist);
+  return autoplay_whitelist &&
+         prefs->IsManagedPreference(prefs::kAutoplayWhitelist) &&
+         IsURLWhitelisted(contents->GetURL(), autoplay_whitelist->GetList());
+}
+#endif
+
 #if defined(OS_POSIX) && !defined(OS_ANDROID) && !defined(OS_MACOSX)
 breakpad::CrashHandlerHostLinux* CreateCrashHandlerHost(
     const std::string& process_type) {
@@ -942,6 +985,7 @@
   registry->RegisterBooleanPref(prefs::kSitePerProcess, false);
 #if !defined(OS_ANDROID)
   registry->RegisterBooleanPref(prefs::kAutoplayAllowed, false);
+  registry->RegisterListPref(prefs::kAutoplayWhitelist);
 #endif
 }
 
@@ -1707,7 +1751,7 @@
     if (client_info)
       switch_value = client_info->client_id;
     switch_value.push_back(',');
-    switch_value.append(chrome::GetChannelString());
+    switch_value.append(chrome::GetChannelName());
     command_line->AppendSwitchASCII(switches::kEnableCrashReporter,
                                     switch_value);
   }
@@ -2810,8 +2854,9 @@
   }
 
 #if !defined(OS_ANDROID)
-  if (prefs->GetBoolean(prefs::kAutoplayAllowed) &&
-      prefs->IsManagedPreference(prefs::kAutoplayAllowed)) {
+  // If autoplay is allowed by policy then update the autoplay policy in web
+  // preferences.
+  if (IsAutoplayAllowedByPolicy(contents, prefs)) {
     web_prefs->autoplay_policy =
         content::AutoplayPolicy::kNoUserGestureRequired;
   }
diff --git a/chrome/browser/chromeos/app_mode/kiosk_profile_loader.cc b/chrome/browser/chromeos/app_mode/kiosk_profile_loader.cc
index 4b9b3a1..1eb23d9f 100644
--- a/chrome/browser/chromeos/app_mode/kiosk_profile_loader.cc
+++ b/chrome/browser/chromeos/app_mode/kiosk_profile_loader.cc
@@ -109,14 +109,13 @@
       return;
     }
 
-    if (!is_mounted.value())
-      SYSLOG(ERROR) << "Cryptohome is mounted before launching kiosk app.";
-
     // Proceed only when cryptohome is not mounded or running on dev box.
-    if (!is_mounted.value() || !base::SysInfo::IsRunningOnChromeOS())
+    if (!is_mounted.value() || !base::SysInfo::IsRunningOnChromeOS()) {
       ReportCheckResult(KioskAppLaunchError::NONE);
-    else
+    } else {
+      SYSLOG(ERROR) << "Cryptohome is mounted before launching kiosk app.";
       ReportCheckResult(KioskAppLaunchError::ALREADY_MOUNTED);
+    }
   }
 
   void ReportCheckResult(KioskAppLaunchError::Error error) {
diff --git a/chrome/browser/component_updater/chrome_component_updater_configurator.cc b/chrome/browser/component_updater/chrome_component_updater_configurator.cc
index 8c53ba3e..99dd05f6 100644
--- a/chrome/browser/component_updater/chrome_component_updater_configurator.cc
+++ b/chrome/browser/component_updater/chrome_component_updater_configurator.cc
@@ -121,7 +121,7 @@
 }
 
 std::string ChromeConfigurator::GetChannel() const {
-  return chrome::GetChannelString();
+  return chrome::GetChannelName();
 }
 
 std::string ChromeConfigurator::GetBrand() const {
diff --git a/chrome/browser/diagnostics/recon_diagnostics.cc b/chrome/browser/diagnostics/recon_diagnostics.cc
index 352db7d7..f65b012a 100644
--- a/chrome/browser/diagnostics/recon_diagnostics.cc
+++ b/chrome/browser/diagnostics/recon_diagnostics.cc
@@ -297,7 +297,7 @@
       RecordFailure(DIAG_RECON_EMPTY_VERSION, "Empty Version");
       return true;
     }
-    std::string version_modifier = chrome::GetChannelString();
+    std::string version_modifier = chrome::GetChannelName();
     if (!version_modifier.empty())
       current_version += " " + version_modifier;
 #if defined(GOOGLE_CHROME_BUILD)
diff --git a/chrome/browser/extensions/updater/chrome_update_client_config.cc b/chrome/browser/extensions/updater/chrome_update_client_config.cc
index 3ec4c12..c960c3d 100644
--- a/chrome/browser/extensions/updater/chrome_update_client_config.cc
+++ b/chrome/browser/extensions/updater/chrome_update_client_config.cc
@@ -126,7 +126,7 @@
 }
 
 std::string ChromeUpdateClientConfig::GetChannel() const {
-  return chrome::GetChannelString();
+  return chrome::GetChannelName();
 }
 
 std::string ChromeUpdateClientConfig::GetBrand() const {
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index 8eacebd..3db68c5 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -151,17 +151,10 @@
     "Renders a border around composited Render Layers to help debug and study "
     "layer compositing.";
 
-const char kContextualSuggestionsAboveArticlesName[] =
-    "Enable Contextual Suggestions Above Articles";
-const char kContextualSuggestionsAboveArticlesDescription[] =
-    "If enabled, shows contextual suggestions in a linear list above "
-    "article suggestions.";
-
-const char kContextualSuggestionsCarouselName[] =
-    "Enable Contextual Suggestions Carousel";
-const char kContextualSuggestionsCarouselDescription[] =
-    "If enabled, shows contextual suggestions in a horizontal carousel in "
-    "bottom sheet content.";
+const char kContextualSuggestionsBottomSheetName[] =
+    "Enable Contextual Suggestions Bottom Sheet";
+const char kContextualSuggestionsBottomSheetDescription[] =
+    "If enabled, shows contextual suggestions in the bottom sheet.";
 
 const char kCreditCardAssistName[] = "Credit Card Assisted Filling";
 const char kCreditCardAssistDescription[] =
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index 1320c28..6fe7b6c4 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -122,11 +122,8 @@
 extern const char kCompositedLayerBordersName[];
 extern const char kCompositedLayerBordersDescription[];
 
-extern const char kContextualSuggestionsAboveArticlesName[];
-extern const char kContextualSuggestionsAboveArticlesDescription[];
-
-extern const char kContextualSuggestionsCarouselName[];
-extern const char kContextualSuggestionsCarouselDescription[];
+extern const char kContextualSuggestionsBottomSheetName[];
+extern const char kContextualSuggestionsBottomSheetDescription[];
 
 extern const char kCreditCardAssistName[];
 extern const char kCreditCardAssistDescription[];
diff --git a/chrome/browser/google/google_brand.cc b/chrome/browser/google/google_brand.cc
index 33cf760f..a150ab5 100644
--- a/chrome/browser/google/google_brand.cc
+++ b/chrome/browser/google/google_brand.cc
@@ -8,6 +8,8 @@
 #include <string>
 
 #include "base/macros.h"
+#include "base/no_destructor.h"
+#include "base/optional.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "build/build_config.h"
@@ -41,11 +43,20 @@
     return true;
   }
 
-  base::string16 brand16;
-  bool ret = GoogleUpdateSettings::GetBrand(&brand16);
-  if (ret)
-    brand->assign(base::UTF16ToASCII(brand16));
-  return ret;
+  // Cache brand code value, since it is queried a lot and registry queries are
+  // slow enough to actually affect top-level metrics like
+  // Omnibox.CharTypedToRepaintLatency.
+  static const base::NoDestructor<base::Optional<std::string>> brand_code(
+      []() -> base::Optional<std::string> {
+        base::string16 brand16;
+        if (!GoogleUpdateSettings::GetBrand(&brand16))
+          return base::nullopt;
+        return base::UTF16ToASCII(brand16);
+      }());
+  if (!brand_code->has_value())
+    return false;
+  brand->assign(**brand_code);
+  return true;
 }
 
 bool GetReactivationBrand(std::string* brand) {
diff --git a/chrome/browser/google/google_brand.h b/chrome/browser/google/google_brand.h
index 3e657dbc..6b37a80 100644
--- a/chrome/browser/google/google_brand.h
+++ b/chrome/browser/google/google_brand.h
@@ -18,6 +18,7 @@
 
 // Returns in |brand| the brand code or distribution tag that has been
 // assigned to a partner. Returns false if the information is not available.
+// TODO(asvitkine): These APIs should return base::Optional<std::string>.
 bool GetBrand(std::string* brand);
 
 // Returns in |brand| the reactivation brand code or distribution tag
diff --git a/chrome/browser/mac/keystone_glue.h b/chrome/browser/mac/keystone_glue.h
index e161790..830037c6 100644
--- a/chrome/browser/mac/keystone_glue.h
+++ b/chrome/browser/mac/keystone_glue.h
@@ -51,17 +51,6 @@
 extern NSString* const kAutoupdateStatusVersion;
 extern NSString* const kAutoupdateStatusErrorMessages;
 
-namespace {
-
-enum BrandFileType {
-  kBrandFileTypeNotDetermined = 0,
-  kBrandFileTypeNone,
-  kBrandFileTypeUser,
-  kBrandFileTypeSystem,
-};
-
-} // namespace
-
 // KeystoneGlue is an adapter around the KSRegistration class, allowing it to
 // be used without linking directly against its containing KeystoneRegistration
 // framework.  This is used in an environment where most builds (such as
@@ -84,8 +73,8 @@
   NSString* appPath_;
   NSString* url_;
   NSString* version_;
-  NSString* channel_;  // Logically: Dev, Beta, or Stable.
-  BrandFileType brandFileType_;
+  std::string channel_;  // Logically: dev, beta, or stable.
+  NSString* brandFile_;  // Cached location of the brand file.
 
   // And the Keystone registration itself, with the active timer
   KSRegistration* registration_;  // strong
diff --git a/chrome/browser/mac/keystone_glue.mm b/chrome/browser/mac/keystone_glue.mm
index 3e93e70..6d5a0111 100644
--- a/chrome/browser/mac/keystone_glue.mm
+++ b/chrome/browser/mac/keystone_glue.mm
@@ -40,9 +40,11 @@
 // updates to Chrome.)
 
 #if defined(GOOGLE_CHROME_BUILD)
-#define kBrandFileName @"Google Chrome Brand.plist";
+#define kStableBrandFileName @"Google Chrome Brand.plist"
+#define kCanaryBrandFileName @"Google Chrome Canary Brand.plist"
 #elif defined(CHROMIUM_BUILD)
-#define kBrandFileName @"Chromium Brand.plist";
+#define kStableBrandFileName @"Chromium Brand.plist"
+#define kCanaryBrandFileName @"Chromium Canary Brand.plist"
 #else
 #error Unknown branding
 #endif
@@ -50,14 +52,23 @@
 // These directories are hardcoded in Keystone promotion preflight and the
 // Keystone install script, so NSSearchPathForDirectoriesInDomains isn't used
 // since the scripts couldn't use anything like that.
-NSString* kBrandUserFile = @"~/Library/Google/" kBrandFileName;
-NSString* kBrandSystemFile = @"/Library/Google/" kBrandFileName;
+NSString* kStableBrandUserFile = @"~/Library/Google/" kStableBrandFileName;
+NSString* kStableBrandSystemFile = @"/Library/Google/" kStableBrandFileName;
+NSString* kCanaryBrandUserFile = @"~/Library/Google/" kCanaryBrandFileName;
+NSString* kCanaryBrandSystemFile = @"/Library/Google/" kCanaryBrandFileName;
 
-NSString* UserBrandFilePath() {
-  return [kBrandUserFile stringByStandardizingPath];
+NSString* UserBrandFilePath(version_info::Channel channel) {
+  NSString* file = (channel == version_info::Channel::CANARY)
+                       ? kCanaryBrandUserFile
+                       : kStableBrandUserFile;
+  return [file stringByStandardizingPath];
 }
-NSString* SystemBrandFilePath() {
-  return [kBrandSystemFile stringByStandardizingPath];
+
+NSString* SystemBrandFilePath(version_info::Channel channel) {
+  NSString* file = (channel == version_info::Channel::CANARY)
+                       ? kCanaryBrandSystemFile
+                       : kStableBrandSystemFile;
+  return [file stringByStandardizingPath];
 }
 
 // Adaptor for scheduling an Objective-C method call in TaskScheduler.
@@ -275,7 +286,6 @@
   [appPath_ release];
   [url_ release];
   [version_ release];
-  [channel_ release];
   [registration_ release];
   [[NSNotificationCenter defaultCenter] removeObserver:self];
   [super dealloc];
@@ -311,130 +321,118 @@
     return;
   }
 
-  NSString* channel = base::mac::ObjCCast<NSString>(
-      [infoDictionary objectForKey:kChannelKey]);
+  std::string channel = chrome::GetChannelName();
   // The stable channel has no tag.  If updating to stable, remove the
   // dev and beta tags since we've been "promoted".
-  if (channel == nil)
-    channel = ksr::KSRegistrationRemoveExistingTag;
+  version_info::Channel channelType = chrome::GetChannelByName(channel);
+  if (channelType == version_info::Channel::STABLE) {
+    channel = ksr::KSRegistrationRemoveExistingTag.UTF8String;
+#if defined(GOOGLE_CHROME_BUILD)
+    DCHECK(chrome::GetChannelByName(channel) == version_info::Channel::STABLE)
+        << "-channel name modification has side effect";
+#endif
+  }
 
   productID_ = [productID retain];
   appPath_ = [appPath retain];
   url_ = [url retain];
   version_ = [version retain];
-  channel_ = [channel retain];
+  channel_ = channel;
 }
 
 - (NSString*)brandFilePath {
   DCHECK(version_ != nil) << "-loadParameters must be called first";
 
-  if (brandFileType_ == kBrandFileTypeNotDetermined) {
+  if (brandFile_)
+    return brandFile_;
 
-    NSFileManager* fm = [NSFileManager defaultManager];
-    NSString* userBrandFile = UserBrandFilePath();
-    NSString* systemBrandFile = SystemBrandFilePath();
+  NSFileManager* fm = [NSFileManager defaultManager];
+  version_info::Channel channel = chrome::GetChannelByName(channel_);
+  NSString* userBrandFile = UserBrandFilePath(channel);
+  NSString* systemBrandFile = SystemBrandFilePath(channel);
 
-    // Default to none.
-    brandFileType_ = kBrandFileTypeNone;
+  // Default to none.
+  brandFile_ = @"";
 
-    // Only the stable channel has a brand code.
-    version_info::Channel channel = chrome::GetChannel();
+  // Only the stable and canary channel can have independent brand codes.
 
-    if (channel == version_info::Channel::DEV ||
-        channel == version_info::Channel::BETA) {
+  if (channel == version_info::Channel::DEV ||
+      channel == version_info::Channel::BETA) {
+    // If on the dev or beta channel, this installation may have replaced
+    // an older system-level installation. Check for a user brand file and
+    // nuke it if present. Don't try to remove the system brand file, there
+    // wouldn't be any permission to do so.
+    //
+    // Don't do this on the canary channel. The canary can run side-by-side
+    // with another Google Chrome installation whose brand code, if any,
+    // should remain intact.
 
-      // If on the dev or beta channel, this installation may have replaced
-      // an older system-level installation. Check for a user brand file and
-      // nuke it if present. Don't try to remove the system brand file, there
-      // wouldn't be any permission to do so.
-      //
-      // Don't do this on the canary channel. The canary can run side-by-side
-      // with another Google Chrome installation whose brand code, if any,
-      // should remain intact.
+    if ([fm fileExistsAtPath:userBrandFile]) {
+      [fm removeItemAtPath:userBrandFile error:NULL];
+    }
 
+  } else if (channel == version_info::Channel::STABLE ||
+             channel == version_info::Channel::CANARY) {
+    // Stable and Canary use different app ids, so they can both have brand
+    // codes. Even if Canary does not actively use brand codes, we want to
+    // exercise the same logic, so that we can detect perf regressions early.
+
+    // If there is a system brand file, use it.
+    if ([fm fileExistsAtPath:systemBrandFile]) {
+      // System
+
+      // Use the system file that is there.
+      brandFile_ = systemBrandFile;
+
+      // Clean up any old user level file.
       if ([fm fileExistsAtPath:userBrandFile]) {
         [fm removeItemAtPath:userBrandFile error:NULL];
       }
 
-    } else if (channel == version_info::Channel::STABLE) {
+    } else {
+      // User
 
-      // If there is a system brand file, use it.
-      if ([fm fileExistsAtPath:systemBrandFile]) {
-        // System
+      NSDictionary* infoDictionary = [self infoDictionary];
+      NSString* appBundleBrandID = base::mac::ObjCCast<NSString>(
+          [infoDictionary objectForKey:kBrandKey]);
 
-        // Use the system file that is there.
-        brandFileType_ = kBrandFileTypeSystem;
+      NSString* storedBrandID = nil;
+      if ([fm fileExistsAtPath:userBrandFile]) {
+        NSDictionary* storedBrandDict =
+            [NSDictionary dictionaryWithContentsOfFile:userBrandFile];
+        storedBrandID = base::mac::ObjCCast<NSString>(
+            [storedBrandDict objectForKey:kBrandKey]);
+      }
 
-        // Clean up any old user level file.
-        if ([fm fileExistsAtPath:userBrandFile]) {
-          [fm removeItemAtPath:userBrandFile error:NULL];
-        }
-
-      } else {
-        // User
-
-        NSDictionary* infoDictionary = [self infoDictionary];
-        NSString* appBundleBrandID = base::mac::ObjCCast<NSString>(
-            [infoDictionary objectForKey:kBrandKey]);
-
-        NSString* storedBrandID = nil;
-        if ([fm fileExistsAtPath:userBrandFile]) {
-          NSDictionary* storedBrandDict =
-              [NSDictionary dictionaryWithContentsOfFile:userBrandFile];
-          storedBrandID = base::mac::ObjCCast<NSString>(
-              [storedBrandDict objectForKey:kBrandKey]);
-        }
-
-        if ((appBundleBrandID != nil) &&
-            (![storedBrandID isEqualTo:appBundleBrandID])) {
-          // App and store don't match, update store and use it.
-          NSDictionary* storedBrandDict =
-              [NSDictionary dictionaryWithObject:appBundleBrandID
-                                          forKey:kBrandKey];
-          // If Keystone hasn't been installed yet, the location the brand file
-          // is written to won't exist, so manually create the directory.
-          NSString *userBrandFileDirectory =
-              [userBrandFile stringByDeletingLastPathComponent];
-          if (![fm fileExistsAtPath:userBrandFileDirectory]) {
-            if (![fm createDirectoryAtPath:userBrandFileDirectory
-               withIntermediateDirectories:YES
-                                attributes:nil
-                                     error:NULL]) {
-              LOG(ERROR) << "Failed to create the directory for the brand file";
-            }
+      if ((appBundleBrandID != nil) &&
+          (![storedBrandID isEqualTo:appBundleBrandID])) {
+        // App and store don't match, update store and use it.
+        NSDictionary* storedBrandDict =
+            [NSDictionary dictionaryWithObject:appBundleBrandID
+                                        forKey:kBrandKey];
+        // If Keystone hasn't been installed yet, the location the brand file
+        // is written to won't exist, so manually create the directory.
+        NSString* userBrandFileDirectory =
+            [userBrandFile stringByDeletingLastPathComponent];
+        if (![fm fileExistsAtPath:userBrandFileDirectory]) {
+          if (![fm createDirectoryAtPath:userBrandFileDirectory
+                  withIntermediateDirectories:YES
+                                   attributes:nil
+                                        error:NULL]) {
+            LOG(ERROR) << "Failed to create the directory for the brand file";
           }
-          if ([storedBrandDict writeToFile:userBrandFile atomically:YES]) {
-            brandFileType_ = kBrandFileTypeUser;
-          }
-        } else if (storedBrandID) {
-          // Had stored brand, use it.
-          brandFileType_ = kBrandFileTypeUser;
         }
+        if ([storedBrandDict writeToFile:userBrandFile atomically:YES]) {
+          brandFile_ = userBrandFile;
+        }
+      } else if (storedBrandID) {
+        // Had stored brand, use it.
+        brandFile_ = userBrandFile;
       }
     }
-
   }
 
-  NSString* result = nil;
-  switch (brandFileType_) {
-    case kBrandFileTypeUser:
-      result = UserBrandFilePath();
-      break;
-
-    case kBrandFileTypeSystem:
-      result = SystemBrandFilePath();
-      break;
-
-    case kBrandFileTypeNotDetermined:
-      NOTIMPLEMENTED();
-      FALLTHROUGH;
-    case kBrandFileTypeNone:
-      // Clear the value.
-      result = @"";
-      break;
-
-  }
-  return result;
+  return brandFile_;
 }
 
 - (BOOL)loadKeystoneRegistration {
@@ -483,9 +481,9 @@
 
   // Note that channel_ is permitted to be an empty string, but it must not be
   // nil.
-  DCHECK(channel_);
   NSString* tagSuffix = [self tagSuffix];
-  NSString* tagValue = [channel_ stringByAppendingString:tagSuffix];
+  NSString* tagValue =
+      [NSString stringWithFormat:@"%s%@", channel_.c_str(), tagSuffix];
   NSString* tagKey = [kChannelKey stringByAppendingString:tagSuffix];
 
   return [NSDictionary dictionaryWithObjectsAndKeys:
@@ -957,14 +955,20 @@
           pathForResource:@"keystone_promote_preflight"
                    ofType:@"sh"];
   const char* preflightPathC = [preflightPath fileSystemRepresentation];
-  const char* userBrandFile = NULL;
-  const char* systemBrandFile = NULL;
-  if (brandFileType_ == kBrandFileTypeUser) {
+
+  // This is typically a once per machine operation, so it is not worth caching
+  // the type of brand file (user vs system). Figure it out here:
+  version_info::Channel channel = chrome::GetChannelByName(channel_);
+  NSString* userBrandFile = UserBrandFilePath(channel);
+  NSString* systemBrandFile = SystemBrandFilePath(channel);
+  const char* arguments[] = {NULL, NULL, NULL};
+  BOOL userBrand = NO;
+  if ([brandFile_ isEqualToString:userBrandFile]) {
     // Running with user level brand file, promote to the system level.
-    userBrandFile = [UserBrandFilePath() fileSystemRepresentation];
-    systemBrandFile = [SystemBrandFilePath() fileSystemRepresentation];
+    userBrand = YES;
+    arguments[0] = userBrandFile.UTF8String;
+    arguments[1] = systemBrandFile.UTF8String;
   }
-  const char* arguments[] = {userBrandFile, systemBrandFile, NULL};
 
   int exit_status;
   OSStatus status = base::mac::ExecuteWithPrivilegesAndWait(
@@ -1006,11 +1010,11 @@
 
   // If the brand file is user level, update parameters to point to the new
   // system level file during promotion.
-  if (brandFileType_ == kBrandFileTypeUser) {
+  if (userBrand) {
     NSMutableDictionary* temp_parameters =
         [[parameters mutableCopy] autorelease];
-    [temp_parameters setObject:SystemBrandFilePath()
-                        forKey:ksr::KSRegistrationBrandPathKey];
+    temp_parameters[ksr::KSRegistrationBrandPathKey] = systemBrandFile;
+    brandFile_ = systemBrandFile;
     parameters = temp_parameters;
   }
 
diff --git a/chrome/browser/media/webrtc/webrtc_event_log_manager.cc b/chrome/browser/media/webrtc/webrtc_event_log_manager.cc
index fea93c4..ef7555d 100644
--- a/chrome/browser/media/webrtc/webrtc_event_log_manager.cc
+++ b/chrome/browser/media/webrtc/webrtc_event_log_manager.cc
@@ -75,13 +75,16 @@
   return GetBrowserContextId(browser_context);
 }
 
-WebRtcEventLogManager* WebRtcEventLogManager::CreateSingletonInstance() {
+std::unique_ptr<WebRtcEventLogManager>
+WebRtcEventLogManager::CreateSingletonInstance() {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
   DCHECK(!g_webrtc_event_log_manager);
   g_webrtc_event_log_manager = new WebRtcEventLogManager;
-  return g_webrtc_event_log_manager;
+  return base::WrapUnique<WebRtcEventLogManager>(g_webrtc_event_log_manager);
 }
 
 WebRtcEventLogManager* WebRtcEventLogManager::GetInstance() {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
   return g_webrtc_event_log_manager;
 }
 
@@ -122,7 +125,8 @@
   DCHECK(browser_context);
   CHECK(!browser_context->IsOffTheRecord());
 
-  // The object outlives the task queue - base::Unretained(this) is safe.
+  // The object is destroyed by ~BrowserProcessImpl(), so base::Unretained(this)
+  // will not be dereferenced after destruction.
   task_runner_->PostTask(
       FROM_HERE,
       base::BindOnce(&WebRtcEventLogManager::EnableForBrowserContextInternal,
@@ -137,7 +141,8 @@
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   DCHECK(browser_context);
 
-  // The object outlives the task queue - base::Unretained(this) is safe.
+  // The object is destroyed by ~BrowserProcessImpl(), so base::Unretained(this)
+  // will not be dereferenced after destruction.
   task_runner_->PostTask(
       FROM_HERE,
       base::BindOnce(&WebRtcEventLogManager::DisableForBrowserContextInternal,
@@ -171,7 +176,8 @@
   const auto browser_context_id = GetBrowserContextId(rph->GetBrowserContext());
   DCHECK_NE(browser_context_id, kNullBrowserContextId);
 
-  // The object outlives the task queue - base::Unretained(this) is safe.
+  // The object is destroyed by ~BrowserProcessImpl(), so base::Unretained(this)
+  // will not be dereferenced after destruction.
   task_runner_->PostTask(
       FROM_HERE,
       base::BindOnce(
@@ -195,7 +201,8 @@
     return;
   }
 
-  // The object outlives the task queue - base::Unretained(this) is safe.
+  // The object is destroyed by ~BrowserProcessImpl(), so base::Unretained(this)
+  // will not be dereferenced after destruction.
   task_runner_->PostTask(
       FROM_HERE,
       base::BindOnce(
@@ -225,7 +232,8 @@
     base::OnceCallback<void(bool)> reply) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   DCHECK(!base_path.empty());
-  // The object outlives the task queue - base::Unretained(this) is safe.
+  // The object is destroyed by ~BrowserProcessImpl(), so base::Unretained(this)
+  // will not be dereferenced after destruction.
   task_runner_->PostTask(
       FROM_HERE,
       base::BindOnce(&WebRtcEventLogManager::EnableLocalLoggingInternal,
@@ -236,7 +244,8 @@
 void WebRtcEventLogManager::DisableLocalLogging(
     base::OnceCallback<void(bool)> reply) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  // The object outlives the task queue - base::Unretained(this) is safe.
+  // The object is destroyed by ~BrowserProcessImpl(), so base::Unretained(this)
+  // will not be dereferenced after destruction.
   task_runner_->PostTask(
       FROM_HERE,
       base::BindOnce(&WebRtcEventLogManager::DisableLocalLoggingInternal,
@@ -262,7 +271,8 @@
 
   const bool remote_logging_allowed = !browser_context->IsOffTheRecord();
 
-  // The object outlives the task queue - base::Unretained(this) is safe.
+  // The object is destroyed by ~BrowserProcessImpl(), so base::Unretained(this)
+  // will not be dereferenced after destruction.
   task_runner_->PostTask(
       FROM_HERE,
       base::BindOnce(
@@ -290,7 +300,8 @@
   const auto browser_context_id = GetBrowserContextId(browser_context);
   DCHECK_NE(browser_context_id, kNullBrowserContextId);
 
-  // The object outlives the task queue - base::Unretained(this) is safe.
+  // The object is destroyed by ~BrowserProcessImpl(), so base::Unretained(this)
+  // will not be dereferenced after destruction.
   task_runner_->PostTask(
       FROM_HERE,
       base::BindOnce(&WebRtcEventLogManager::StartRemoteLoggingInternal,
@@ -304,7 +315,8 @@
     WebRtcLocalEventLogsObserver* observer,
     base::OnceClosure reply) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  // The object outlives the task queue - base::Unretained(this) is safe.
+  // The object is destroyed by ~BrowserProcessImpl(), so base::Unretained(this)
+  // will not be dereferenced after destruction.
   task_runner_->PostTask(
       FROM_HERE,
       base::BindOnce(&WebRtcEventLogManager::SetLocalLogsObserverInternal,
@@ -315,7 +327,8 @@
     WebRtcRemoteEventLogsObserver* observer,
     base::OnceClosure reply) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  // The object outlives the task queue - base::Unretained(this) is safe.
+  // The object is destroyed by ~BrowserProcessImpl(), so base::Unretained(this)
+  // will not be dereferenced after destruction.
   task_runner_->PostTask(
       FROM_HERE,
       base::BindOnce(&WebRtcEventLogManager::SetRemoteLogsObserverInternal,
@@ -347,7 +360,8 @@
   host->RemoveObserver(this);
   observed_render_process_hosts_.erase(host);
 
-  // The object outlives the task queue - base::Unretained(this) is safe.
+  // The object is destroyed by ~BrowserProcessImpl(), so base::Unretained(this)
+  // will not be dereferenced after destruction.
   task_runner_->PostTask(
       FROM_HERE,
       base::BindOnce(&WebRtcEventLogManager::RenderProcessExitedInternal,
@@ -639,7 +653,8 @@
     }
   };
 
-  // The object outlives the task queue - base::Unretained(this) is safe.
+  // The object is destroyed by ~BrowserProcessImpl(), so base::Unretained(this)
+  // will not be dereferenced after destruction.
   task_runner_->PostTask(FROM_HERE, base::BindOnce(task, base::Unretained(this),
                                                    clock, std::move(reply)));
 }
@@ -658,7 +673,8 @@
     }
   };
 
-  // The object outlives the task queue - base::Unretained(this) is safe.
+  // The object is destroyed by ~BrowserProcessImpl(), so base::Unretained(this)
+  // will not be dereferenced after destruction.
   task_runner_->PostTask(
       FROM_HERE, base::BindOnce(task, base::Unretained(this),
                                 std::move(pc_tracker_proxy), std::move(reply)));
@@ -683,7 +699,8 @@
         }
       };
 
-  // The object outlives the task queue - base::Unretained(this) is safe.
+  // The object is destroyed by ~BrowserProcessImpl(), so base::Unretained(this)
+  // will not be dereferenced after destruction.
   task_runner_->PostTask(
       FROM_HERE, base::BindOnce(task, base::Unretained(this),
                                 std::move(uploader_factory), std::move(reply)));
diff --git a/chrome/browser/media/webrtc/webrtc_event_log_manager.h b/chrome/browser/media/webrtc/webrtc_event_log_manager.h
index 77b46e0..9123f7d 100644
--- a/chrome/browser/media/webrtc/webrtc_event_log_manager.h
+++ b/chrome/browser/media/webrtc/webrtc_event_log_manager.h
@@ -27,13 +27,15 @@
 };
 
 // This is a singleton class running in the browser UI thread (ownership of
-// the only instance lies in BrowserContext).  It is in charge of writing WebRTC
+// the only instance lies in BrowserContext). It is in charge of writing WebRTC
 // event logs to temporary files, then uploading those files to remote servers,
 // as well as of writing the logs to files which were manually indicated by the
 // user from the WebRTCIntenals. (A log may simulatenously be written to both,
 // either, or none.)
-// This needs to be final, so that posting |base::Unretained(this)| to the
-// internal task runner would not be a problem during destruction.
+// The only instance of this class is owned by BrowserProcessImpl. It is
+// destroyed from ~BrowserProcessImpl(), at which point any tasks posted to the
+// internal SequencedTaskRunner, or coming from another thread, would no longer
+// execute.
 class WebRtcEventLogManager final : public content::RenderProcessHostObserver,
                                     public content::WebRtcEventLogger,
                                     public WebRtcLocalEventLogsObserver,
@@ -67,11 +69,14 @@
   static BrowserContextId GetBrowserContextId(int render_process_id);
 
   // Ensures that no previous instantiation of the class was performed, then
-  // instantiates the class and returns the object. Subsequent calls to
-  // GetInstance() will return this object.
-  static WebRtcEventLogManager* CreateSingletonInstance();
+  // instantiates the class and returns the object (ownership is transfered to
+  // the caller). Subsequent calls to GetInstance() will return this object,
+  // until it is destructed, at which pointer nullptr will be returned by
+  // subsequent calls.
+  static std::unique_ptr<WebRtcEventLogManager> CreateSingletonInstance();
 
-  // Returns the object previously constructed using CreateSingletonInstance().
+  // Returns the object previously constructed using CreateSingletonInstance(),
+  // if it was constructed and was not yet destroyed; nullptr otherwise.
   static WebRtcEventLogManager* GetInstance();
 
   ~WebRtcEventLogManager() override;
diff --git a/chrome/browser/media/webrtc/webrtc_event_log_manager_unittest.cc b/chrome/browser/media/webrtc/webrtc_event_log_manager_unittest.cc
index 7e3252e..9c83d8a 100644
--- a/chrome/browser/media/webrtc/webrtc_event_log_manager_unittest.cc
+++ b/chrome/browser/media/webrtc/webrtc_event_log_manager_unittest.cc
@@ -127,7 +127,6 @@
   }
 
   void SetUp() override {
-    content::WebRtcEventLogger::Set(event_log_manager_.get());
     SetLocalLogsObserver(&local_observer_);
     SetRemoteLogsObserver(&remote_observer_);
     LoadProfiles();
@@ -141,7 +140,6 @@
     // destroy |event_log_manager_|. However, we must also make sure that their
     // destructors do not attempt to access |event_log_manager_|, which in
     // normal code lives forever, but not in the unit tests.
-    content::WebRtcEventLogger::ClearForTesting();
     event_log_manager_.reset();
 
     // Guard against unexpected state changes.
@@ -519,7 +517,7 @@
  public:
   WebRtcEventLogManagerTest() {
     scoped_feature_list_.InitAndEnableFeature(features::kWebRtcRemoteEventLog);
-    event_log_manager_.reset(WebRtcEventLogManager::CreateSingletonInstance());
+    event_log_manager_ = WebRtcEventLogManager::CreateSingletonInstance();
   }
 
   void SetUp() override {
@@ -536,7 +534,7 @@
     : public WebRtcEventLogManagerTestBase {
  public:
   WebRtcEventLogManagerTestWithRemoteLoggingDisabled() {
-    event_log_manager_.reset(WebRtcEventLogManager::CreateSingletonInstance());
+    event_log_manager_ = WebRtcEventLogManager::CreateSingletonInstance();
   }
 };
 
diff --git a/chrome/browser/media/webrtc/webrtc_event_log_uploader.cc b/chrome/browser/media/webrtc/webrtc_event_log_uploader.cc
index 8d7f0bd..dec2da97 100644
--- a/chrome/browser/media/webrtc/webrtc_event_log_uploader.cc
+++ b/chrome/browser/media/webrtc/webrtc_event_log_uploader.cc
@@ -19,15 +19,20 @@
 // Explanation about the life cycle of a WebRtcEventLogUploaderImpl object, and
 // about why its use of base::Unretained is safe:
 // * WebRtcEventLogUploaderImpl objects are owned (indirectly) by
-//   WebRtcEventLogManager, which is a singleton object that is not destroyed
-//   during Chrome shutdown, but rather, is allowed to leak.
-// * Therefore, objects of type WebRtcEventLogUploaderImpl will only be
-//   destroyed when their owner explicitly decides to do so.
+//   WebRtcEventLogManager, which is a singleton object that is only destroyed
+//   during Chrome shutdown, from ~BrowserProcessImpl().
+//   When ~BrowserProcessImpl() executes, tasks previously posted to
+//   WebRtcEventLogManager's internal task will not execute, and anything posted
+//   later will be discarded. Deleting a WebRtcEventLogUploaderImpl will
+//   therefore have no adverse effects.
+// * Except for during Chrome shutdown, WebRtcEventLogUploaderImpl objects will
+//   only be destroyed when their owner explicitly decides to destroy them.
 // * The direct owner, WebRtcRemoteEventLogManager, only deletes a
 //   WebRtcEventLogUploaderImpl after it receives a notification
 //   of type OnWebRtcEventLogUploadComplete.
-// * OnWebRtcEventLogUploadComplete() is only ever called as the last step,
-//   there are no tasks pending which have a reference to this object.
+// * OnWebRtcEventLogUploadComplete() is only ever called as the last step in
+//   URLFetcher's lifecycle. When it is called, there are no tasks pending which
+//   have a reference to this WebRtcEventLogUploaderImpl object.
 // * The previous point follows from OnURLFetchComplete being guaranteed to
 //   be the last callback called on a URLFetcherDelegate.
 
@@ -168,13 +173,20 @@
 }
 
 WebRtcEventLogUploaderImpl::~WebRtcEventLogUploaderImpl() {
-  DCHECK(io_task_runner_->RunsTasksInCurrentSequence());
   // WebRtcEventLogUploaderImpl objects only deleted if either:
-  // 1. The upload was never started, meaning |url_fetcher_| was never set.
-  // 2. Upload started and finished.
-  // Therefore, we can be sure that when we destroy this object, there are no
-  // tasks pending that still hold a base::Unretained() reference to it.
-  DCHECK(!url_fetcher_);
+  // 1. Chrome shutdown - see the explanation at top of this file.
+  // 2. The upload was never started, meaning |url_fetcher_| was never set.
+  // 3. Upload started and finished - |url_fetcher_| should have been reset
+  //    so that we would be able to DCHECK and demonstrate that the determinant
+  //    is maintained.
+  // Therefore, we can be sure that when we destroy this object, there are
+  // either no tasks holding a reference to it, or they would not be allowed
+  // to run.
+  if (io_task_runner_->RunsTasksInCurrentSequence()) {
+    DCHECK(!url_fetcher_);
+  } else {
+    DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  }
 }
 
 bool WebRtcEventLogUploaderImpl::PrepareUploadData() {
diff --git a/chrome/browser/media/webrtc/webrtc_text_log_handler.cc b/chrome/browser/media/webrtc/webrtc_text_log_handler.cc
index 0e2129e..770e3ae 100644
--- a/chrome/browser/media/webrtc/webrtc_text_log_handler.cc
+++ b/chrome/browser/media/webrtc/webrtc_text_log_handler.cc
@@ -403,7 +403,7 @@
 
   // Chrome version
   LogToCircularBuffer("Chrome version: " + version_info::GetVersionNumber() +
-                      " " + chrome::GetChannelString());
+                      " " + chrome::GetChannelName());
 
   // OS
   LogToCircularBuffer(base::SysInfo::OperatingSystemName() + " " +
diff --git a/chrome/browser/media_galleries/chromeos/mtp_device_delegate_impl_chromeos.cc b/chrome/browser/media_galleries/chromeos/mtp_device_delegate_impl_chromeos.cc
index 27b64b2..f7dd21f 100644
--- a/chrome/browser/media_galleries/chromeos/mtp_device_delegate_impl_chromeos.cc
+++ b/chrome/browser/media_galleries/chromeos/mtp_device_delegate_impl_chromeos.cc
@@ -330,13 +330,14 @@
 // - When |file_path| is a directory, base::File::FILE_ERROR_NOT_A_FILE is set.
 // - When |file_path| does not exist, base::File::FILE_ERROR_NOT_FOUND is set.
 // - For other error cases, base::File::FILE_ERROR_FAILED is set.
-std::pair<int, base::File::Error> OpenFileDescriptor(const char* file_path,
-                                                     const int flags) {
+std::pair<int, base::File::Error> OpenFileDescriptor(
+    const base::FilePath& file_path,
+    const int flags) {
   base::AssertBlockingAllowed();
 
-  if (base::DirectoryExists(base::FilePath(file_path)))
+  if (base::DirectoryExists(file_path))
     return std::make_pair(-1, base::File::FILE_ERROR_NOT_A_FILE);
-  int file_descriptor = open(file_path, flags);
+  int file_descriptor = open(file_path.value().c_str(), flags);
   if (file_descriptor >= 0)
     return std::make_pair(file_descriptor, base::File::FILE_OK);
   if (errno == ENOENT)
@@ -1516,8 +1517,7 @@
 
   base::PostTaskWithTraitsAndReplyWithResult(
       FROM_HERE, {base::MayBlock(), base::TaskPriority::BACKGROUND},
-      base::Bind(&OpenFileDescriptor, source_file_path.value().c_str(),
-                 O_RDONLY),
+      base::Bind(&OpenFileDescriptor, source_file_path, O_RDONLY),
       base::Bind(&MTPDeviceDelegateImplLinux::OnDidOpenFDToCopyFileFromLocal,
                  weak_ptr_factory_.GetWeakPtr(), device_file_path,
                  success_callback, error_callback));
diff --git a/chrome/browser/net/default_network_context_params.cc b/chrome/browser/net/default_network_context_params.cc
index 75c3a91d..aec0ef0 100644
--- a/chrome/browser/net/default_network_context_params.cc
+++ b/chrome/browser/net/default_network_context_params.cc
@@ -33,7 +33,7 @@
 
   network_context_params->user_agent = GetUserAgent();
 
-  std::string quic_user_agent_id = chrome::GetChannelString();
+  std::string quic_user_agent_id = chrome::GetChannelName();
   if (!quic_user_agent_id.empty())
     quic_user_agent_id.push_back(' ');
   quic_user_agent_id.append(
diff --git a/chrome/browser/net/network_context_configuration_browsertest.cc b/chrome/browser/net/network_context_configuration_browsertest.cc
index b84cf47..12b3c9e 100644
--- a/chrome/browser/net/network_context_configuration_browsertest.cc
+++ b/chrome/browser/net/network_context_configuration_browsertest.cc
@@ -575,7 +575,9 @@
   }
 }
 
-IN_PROC_BROWSER_TEST_P(NetworkContextConfigurationBrowserTest, ProxyConfig) {
+// Flaky, see https://crbug.com/823077
+IN_PROC_BROWSER_TEST_P(NetworkContextConfigurationBrowserTest,
+                       DISABLED_ProxyConfig) {
   SetProxyPref(embedded_test_server()->host_port_pair());
   TestProxyConfigured();
 }
diff --git a/chrome/browser/ntp_snippets/contextual_content_suggestions_service_factory.cc b/chrome/browser/ntp_snippets/contextual_content_suggestions_service_factory.cc
index 6e20b54b..df8bc4c 100644
--- a/chrome/browser/ntp_snippets/contextual_content_suggestions_service_factory.cc
+++ b/chrome/browser/ntp_snippets/contextual_content_suggestions_service_factory.cc
@@ -36,9 +36,7 @@
 bool IsContextualContentSuggestionsEnabled() {
 #if defined(OS_ANDROID)
   return base::FeatureList::IsEnabled(
-             chrome::android::kContextualSuggestionsCarousel) ||
-         base::FeatureList::IsEnabled(
-             chrome::android::kContextualSuggestionsAboveArticles);
+      chrome::android::kContextualSuggestionsBottomSheet);
 #else
   return false;
 #endif  // OS_ANDROID
diff --git a/chrome/browser/policy/configuration_policy_handler_list_factory.cc b/chrome/browser/policy/configuration_policy_handler_list_factory.cc
index 741503e..87ff2966 100644
--- a/chrome/browser/policy/configuration_policy_handler_list_factory.cc
+++ b/chrome/browser/policy/configuration_policy_handler_list_factory.cc
@@ -779,6 +779,10 @@
   { key::kAutoplayAllowed,
     prefs::kAutoplayAllowed,
     base::Value::Type::BOOLEAN },
+
+  { key::kAutoplayWhitelist,
+    prefs::kAutoplayWhitelist,
+    base::Value::Type::LIST },
 #endif  // !defined(OS_ANDROID)
 };
 // clang-format on
diff --git a/chrome/browser/policy/policy_browsertest.cc b/chrome/browser/policy/policy_browsertest.cc
index 92e178b..72fcff3 100644
--- a/chrome/browser/policy/policy_browsertest.cc
+++ b/chrome/browser/policy/policy_browsertest.cc
@@ -293,6 +293,8 @@
 const base::FilePath::CharType kAppUnpackedExt[] =
     FILE_PATH_LITERAL("app");
 
+const char kAutoplayTestPageURL[] = "/media/autoplay_iframe.html";
+
 #if !defined(OS_MACOSX)
 const base::FilePath::CharType kUnpackedFullscreenAppName[] =
     FILE_PATH_LITERAL("fullscreen_app");
@@ -5120,15 +5122,69 @@
 
 #if !defined(OS_ANDROID)
 
-IN_PROC_BROWSER_TEST_F(PolicyTest, AutoplayAllowedByPolicy) {
-  ASSERT_TRUE(embedded_test_server()->Start());
-  content::WebContents* web_contents =
-      browser()->tab_strip_model()->GetActiveWebContents();
+class AutoplayPolicyTest : public PolicyTest {
+ public:
+  AutoplayPolicyTest() {
+    // Start two embedded test servers on different ports. This will ensure
+    // the test works correctly with cross origin iframes and site-per-process.
+    embedded_test_server2()->AddDefaultHandlers(
+        base::FilePath(FILE_PATH_LITERAL("chrome/test/data")));
+    EXPECT_TRUE(embedded_test_server()->Start());
+    EXPECT_TRUE(embedded_test_server2()->Start());
+  }
+
+  void NavigateToTestPage() {
+    GURL origin = embedded_test_server()->GetURL(kAutoplayTestPageURL);
+    ui_test_utils::NavigateToURL(browser(), origin);
+
+    // Navigate the subframe to the test page but on the second origin.
+    GURL origin2 = embedded_test_server2()->GetURL(kAutoplayTestPageURL);
+    std::string script = base::StringPrintf(
+        "setTimeout(\""
+        "document.getElementById('subframe').src='%s';"
+        "\",0)",
+        origin2.spec().c_str());
+    content::TestNavigationObserver load_observer(GetWebContents());
+    EXPECT_TRUE(ExecuteScriptWithoutUserGesture(GetWebContents(), script));
+    load_observer.Wait();
+  }
+
+  net::EmbeddedTestServer* embedded_test_server2() {
+    return &embedded_test_server2_;
+  }
+
+  bool TryAutoplay(content::RenderFrameHost* rfh) {
+    bool result = false;
+
+    EXPECT_TRUE(content::ExecuteScriptWithoutUserGestureAndExtractBool(
+        rfh, "tryPlayback();", &result));
+
+    return result;
+  }
+
+  content::WebContents* GetWebContents() {
+    return browser()->tab_strip_model()->GetActiveWebContents();
+  }
+
+  content::RenderFrameHost* GetMainFrame() {
+    return GetWebContents()->GetMainFrame();
+  }
+
+  content::RenderFrameHost* GetChildFrame() {
+    return GetWebContents()->GetAllFrames()[1];
+  }
+
+ private:
+  // Second instance of embedded test server to provide a second test origin.
+  net::EmbeddedTestServer embedded_test_server2_;
+};
+
+IN_PROC_BROWSER_TEST_F(AutoplayPolicyTest, AutoplayAllowedByPolicy) {
+  NavigateToTestPage();
 
   // Check that autoplay was not allowed.
-  EXPECT_EQ(
-      web_contents->GetRenderViewHost()->GetWebkitPreferences().autoplay_policy,
-      content::AutoplayPolicy::kDocumentUserActivationRequired);
+  EXPECT_FALSE(TryAutoplay(GetMainFrame()));
+  EXPECT_FALSE(TryAutoplay(GetChildFrame()));
 
   // Update policy to allow autoplay.
   PolicyMap policies;
@@ -5137,10 +5193,177 @@
   UpdateProviderPolicy(policies);
 
   // Check that autoplay was allowed by policy.
-  web_contents->GetRenderViewHost()->OnWebkitPreferencesChanged();
-  EXPECT_EQ(
-      web_contents->GetRenderViewHost()->GetWebkitPreferences().autoplay_policy,
-      content::AutoplayPolicy::kNoUserGestureRequired);
+  GetWebContents()->GetRenderViewHost()->OnWebkitPreferencesChanged();
+  EXPECT_TRUE(TryAutoplay(GetMainFrame()));
+  EXPECT_TRUE(TryAutoplay(GetChildFrame()));
+}
+
+IN_PROC_BROWSER_TEST_F(AutoplayPolicyTest, AutoplayWhitelist_Allowed) {
+  NavigateToTestPage();
+
+  // Check that autoplay was not allowed.
+  EXPECT_FALSE(TryAutoplay(GetMainFrame()));
+  EXPECT_FALSE(TryAutoplay(GetChildFrame()));
+
+  // Create a test whitelist with our origin.
+  std::vector<base::Value> whitelist;
+  whitelist.push_back(base::Value(embedded_test_server()->GetURL("/").spec()));
+
+  // Update policy to allow autoplay for our test origin.
+  PolicyMap policies;
+  SetPolicy(&policies, key::kAutoplayWhitelist,
+            std::make_unique<base::ListValue>(whitelist));
+  UpdateProviderPolicy(policies);
+
+  // Check that autoplay was allowed by policy.
+  GetWebContents()->GetRenderViewHost()->OnWebkitPreferencesChanged();
+  EXPECT_TRUE(TryAutoplay(GetMainFrame()));
+  EXPECT_TRUE(TryAutoplay(GetChildFrame()));
+}
+
+IN_PROC_BROWSER_TEST_F(AutoplayPolicyTest, AutoplayWhitelist_PatternAllowed) {
+  NavigateToTestPage();
+
+  // Check that autoplay was not allowed.
+  EXPECT_FALSE(TryAutoplay(GetMainFrame()));
+  EXPECT_FALSE(TryAutoplay(GetChildFrame()));
+
+  // Create a test whitelist with our origin.
+  std::vector<base::Value> whitelist;
+  whitelist.push_back(base::Value("127.0.0.1:*"));
+
+  // Update policy to allow autoplay for our test origin.
+  PolicyMap policies;
+  SetPolicy(&policies, key::kAutoplayWhitelist,
+            std::make_unique<base::ListValue>(whitelist));
+  UpdateProviderPolicy(policies);
+
+  // Check that autoplay was allowed by policy.
+  GetWebContents()->GetRenderViewHost()->OnWebkitPreferencesChanged();
+  EXPECT_TRUE(TryAutoplay(GetMainFrame()));
+  EXPECT_TRUE(TryAutoplay(GetChildFrame()));
+}
+
+IN_PROC_BROWSER_TEST_F(AutoplayPolicyTest, AutoplayWhitelist_Missing) {
+  NavigateToTestPage();
+
+  // Check that autoplay was not allowed.
+  EXPECT_FALSE(TryAutoplay(GetMainFrame()));
+  EXPECT_FALSE(TryAutoplay(GetChildFrame()));
+
+  // Create a test whitelist with a random origin.
+  std::vector<base::Value> whitelist;
+  whitelist.push_back(base::Value("https://www.example.com"));
+
+  // Update policy to allow autoplay for a random origin.
+  PolicyMap policies;
+  SetPolicy(&policies, key::kAutoplayWhitelist,
+            std::make_unique<base::ListValue>(whitelist));
+  UpdateProviderPolicy(policies);
+
+  // Check that autoplay was not allowed.
+  GetWebContents()->GetRenderViewHost()->OnWebkitPreferencesChanged();
+  EXPECT_FALSE(TryAutoplay(GetMainFrame()));
+  EXPECT_FALSE(TryAutoplay(GetChildFrame()));
+}
+
+IN_PROC_BROWSER_TEST_F(AutoplayPolicyTest, AutoplayDeniedByPolicy) {
+  NavigateToTestPage();
+
+  // Check that autoplay was not allowed.
+  EXPECT_FALSE(TryAutoplay(GetMainFrame()));
+  EXPECT_FALSE(TryAutoplay(GetChildFrame()));
+
+  // Update policy to forbid autoplay.
+  PolicyMap policies;
+  SetPolicy(&policies, key::kAutoplayAllowed,
+            std::make_unique<base::Value>(false));
+  UpdateProviderPolicy(policies);
+
+  // Check that autoplay was not allowed by policy.
+  GetWebContents()->GetRenderViewHost()->OnWebkitPreferencesChanged();
+  EXPECT_FALSE(TryAutoplay(GetMainFrame()));
+  EXPECT_FALSE(TryAutoplay(GetChildFrame()));
+
+  // Create a test whitelist with a random origin.
+  std::vector<base::Value> whitelist;
+  whitelist.push_back(base::Value("https://www.example.com"));
+
+  // Update policy to allow autoplay for a random origin.
+  SetPolicy(&policies, key::kAutoplayWhitelist,
+            std::make_unique<base::ListValue>(whitelist));
+  UpdateProviderPolicy(policies);
+
+  // Check that autoplay was not allowed.
+  GetWebContents()->GetRenderViewHost()->OnWebkitPreferencesChanged();
+  EXPECT_FALSE(TryAutoplay(GetMainFrame()));
+  EXPECT_FALSE(TryAutoplay(GetChildFrame()));
+}
+
+IN_PROC_BROWSER_TEST_F(AutoplayPolicyTest, AutoplayDeniedAllowedWithURL) {
+  NavigateToTestPage();
+
+  // Check that autoplay was not allowed.
+  EXPECT_FALSE(TryAutoplay(GetMainFrame()));
+  EXPECT_FALSE(TryAutoplay(GetChildFrame()));
+
+  // Update policy to forbid autoplay.
+  PolicyMap policies;
+  SetPolicy(&policies, key::kAutoplayAllowed,
+            std::make_unique<base::Value>(false));
+  UpdateProviderPolicy(policies);
+
+  // Check that autoplay was not allowed by policy.
+  GetWebContents()->GetRenderViewHost()->OnWebkitPreferencesChanged();
+  EXPECT_FALSE(TryAutoplay(GetMainFrame()));
+  EXPECT_FALSE(TryAutoplay(GetChildFrame()));
+
+  // Create a test whitelist with our test origin.
+  std::vector<base::Value> whitelist;
+  whitelist.push_back(base::Value(embedded_test_server()->GetURL("/").spec()));
+
+  // Update policy to allow autoplay for our test origin.
+  SetPolicy(&policies, key::kAutoplayWhitelist,
+            std::make_unique<base::ListValue>(whitelist));
+  UpdateProviderPolicy(policies);
+
+  // Check that autoplay was allowed by policy.
+  GetWebContents()->GetRenderViewHost()->OnWebkitPreferencesChanged();
+  EXPECT_TRUE(TryAutoplay(GetMainFrame()));
+  EXPECT_TRUE(TryAutoplay(GetChildFrame()));
+}
+
+IN_PROC_BROWSER_TEST_F(AutoplayPolicyTest, AutoplayAllowedGlobalAndURL) {
+  NavigateToTestPage();
+
+  // Check that autoplay was not allowed.
+  EXPECT_FALSE(TryAutoplay(GetMainFrame()));
+  EXPECT_FALSE(TryAutoplay(GetChildFrame()));
+
+  // Update policy to forbid autoplay.
+  PolicyMap policies;
+  SetPolicy(&policies, key::kAutoplayAllowed,
+            std::make_unique<base::Value>(false));
+  UpdateProviderPolicy(policies);
+
+  // Check that autoplay was not allowed by policy.
+  GetWebContents()->GetRenderViewHost()->OnWebkitPreferencesChanged();
+  EXPECT_FALSE(TryAutoplay(GetMainFrame()));
+  EXPECT_FALSE(TryAutoplay(GetChildFrame()));
+
+  // Create a test whitelist with our test origin.
+  std::vector<base::Value> whitelist;
+  whitelist.push_back(base::Value(embedded_test_server()->GetURL("/").spec()));
+
+  // Update policy to allow autoplay for our test origin.
+  SetPolicy(&policies, key::kAutoplayWhitelist,
+            std::make_unique<base::ListValue>(whitelist));
+  UpdateProviderPolicy(policies);
+
+  // Check that autoplay was allowed by policy.
+  GetWebContents()->GetRenderViewHost()->OnWebkitPreferencesChanged();
+  EXPECT_TRUE(TryAutoplay(GetMainFrame()));
+  EXPECT_TRUE(TryAutoplay(GetChildFrame()));
 }
 
 #endif  // !defined(OS_ANDROID)
diff --git a/chrome/browser/profile_resetter/resettable_settings_snapshot.cc b/chrome/browser/profile_resetter/resettable_settings_snapshot.cc
index e38ce8e..ccabf2df 100644
--- a/chrome/browser/profile_resetter/resettable_settings_snapshot.cc
+++ b/chrome/browser/profile_resetter/resettable_settings_snapshot.cc
@@ -242,7 +242,7 @@
           l10n_util::GetStringUTF16(IDS_VERSION_UI_USER_AGENT),
           GetUserAgent());
   std::string version = version_info::GetVersionNumber();
-  version += chrome::GetChannelString();
+  version += chrome::GetChannelName();
   AddPair(list.get(),
           l10n_util::GetStringUTF16(IDS_PRODUCT_NAME),
           version);
diff --git a/chrome/browser/profiles/profile_io_data.cc b/chrome/browser/profiles/profile_io_data.cc
index e7f8c66..0cd5bb8 100644
--- a/chrome/browser/profiles/profile_io_data.cc
+++ b/chrome/browser/profiles/profile_io_data.cc
@@ -397,7 +397,6 @@
     std::unique_ptr<ProfileIOData::ChromeURLRequestContextGetterVector>
         getters) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  ProfileIOData::ChromeURLRequestContextGetterVector::iterator iter;
   for (auto& chrome_context_getter : *getters)
     chrome_context_getter->NotifyContextShuttingDown();
 }
diff --git a/chrome/browser/resources/media/media_engagement.js b/chrome/browser/resources/media/media_engagement.js
index a4a8af78..6f685cb 100644
--- a/chrome/browser/resources/media/media_engagement.js
+++ b/chrome/browser/resources/media/media_engagement.js
@@ -80,7 +80,7 @@
   if (sortKey == 'visits' || sortKey == 'mediaPlaybacks' ||
       sortKey == 'lastMediaPlaybackTime' || sortKey == 'totalScore' ||
       sortKey == 'audiblePlaybacks' || sortKey == 'significantPlaybacks' ||
-      sortKey == 'highScoreChanges') {
+      sortKey == 'highScoreChanges' || sortKey == 'isHigh') {
     return val1 - val2;
   }
 
diff --git a/chrome/browser/resources/print_preview/new/header.js b/chrome/browser/resources/print_preview/new/header.js
index b1bf792..4c5e0240 100644
--- a/chrome/browser/resources/print_preview/new/header.js
+++ b/chrome/browser/resources/print_preview/new/header.js
@@ -88,13 +88,13 @@
    */
   computeLabelInfo_: function() {
     const saveToPdfOrDrive = this.isPdfOrDrive_();
-    let numPages = this.getSetting('pages').value.length;
+    let numPages = this.getSettingValue('pages').length;
     let numSheets = numPages;
-    if (!saveToPdfOrDrive && this.getSetting('duplex').value) {
+    if (!saveToPdfOrDrive && this.getSettingValue('duplex')) {
       numSheets = Math.ceil(numPages / 2);
     }
 
-    const copies = /** @type {number} */ (this.getSetting('copies').value);
+    const copies = parseInt(this.getSettingValue('copies'), 10);
     numSheets *= copies;
     numPages *= copies;
 
diff --git a/chrome/browser/resources/print_preview/new/model.js b/chrome/browser/resources/print_preview/new/model.js
index 0b90df4..dec76c3 100644
--- a/chrome/browser/resources/print_preview/new/model.js
+++ b/chrome/browser/resources/print_preview/new/model.js
@@ -365,7 +365,7 @@
       this.set('settings.dpi.value', defaultOption);
     } else if (
         caps && caps.dpi && caps.dpi.option && caps.dpi.option.length > 0) {
-      this.set('settings.dpi.value', caps.dpi.option[0]);
+      this.set('settings.dpi.unavailableValue', caps.dpi.option[0]);
     }
 
     if (this.settings.vendorItems.available) {
@@ -518,7 +518,7 @@
       duplex: this.getSettingValue('duplex') ?
           print_preview_new.DuplexMode.LONG_EDGE :
           print_preview_new.DuplexMode.SIMPLEX,
-      copies: this.getSettingValue('copies'),
+      copies: parseInt(this.getSettingValue('copies'), 10),
       collate: this.getSettingValue('collate'),
       shouldPrintBackgrounds: this.getSettingValue('cssBackground'),
       shouldPrintSelectionOnly: false,  // only used in print preview
diff --git a/chrome/browser/resources/settings/incompatible_applications_page/incompatible_applications_page.html b/chrome/browser/resources/settings/incompatible_applications_page/incompatible_applications_page.html
index b7e71fb..06e21fbc 100644
--- a/chrome/browser/resources/settings/incompatible_applications_page/incompatible_applications_page.html
+++ b/chrome/browser/resources/settings/incompatible_applications_page/incompatible_applications_page.html
@@ -36,7 +36,7 @@
         </div>
       </div>
       <div class="settings-box continuation">
-        <div class="secondary">[[listTitleText_]]</div>
+        <h2 class="secondary">[[listTitleText_]]</h2>
       </div>
       <div id="incompatible-applications-list" class="list-frame vertical-list">
         <template is="dom-repeat" items="[[applications_]]" as="application">
diff --git a/chrome/browser/search_engines/ui_thread_search_terms_data.cc b/chrome/browser/search_engines/ui_thread_search_terms_data.cc
index 418fcfc..a3c60ab 100644
--- a/chrome/browser/search_engines/ui_thread_search_terms_data.cc
+++ b/chrome/browser/search_engines/ui_thread_search_terms_data.cc
@@ -125,7 +125,7 @@
   if (version_info::IsOfficialBuild())
     version += " (Official)";
   version += " " + version_info::GetOSType();
-  std::string modifier(chrome::GetChannelString());
+  std::string modifier(chrome::GetChannelName());
   if (!modifier.empty())
     version += " " + modifier;
   return version;
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 22bc6fa0..778b809 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -1011,6 +1011,7 @@
     "//components/safe_browsing/web_ui",
     "//components/search",
     "//components/search_engines",
+    "//components/security_interstitials/content:security_interstitial_page",
     "//components/security_interstitials/core",
     "//components/security_state/content",
     "//components/security_state/core",
diff --git a/chrome/browser/ui/aura/accessibility/ax_root_obj_wrapper.cc b/chrome/browser/ui/aura/accessibility/ax_root_obj_wrapper.cc
index d1bab173..7e668151 100644
--- a/chrome/browser/ui/aura/accessibility/ax_root_obj_wrapper.cc
+++ b/chrome/browser/ui/aura/accessibility/ax_root_obj_wrapper.cc
@@ -54,7 +54,7 @@
   out_node_data->id = unique_id_.Get();
   out_node_data->role = ax::mojom::Role::kDesktop;
   out_node_data->AddStringAttribute(ax::mojom::StringAttribute::kChromeChannel,
-                                    chrome::GetChannelString());
+                                    chrome::GetChannelName());
 }
 
 const ui::AXUniqueId& AXRootObjWrapper::GetUniqueId() const {
diff --git a/chrome/browser/ui/passwords/password_manager_presenter_unittest.cc b/chrome/browser/ui/passwords/password_manager_presenter_unittest.cc
index c7633d9..ca9cd6d 100644
--- a/chrome/browser/ui/passwords/password_manager_presenter_unittest.cc
+++ b/chrome/browser/ui/passwords/password_manager_presenter_unittest.cc
@@ -23,9 +23,18 @@
 
 using base::ASCIIToUTF16;
 using testing::_;
+using testing::Each;
 using testing::Eq;
 using testing::Property;
 
+namespace {
+
+MATCHER(IsNotBlacklisted, "") {
+  return !arg->blacklisted_by_user;
+}
+
+}  // namespace
+
 class PasswordManagerPresenterTest : public testing::Test {
  protected:
   PasswordManagerPresenterTest() {}
@@ -126,4 +135,48 @@
   UpdateLists();
 }
 
+// Check that only stored passwords, not blacklisted entries, are provided for
+// exporting.
+TEST_F(PasswordManagerPresenterTest, BlacklistedPasswordsNotExported) {
+  AddPasswordEntry(GURL("http://abc1.com"), "test@gmail.com", "test");
+  AddPasswordException(GURL("http://abc2.com"));
+  EXPECT_CALL(*GetUIController(),
+              SetPasswordList(Property(
+                  &std::vector<std::unique_ptr<autofill::PasswordForm>>::size,
+                  Eq(1u))));
+  EXPECT_CALL(*GetUIController(),
+              SetPasswordExceptionList(Property(
+                  &std::vector<std::unique_ptr<autofill::PasswordForm>>::size,
+                  Eq(1u))));
+  UpdateLists();
+
+  std::vector<std::unique_ptr<autofill::PasswordForm>> passwords_for_export =
+      GetUIController()->GetPasswordManagerPresenter()->GetAllPasswords();
+  EXPECT_EQ(1u, passwords_for_export.size());
+  EXPECT_THAT(passwords_for_export, Each(IsNotBlacklisted()));
+}
+
+// Check that stored passwords are provided for exporting even if there is a
+// blacklist entry for the same origin. This is needed to keep the user in
+// control of all of their stored passwords.
+TEST_F(PasswordManagerPresenterTest, BlacklistDoesNotPreventExporting) {
+  const GURL kSameOrigin("https://abc.com");
+  AddPasswordEntry(kSameOrigin, "test@gmail.com", "test");
+  AddPasswordException(kSameOrigin);
+  EXPECT_CALL(*GetUIController(),
+              SetPasswordList(Property(
+                  &std::vector<std::unique_ptr<autofill::PasswordForm>>::size,
+                  Eq(1u))));
+  EXPECT_CALL(*GetUIController(),
+              SetPasswordExceptionList(Property(
+                  &std::vector<std::unique_ptr<autofill::PasswordForm>>::size,
+                  Eq(1u))));
+  UpdateLists();
+
+  std::vector<std::unique_ptr<autofill::PasswordForm>> passwords_for_export =
+      GetUIController()->GetPasswordManagerPresenter()->GetAllPasswords();
+  ASSERT_EQ(1u, passwords_for_export.size());
+  EXPECT_EQ(kSameOrigin, passwords_for_export[0]->origin);
+}
+
 }  // namespace
diff --git a/chrome/browser/ui/views/constrained_window_views_browsertest.cc b/chrome/browser/ui/views/constrained_window_views_browsertest.cc
index ad45018..f9e79285 100644
--- a/chrome/browser/ui/views/constrained_window_views_browsertest.cc
+++ b/chrome/browser/ui/views/constrained_window_views_browsertest.cc
@@ -155,6 +155,8 @@
   content::WebContents* web_contents =
       browser()->tab_strip_model()->GetActiveWebContents();
   std::unique_ptr<TestDialog> dialog = ShowModalDialog(web_contents);
+  // On Mac, animations cause this test to be flaky.
+  dialog->GetWidget()->SetVisibilityChangedAnimationsEnabled(false);
   EXPECT_TRUE(dialog->GetWidget()->IsVisible());
 
   // Move the tab to a second browser window; but first create another tab.
@@ -181,6 +183,8 @@
 IN_PROC_BROWSER_TEST_F(ConstrainedWindowViewTest, ClosesOnEscape) {
   std::unique_ptr<TestDialog> dialog =
       ShowModalDialog(browser()->tab_strip_model()->GetActiveWebContents());
+  // On Mac, animations cause this test to be flaky.
+  dialog->GetWidget()->SetVisibilityChangedAnimationsEnabled(false);
   EXPECT_TRUE(dialog->GetWidget()->IsVisible());
   EXPECT_TRUE(ui_test_utils::SendKeyPressSync(browser(), ui::VKEY_ESCAPE,
                                               false, false, false, false));
diff --git a/chrome/browser/ui/views/exclusive_access_bubble_views_interactive_uitest.cc b/chrome/browser/ui/views/exclusive_access_bubble_views_interactive_uitest.cc
index cbaab4a..9629e512 100644
--- a/chrome/browser/ui/views/exclusive_access_bubble_views_interactive_uitest.cc
+++ b/chrome/browser/ui/views/exclusive_access_bubble_views_interactive_uitest.cc
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "build/build_config.h"
 #include "chrome/browser/ui/exclusive_access/fullscreen_controller_test.h"
 #include "chrome/browser/ui/views/exclusive_access_bubble_views.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
@@ -37,11 +38,17 @@
   DISALLOW_COPY_AND_ASSIGN(ExclusiveAccessBubbleViewsTest);
 };
 
+#if defined(OS_MACOSX)
+// Encounters an internal MacOS assert: http://crbug.com/823490
+#define MAYBE_NativeClose DISABLED_NativeClose
+#else
+#define MAYBE_NativeClose NativeClose
+#endif
 // Simulate obscure codepaths resulting in the bubble Widget being closed before
 // the ExclusiveAccessBubbleViews destructor asks for it. If a close bypasses
 // the destructor, animations could still be running that attempt to manipulate
 // a destroyed Widget and crash.
-IN_PROC_BROWSER_TEST_F(ExclusiveAccessBubbleViewsTest, NativeClose) {
+IN_PROC_BROWSER_TEST_F(ExclusiveAccessBubbleViewsTest, MAYBE_NativeClose) {
   EXPECT_FALSE(bubble());
   EnterActiveTabFullscreen();
   EXPECT_TRUE(bubble());
diff --git a/chrome/browser/ui/views/frame/browser_view_interactive_uitest.cc b/chrome/browser/ui/views/frame/browser_view_interactive_uitest.cc
index a3ef188..75e78b4 100644
--- a/chrome/browser/ui/views/frame/browser_view_interactive_uitest.cc
+++ b/chrome/browser/ui/views/frame/browser_view_interactive_uitest.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/ui/views/frame/browser_view.h"
 
 #include "base/macros.h"
+#include "build/build_config.h"
 #include "chrome/browser/ui/browser_commands.h"
 #include "chrome/browser/ui/views/location_bar/location_bar_view.h"
 #include "chrome/test/base/in_process_browser_test.h"
@@ -27,7 +28,13 @@
 
 }  // namespace
 
-IN_PROC_BROWSER_TEST_F(BrowserViewTest, FullscreenClearsFocus) {
+#if defined(OS_MACOSX)
+// Encounters an internal MacOS assert: http://crbug.com/823490
+#define MAYBE_FullscreenClearsFocus DISABLED_FullscreenClearsFocus
+#else
+#define MAYBE_FullscreenClearsFocus FullscreenClearsFocus
+#endif
+IN_PROC_BROWSER_TEST_F(BrowserViewTest, MAYBE_FullscreenClearsFocus) {
   BrowserView* browser_view = static_cast<BrowserView*>(browser()->window());
   LocationBarView* location_bar_view = browser_view->GetLocationBarView();
   FocusManager* focus_manager = browser_view->GetFocusManager();
diff --git a/chrome/browser/ui/views/keyboard_access_browsertest.cc b/chrome/browser/ui/views/keyboard_access_browsertest.cc
index 7ecd475..fd6da7ca 100644
--- a/chrome/browser/ui/views/keyboard_access_browsertest.cc
+++ b/chrome/browser/ui/views/keyboard_access_browsertest.cc
@@ -339,6 +339,9 @@
 // http://crbug.com/62310.
 #if defined(OS_CHROMEOS)
 #define MAYBE_TestMenuKeyboardAccess DISABLED_TestMenuKeyboardAccess
+#elif defined(OS_MACOSX)
+// No keyboard shortcut for the Chrome menu on Mac: http://crbug.com/823952
+#define MAYBE_TestMenuKeyboardAccess DISABLED_TestMenuKeyboardAccess
 #else
 #define MAYBE_TestMenuKeyboardAccess TestMenuKeyboardAccess
 #endif
@@ -350,10 +353,12 @@
 // http://crbug.com/62310.
 #if defined(OS_CHROMEOS)
 #define MAYBE_TestAltMenuKeyboardAccess DISABLED_TestAltMenuKeyboardAccess
+#elif defined(OS_MACOSX)
+// No keyboard shortcut for the Chrome menu on Mac: http://crbug.com/823952
+#define MAYBE_TestAltMenuKeyboardAccess DISABLED_TestAltMenuKeyboardAccess
 #else
 #define MAYBE_TestAltMenuKeyboardAccess TestAltMenuKeyboardAccess
 #endif
-
 IN_PROC_BROWSER_TEST_F(KeyboardAccessTest, MAYBE_TestAltMenuKeyboardAccess) {
   TestMenuKeyboardAccess(true, false, false);
 }
diff --git a/chrome/browser/ui/views/location_bar/location_icon_view_interactive_uitest.cc b/chrome/browser/ui/views/location_bar/location_icon_view_interactive_uitest.cc
index 7ad9c8e5..b2f0071 100644
--- a/chrome/browser/ui/views/location_bar/location_icon_view_interactive_uitest.cc
+++ b/chrome/browser/ui/views/location_bar/location_icon_view_interactive_uitest.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/ui/views/location_bar/location_icon_view.h"
 
+#include "build/build_config.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
 #include "chrome/browser/ui/views/location_bar/location_bar_view.h"
 #include "chrome/browser/ui/views/page_info/page_info_bubble_view.h"
@@ -60,8 +61,16 @@
             PageInfoBubbleView::GetShownBubbleType());
 }
 
+#if defined(OS_MACOSX)
+// Widget activation doesn't work on Mac: https://crbug.com/823543
+#define MAYBE_ActivateFirstInactiveBubbleForAccessibility \
+  DISABLED_ActivateFirstInactiveBubbleForAccessibility
+#else
+#define MAYBE_ActivateFirstInactiveBubbleForAccessibility \
+  ActivateFirstInactiveBubbleForAccessibility
+#endif
 IN_PROC_BROWSER_TEST_F(LocationIconViewTest,
-                       ActivateFirstInactiveBubbleForAccessibility) {
+                       MAYBE_ActivateFirstInactiveBubbleForAccessibility) {
   BrowserView* browser_view = BrowserView::GetBrowserViewForBrowser(browser());
   LocationBarView* location_bar_view = browser_view->GetLocationBarView();
   EXPECT_FALSE(
diff --git a/chrome/browser/ui/views/ssl_client_certificate_selector_browsertest.cc b/chrome/browser/ui/views/ssl_client_certificate_selector_browsertest.cc
index 6bd9ea4..eb5d4284 100644
--- a/chrome/browser/ui/views/ssl_client_certificate_selector_browsertest.cc
+++ b/chrome/browser/ui/views/ssl_client_certificate_selector_browsertest.cc
@@ -392,7 +392,14 @@
   EXPECT_CALL(*auth_requestor_.get(), CancelCertificateSelection());
 }
 
-IN_PROC_BROWSER_TEST_F(SSLClientCertificateSelectorMultiProfileTest, Escape) {
+#if defined(OS_MACOSX)
+// Widget activation doesn't work on Mac: https://crbug.com/823543
+#define MAYBE_Escape DISABLED_Escape
+#else
+#define MAYBE_Escape Escape
+#endif
+IN_PROC_BROWSER_TEST_F(SSLClientCertificateSelectorMultiProfileTest,
+                       MAYBE_Escape) {
   EXPECT_CALL(*auth_requestor_1_.get(), CertificateSelected(nullptr, nullptr));
 
   EXPECT_TRUE(ui_test_utils::SendKeyPressSync(
@@ -406,8 +413,14 @@
   EXPECT_CALL(*auth_requestor_.get(), CancelCertificateSelection());
 }
 
+#if defined(OS_MACOSX)
+// Widget activation doesn't work on Mac: https://crbug.com/823543
+#define MAYBE_SelectDefault DISABLED_SelectDefault
+#else
+#define MAYBE_SelectDefault SelectDefault
+#endif
 IN_PROC_BROWSER_TEST_F(SSLClientCertificateSelectorMultiProfileTest,
-                       SelectDefault) {
+                       MAYBE_SelectDefault) {
   EXPECT_CALL(*auth_requestor_1_.get(),
               CertificateSelected(cert_identity_1_->certificate(),
                                   cert_identity_1_->ssl_private_key()));
diff --git a/chrome/browser/ui/views/toolbar/toolbar_view_interactive_uitest.cc b/chrome/browser/ui/views/toolbar/toolbar_view_interactive_uitest.cc
index 6e5485b..32fec27 100644
--- a/chrome/browser/ui/views/toolbar/toolbar_view_interactive_uitest.cc
+++ b/chrome/browser/ui/views/toolbar/toolbar_view_interactive_uitest.cc
@@ -259,10 +259,23 @@
     EXPECT_EQ(ids[i], reverse_ids[count - 2 - i]);
 }
 
-IN_PROC_BROWSER_TEST_F(ToolbarViewTest, ToolbarCycleFocus) {
+#if defined(OS_MACOSX)
+// Widget activation doesn't work on Mac: https://crbug.com/823543
+#define MAYBE_ToolbarCycleFocus DISABLED_ToolbarCycleFocus
+#else
+#define MAYBE_ToolbarCycleFocus ToolbarCycleFocus
+#endif
+IN_PROC_BROWSER_TEST_F(ToolbarViewTest, MAYBE_ToolbarCycleFocus) {
   RunToolbarCycleFocusTest(browser());
 }
 
+#if defined(OS_MACOSX)
+// Widget activation doesn't work on Mac: https://crbug.com/823543
+#define MAYBE_ToolbarCycleFocusWithBookmarkBar \
+  DISABLED_ToolbarCycleFocusWithBookmarkBar
+#else
+#define MAYBE_ToolbarCycleFocusWithBookmarkBar ToolbarCycleFocusWithBookmarkBar
+#endif
 IN_PROC_BROWSER_TEST_F(ToolbarViewTest, ToolbarCycleFocusWithBookmarkBar) {
   CommandUpdater* updater = browser()->command_controller();
   updater->ExecuteCommand(IDC_SHOW_BOOKMARK_BAR);
diff --git a/chrome/browser/ui/webui/about_ui.cc b/chrome/browser/ui/webui/about_ui.cc
index 808d6e7..a54cb8f9 100644
--- a/chrome/browser/ui/webui/about_ui.cc
+++ b/chrome/browser/ui/webui/about_ui.cc
@@ -326,25 +326,6 @@
   return html;
 }
 
-std::string HelpCenterContent() {
-  std::string html;
-  AppendHeader(&html, 0, l10n_util::GetStringUTF8(IDS_CONNECTION_HELP_TITLE));
-  html +=
-      "<meta name=\"viewport\" content=\"initial-scale=1, minimum-scale=1, "
-      "width=device-width\">\n";
-  webui::AppendWebUiCssTextDefaults(&html);
-  html += "<style>";
-  html += l10n_util::GetStringUTF8(IDR_SECURITY_INTERSTITIAL_COMMON_CSS);
-  html += l10n_util::GetStringUTF8(IDR_SECURITY_INTERSTITIAL_CORE_CSS);
-  html += "</style>";
-  AppendBody(&html);
-  html += "<div class=\"interstitial-wrapper\">\n";
-  html += l10n_util::GetStringUTF8(IDS_CONNECTION_HELP_HTML);
-  html += "</div>\n";
-  AppendFooter(&html);
-  return html;
-}
-
 // AboutDnsHandler bounces the request back to the IO thread to collect
 // the DNS information.
 class AboutDnsHandler : public base::RefCountedThreadSafe<AboutDnsHandler> {
@@ -445,8 +426,6 @@
   // Add your data source here, in alphabetical order.
   if (source_name_ == chrome::kChromeUIChromeURLsHost) {
     response = ChromeURLs();
-  } else if (source_name_ == chrome::kChromeUIConnectionHelpHost) {
-    response = HelpCenterContent();
   } else if (source_name_ == chrome::kChromeUICreditsHost) {
     int idr = IDR_ABOUT_UI_CREDITS_HTML;
     if (path == kCreditsJsPath)
diff --git a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
index 944bd9d7b..aa94ebd 100644
--- a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
+++ b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
@@ -80,6 +80,8 @@
 #include "components/prefs/pref_service.h"
 #include "components/safe_browsing/web_ui/constants.h"
 #include "components/safe_browsing/web_ui/safe_browsing_ui.h"
+#include "components/security_interstitials/content/connection_help_ui.h"
+#include "components/security_interstitials/content/urls.h"
 #include "components/signin/core/browser/profile_management_switches.h"
 #include "components/signin/core/browser/signin_buildflags.h"
 #include "content/public/browser/web_contents.h"
@@ -280,10 +282,6 @@
 #endif  // defined(OS_WIN)
 
 bool IsAboutUI(const GURL& url) {
-  if (base::FeatureList::IsEnabled(features::kBundledConnectionHelpFeature) &&
-      url.host_piece() == chrome::kChromeUIConnectionHelpHost) {
-    return true;
-  }
   return (url.host_piece() == chrome::kChromeUIChromeURLsHost ||
           url.host_piece() == chrome::kChromeUICreditsHost ||
           url.host_piece() == chrome::kChromeUIDNSHost
@@ -405,6 +403,10 @@
     return MdBookmarksUI::IsEnabled() ? &NewWebUI<MdBookmarksUI>
                                       : &NewWebUI<BookmarksUI>;
   }
+  if (base::FeatureList::IsEnabled(features::kBundledConnectionHelpFeature) &&
+      url.host_piece() == security_interstitials::kChromeUIConnectionHelpHost) {
+    return &NewWebUI<security_interstitials::ConnectionHelpUI>;
+  }
   // Downloads list on Android uses the built-in download manager.
   if (url.host_piece() == chrome::kChromeUIDownloadsHost)
     return &NewWebUI<MdDownloadsUI>;
diff --git a/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc
index b54c7d6..9a56f4b0 100644
--- a/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc
@@ -397,7 +397,7 @@
   params.SetString("clientVersion", version_info::GetVersionNumber());
   if (!platform_version->empty())
     params.SetString("platformVersion", *platform_version);
-  params.SetString("releaseChannel", chrome::GetChannelString());
+  params.SetString("releaseChannel", chrome::GetChannelName());
   params.SetString("endpointGen", kEndpointGen);
 
   std::string email_domain;
diff --git a/chrome/browser/ui/webui/flash_ui.cc b/chrome/browser/ui/webui/flash_ui.cc
index f4352f0..1f92cb6 100644
--- a/chrome/browser/ui/webui/flash_ui.cc
+++ b/chrome/browser/ui/webui/flash_ui.cc
@@ -244,9 +244,9 @@
   auto list = std::make_unique<base::ListValue>();
 
   // Chrome version information.
-  AddPair(list.get(), l10n_util::GetStringUTF16(IDS_PRODUCT_NAME),
-          version_info::GetVersionNumber() + " (" + chrome::GetChannelString() +
-              ")");
+  AddPair(
+      list.get(), l10n_util::GetStringUTF16(IDS_PRODUCT_NAME),
+      version_info::GetVersionNumber() + " (" + chrome::GetChannelName() + ")");
 
   // OS version information.
   std::string os_label = version_info::GetOSType();
diff --git a/chrome/browser/ui/webui/nacl_ui.cc b/chrome/browser/ui/webui/nacl_ui.cc
index d687697c..d2acc6d 100644
--- a/chrome/browser/ui/webui/nacl_ui.cc
+++ b/chrome/browser/ui/webui/nacl_ui.cc
@@ -183,10 +183,9 @@
 
 void NaClDomHandler::AddOperatingSystemInfo(base::ListValue* list) {
   // Obtain the Chrome version info.
-  AddPair(list,
-          l10n_util::GetStringUTF16(IDS_PRODUCT_NAME),
+  AddPair(list, l10n_util::GetStringUTF16(IDS_PRODUCT_NAME),
           ASCIIToUTF16(version_info::GetVersionNumber() + " (" +
-                       chrome::GetChannelString() + ")"));
+                       chrome::GetChannelName() + ")"));
 
   // OS version information.
   // TODO(jvoung): refactor this to share the extra windows labeling
diff --git a/chrome/browser/ui/webui/net_export_ui.cc b/chrome/browser/ui/webui/net_export_ui.cc
index 9adb8914..896cdb11 100644
--- a/chrome/browser/ui/webui/net_export_ui.cc
+++ b/chrome/browser/ui/webui/net_export_ui.cc
@@ -333,7 +333,7 @@
   file_writer_->StartNetLog(
       path, capture_mode_, max_log_file_size_,
       base::CommandLine::ForCurrentProcess()->GetCommandLineString(),
-      chrome::GetChannelString(), GetURLRequestContexts());
+      chrome::GetChannelName(), GetURLRequestContexts());
 }
 
 void NetExportMessageHandler::ShowFileInShell(const base::FilePath& path) {
diff --git a/chrome/browser/ui/webui/net_internals/net_internals_ui.cc b/chrome/browser/ui/webui/net_internals/net_internals_ui.cc
index aa1c9cb..3c8c7e3 100644
--- a/chrome/browser/ui/webui/net_internals/net_internals_ui.cc
+++ b/chrome/browser/ui/webui/net_internals/net_internals_ui.cc
@@ -663,7 +663,7 @@
       "receivedConstants",
       net_log::ChromeNetLog::GetConstants(
           base::CommandLine::ForCurrentProcess()->GetCommandLineString(),
-          chrome::GetChannelString()));
+          chrome::GetChannelName()));
 
   PrePopulateEventList();
 
diff --git a/chrome/browser/ui/webui/net_internals/net_internals_ui_browsertest.cc b/chrome/browser/ui/webui/net_internals/net_internals_ui_browsertest.cc
index 555bcec..4082f857 100644
--- a/chrome/browser/ui/webui/net_internals/net_internals_ui_browsertest.cc
+++ b/chrome/browser/ui/webui/net_internals/net_internals_ui_browsertest.cc
@@ -331,7 +331,7 @@
 
   std::unique_ptr<base::Value> constants(net_log::ChromeNetLog::GetConstants(
       base::CommandLine::ForCurrentProcess()->GetCommandLineString(),
-      chrome::GetChannelString()));
+      chrome::GetChannelName()));
 
   std::unique_ptr<net::FileNetLogObserver> net_log_logger =
       net::FileNetLogObserver::CreateUnbounded(state->log_path,
diff --git a/chrome/browser/ui/webui/settings/about_handler.cc b/chrome/browser/ui/webui/settings/about_handler.cc
index 0e22bfc..4f86dbe 100644
--- a/chrome/browser/ui/webui/settings/about_handler.cc
+++ b/chrome/browser/ui/webui/settings/about_handler.cc
@@ -283,7 +283,7 @@
           l10n_util::GetStringUTF16(version_info::IsOfficialBuild()
                                         ? IDS_VERSION_UI_OFFICIAL
                                         : IDS_VERSION_UI_UNOFFICIAL),
-          base::UTF8ToUTF16(chrome::GetChannelString()),
+          base::UTF8ToUTF16(chrome::GetChannelName()),
 #if defined(ARCH_CPU_64_BITS)
           l10n_util::GetStringUTF16(IDS_VERSION_UI_64BIT)));
 #else
diff --git a/chrome/browser/ui/webui/snippets_internals_ui.cc b/chrome/browser/ui/webui/snippets_internals_ui.cc
index cbaf8fe..7f3d75c6 100644
--- a/chrome/browser/ui/webui/snippets_internals_ui.cc
+++ b/chrome/browser/ui/webui/snippets_internals_ui.cc
@@ -27,12 +27,9 @@
       content::WebUIDataSource::Create(chrome::kChromeUISnippetsInternalsHost);
 
 #if defined(OS_ANDROID)
-  source->AddBoolean(
-      "contextualSuggestionsEnabled",
-      base::FeatureList::IsEnabled(
-          chrome::android::kContextualSuggestionsCarousel) ||
-          base::FeatureList::IsEnabled(
-              chrome::android::kContextualSuggestionsAboveArticles));
+  source->AddBoolean("contextualSuggestionsEnabled",
+                     base::FeatureList::IsEnabled(
+                         chrome::android::kContextualSuggestionsBottomSheet));
 #else
   source->AddBoolean("contextualSuggestionsEnabled", false);
 #endif
diff --git a/chrome/browser/ui/webui/version_ui.cc b/chrome/browser/ui/webui/version_ui.cc
index 4a98bef..bc9b88c 100644
--- a/chrome/browser/ui/webui/version_ui.cc
+++ b/chrome/browser/ui/webui/version_ui.cc
@@ -57,7 +57,7 @@
   html_source->AddString(version_ui::kVersion,
                          version_info::GetVersionNumber());
   html_source->AddString(version_ui::kVersionModifier,
-                         chrome::GetChannelString());
+                         chrome::GetChannelName());
   html_source->AddString(version_ui::kJSEngine, "V8");
   html_source->AddString(version_ui::kJSVersion, V8_VERSION_STRING);
   html_source->AddLocalizedString(version_ui::kCompany,
diff --git a/chrome/browser/ui/webui/webui_browsertest.cc b/chrome/browser/ui/webui/webui_browsertest.cc
index 95e722ad..dc838bc 100644
--- a/chrome/browser/ui/webui/webui_browsertest.cc
+++ b/chrome/browser/ui/webui/webui_browsertest.cc
@@ -3,18 +3,14 @@
 // found in the LICENSE file.
 
 #include "base/command_line.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/test/scoped_feature_list.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_commands.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/webui/chrome_web_ui_controller_factory.h"
-#include "chrome/common/chrome_features.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/url_constants.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/ui_test_utils.h"
-#include "components/strings/grit/components_strings.h"
 #include "content/public/browser/child_process_security_policy.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/render_process_host.h"
@@ -22,7 +18,6 @@
 #include "content/public/common/content_switches.h"
 #include "content/public/test/browser_test_utils.h"
 #include "content/public/test/test_utils.h"
-#include "ui/base/l10n/l10n_util.h"
 
 namespace {
 
@@ -98,18 +93,3 @@
   // Verify that after a reload, the test handler has been disallowed.
   EXPECT_FALSE(test_handler->IsJavascriptAllowed());
 }
-
-// Tests that navigating to chrome://connection-help displays the proper help
-// page.
-IN_PROC_BROWSER_TEST_F(WebUIImplBrowserTest, ConnectionHelpUI) {
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitAndEnableFeature(features::kBundledConnectionHelpFeature);
-  ui_test_utils::NavigateToURL(browser(),
-                               GURL(chrome::kChromeUIConnectionHelpURL));
-  content::WaitForLoadStop(
-      browser()->tab_strip_model()->GetActiveWebContents());
-  base::string16 tab_title;
-  ui_test_utils::GetCurrentTabTitle(browser(), &tab_title);
-  EXPECT_EQ(base::UTF16ToUTF8(tab_title),
-            l10n_util::GetStringUTF8(IDS_CONNECTION_HELP_TITLE));
-}
diff --git a/chrome/browser/update_client/chrome_update_query_params_delegate.cc b/chrome/browser/update_client/chrome_update_query_params_delegate.cc
index 1712095b..db647b2c 100644
--- a/chrome/browser/update_client/chrome_update_query_params_delegate.cc
+++ b/chrome/browser/update_client/chrome_update_query_params_delegate.cc
@@ -31,7 +31,7 @@
 
 std::string ChromeUpdateQueryParamsDelegate::GetExtraParams() {
   return base::StringPrintf("&prodchannel=%s&prodversion=%s&lang=%s",
-                            chrome::GetChannelString().c_str(),
+                            chrome::GetChannelName().c_str(),
                             version_info::GetVersionNumber().c_str(),
                             GetLang());
 }
diff --git a/chrome/browser/update_client/chrome_update_query_params_delegate_unittest.cc b/chrome/browser/update_client/chrome_update_query_params_delegate_unittest.cc
index 3bd6775..b72f8129 100644
--- a/chrome/browser/update_client/chrome_update_query_params_delegate_unittest.cc
+++ b/chrome/browser/update_client/chrome_update_query_params_delegate_unittest.cc
@@ -39,9 +39,8 @@
       params, StringPrintf(
                   "prod=%s",
                   update_client::UpdateQueryParams::GetProdIdString(prod_id))));
-  EXPECT_TRUE(Contains(
-      params,
-      StringPrintf("prodchannel=%s", chrome::GetChannelString().c_str())));
+  EXPECT_TRUE(Contains(params, StringPrintf("prodchannel=%s",
+                                            chrome::GetChannelName().c_str())));
   EXPECT_TRUE(
       Contains(params, StringPrintf("prodversion=%s",
                                     version_info::GetVersionNumber().c_str())));
diff --git a/chrome/browser/vr/elements/disc_button.cc b/chrome/browser/vr/elements/disc_button.cc
index d999a64..1e301dc4 100644
--- a/chrome/browser/vr/elements/disc_button.cc
+++ b/chrome/browser/vr/elements/disc_button.cc
@@ -37,7 +37,10 @@
   vector_icon->AddChild(std::move(target));
   AddChild(std::move(vector_icon));
 
-  SetSounds(kSoundButtonHover, kSoundBackButtonClick, audio_delegate);
+  Sounds sounds;
+  sounds.hover_enter = kSoundButtonHover;
+  sounds.button_down = kSoundBackButtonClick;
+  SetSounds(sounds, audio_delegate);
 }
 
 DiscButton::~DiscButton() = default;
diff --git a/chrome/browser/vr/elements/resizer.cc b/chrome/browser/vr/elements/resizer.cc
index de727a0..77b10b2 100644
--- a/chrome/browser/vr/elements/resizer.cc
+++ b/chrome/browser/vr/elements/resizer.cc
@@ -61,7 +61,7 @@
 
 void Resizer::UpdateTransform(const gfx::Transform& head_pose) {
   float delta = touchpad_position_.y() - initial_touchpad_position_.y();
-  t_ = base::ClampToRange(initial_t_ - delta, 0.0f, 1.0f);
+  t_ = base::ClampToRange(initial_t_ + delta, 0.0f, 1.0f);
   float scale =
       gfx::Tween::FloatValueBetween(t_, kMinResizerScale, kMaxResizerScale);
   transform_.MakeIdentity();
diff --git a/chrome/browser/vr/elements/resizer_unittest.cc b/chrome/browser/vr/elements/resizer_unittest.cc
index 659c7ab..3168fb2 100644
--- a/chrome/browser/vr/elements/resizer_unittest.cc
+++ b/chrome/browser/vr/elements/resizer_unittest.cc
@@ -62,21 +62,21 @@
 }
 
 TEST_F(ResizerTest, UpwardMove) {
-  Move({0.5f, 0.5f}, {0.5f, 1.0f});
+  Move({0.5f, 0.5f}, {0.5f, 0.0f});
   CheckScale(kMinResizerScale);
 }
 
 TEST_F(ResizerTest, DownwardMove) {
-  Move({0.5f, 0.5f}, {0.5f, 0.0f});
+  Move({0.5f, 0.5f}, {0.5f, 1.0f});
   CheckScale(kMaxResizerScale);
 }
 
 TEST_F(ResizerTest, AccumulatedMove) {
-  Move({0.5f, 0.5f}, {0.5f, 0.25f});
+  Move({0.5f, 0.5f}, {0.5f, 0.75f});
   float scale = ComputeScale();
   EXPECT_LT(1.0f, scale);
   EXPECT_GT(kMaxResizerScale, scale);
-  Move({0.5f, 0.5f}, {0.5f, 0.25f});
+  Move({0.5f, 0.5f}, {0.5f, 0.75f});
   CheckScale(kMaxResizerScale);
 }
 
diff --git a/chrome/browser/vr/elements/ui_element.cc b/chrome/browser/vr/elements/ui_element.cc
index 56f71f9..e112782 100644
--- a/chrome/browser/vr/elements/ui_element.cc
+++ b/chrome/browser/vr/elements/ui_element.cc
@@ -13,7 +13,6 @@
 #include "base/strings/stringprintf.h"
 #include "base/time/time.h"
 #include "chrome/browser/vr/model/camera_model.h"
-#include "chrome/browser/vr/model/sound_id.h"
 #include "third_party/WebKit/public/platform/WebGestureEvent.h"
 #include "third_party/skia/include/core/SkRRect.h"
 #include "third_party/skia/include/core/SkRect.h"
@@ -141,8 +140,8 @@
 void UiElement::Initialize(SkiaSurfaceProvider* provider) {}
 
 void UiElement::OnHoverEnter(const gfx::PointF& position) {
-  if (hover_sound_id_ != kSoundNone && audio_delegate_) {
-    audio_delegate_->PlaySound(hover_sound_id_);
+  if (sounds_.hover_enter != kSoundNone && audio_delegate_) {
+    audio_delegate_->PlaySound(sounds_.hover_enter);
   }
   if (event_handlers_.hover_enter) {
     event_handlers_.hover_enter.Run();
@@ -152,6 +151,9 @@
 }
 
 void UiElement::OnHoverLeave() {
+  if (sounds_.hover_leave != kSoundNone && audio_delegate_) {
+    audio_delegate_->PlaySound(sounds_.hover_leave);
+  }
   if (event_handlers_.hover_leave) {
     event_handlers_.hover_leave.Run();
   } else if (parent() && bubble_events()) {
@@ -160,6 +162,9 @@
 }
 
 void UiElement::OnMove(const gfx::PointF& position) {
+  if (sounds_.move != kSoundNone && audio_delegate_) {
+    audio_delegate_->PlaySound(sounds_.move);
+  }
   if (event_handlers_.hover_move) {
     event_handlers_.hover_move.Run(position);
   } else if (parent() && bubble_events()) {
@@ -168,8 +173,8 @@
 }
 
 void UiElement::OnButtonDown(const gfx::PointF& position) {
-  if (hover_sound_id_ != kSoundNone && audio_delegate_) {
-    audio_delegate_->PlaySound(click_sound_id_);
+  if (sounds_.button_down != kSoundNone && audio_delegate_) {
+    audio_delegate_->PlaySound(sounds_.button_down);
   }
   if (event_handlers_.button_down) {
     event_handlers_.button_down.Run();
@@ -179,6 +184,9 @@
 }
 
 void UiElement::OnButtonUp(const gfx::PointF& position) {
+  if (sounds_.button_up != kSoundNone && audio_delegate_) {
+    audio_delegate_->PlaySound(sounds_.button_up);
+  }
   if (event_handlers_.button_up) {
     event_handlers_.button_up.Run();
   } else if (parent() && bubble_events()) {
@@ -535,11 +543,8 @@
 }
 #endif
 
-void UiElement::SetSounds(SoundId hover,
-                          SoundId click,
-                          AudioDelegate* delegate) {
-  hover_sound_id_ = hover;
-  click_sound_id_ = click;
+void UiElement::SetSounds(Sounds sounds, AudioDelegate* delegate) {
+  sounds_ = sounds;
   audio_delegate_ = delegate;
 }
 
diff --git a/chrome/browser/vr/elements/ui_element.h b/chrome/browser/vr/elements/ui_element.h
index c47278b..9e1026f 100644
--- a/chrome/browser/vr/elements/ui_element.h
+++ b/chrome/browser/vr/elements/ui_element.h
@@ -24,6 +24,7 @@
 #include "chrome/browser/vr/elements/ui_element_type.h"
 #include "chrome/browser/vr/model/camera_model.h"
 #include "chrome/browser/vr/model/reticle_model.h"
+#include "chrome/browser/vr/model/sounds.h"
 #include "chrome/browser/vr/target_property.h"
 #include "ui/gfx/geometry/point3_f.h"
 #include "ui/gfx/geometry/quaternion.h"
@@ -472,7 +473,7 @@
 
   // Set the sounds that play when an applicable handler is executed.  Elements
   // that override element hover and click methods must manage their own sounds.
-  void SetSounds(SoundId hover, SoundId click, AudioDelegate* delegate);
+  void SetSounds(Sounds sounds, AudioDelegate* delegate);
 
   bool resizable_by_layout() { return resizable_by_layout_; }
   void set_resizable_by_layout(bool resizable) {
@@ -608,8 +609,7 @@
   UpdatePhase phase_ = kClean;
 
   AudioDelegate* audio_delegate_ = nullptr;
-  SoundId hover_sound_id_ = kSoundNone;
-  SoundId click_sound_id_ = kSoundNone;
+  Sounds sounds_;
 
   // Indicates that this element may be resized by parent layout elements.
   bool resizable_by_layout_ = false;
diff --git a/chrome/browser/vr/model/sounds.h b/chrome/browser/vr/model/sounds.h
new file mode 100644
index 0000000..45e4e21
--- /dev/null
+++ b/chrome/browser/vr/model/sounds.h
@@ -0,0 +1,22 @@
+// 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 CHROME_BROWSER_VR_MODEL_SOUNDS_H_
+#define CHROME_BROWSER_VR_MODEL_SOUNDS_H_
+
+#include "chrome/browser/vr/model/sound_id.h"
+
+namespace vr {
+
+struct Sounds {
+  SoundId hover_enter = kSoundNone;
+  SoundId hover_leave = kSoundNone;
+  SoundId button_down = kSoundNone;
+  SoundId button_up = kSoundNone;
+  SoundId move = kSoundNone;
+};
+
+}  // namespace vr
+
+#endif  // CHROME_BROWSER_VR_MODEL_SOUNDS_H_
diff --git a/chrome/browser/vr/ui_scene_creator.cc b/chrome/browser/vr/ui_scene_creator.cc
index 24024f9..fd1175c48 100644
--- a/chrome/browser/vr/ui_scene_creator.cc
+++ b/chrome/browser/vr/ui_scene_creator.cc
@@ -126,6 +126,13 @@
   return element;
 }
 
+Sounds CreateButtonSounds() {
+  Sounds sounds;
+  sounds.hover_enter = kSoundButtonHover;
+  sounds.button_down = kSoundButtonClick;
+  return sounds;
+}
+
 typedef VectorBinding<OmniboxSuggestion, Button> SuggestionSetBinding;
 typedef typename SuggestionSetBinding::ElementBinding SuggestionBinding;
 
@@ -200,7 +207,7 @@
   background->set_bubble_events(true);
   background->set_bounds_contain_children(true);
   background->set_hover_offset(0.0);
-  background->SetSounds(kSoundButtonHover, kSoundButtonClick, audio_delegate);
+  background->SetSounds(CreateButtonSounds(), audio_delegate);
   VR_BIND_BUTTON_COLORS(model, background.get(),
                         &ColorScheme::suggestion_button_colors,
                         &Button::SetButtonColors);
@@ -1080,6 +1087,9 @@
   plane->set_bounds_contain_padding(false);
   plane->set_corner_radius(kContentCornerRadius);
   plane->set_cursor_type(kCursorReposition);
+  Sounds sounds;
+  sounds.button_up = kSoundButtonClick;
+  plane->SetSounds(sounds, audio_delegate_);
   plane->set_padding(0, kRepositionFrameHitPlaneTopPadding, 0, 0);
   plane->set_event_handlers(CreateRepositioningHandlers(model_, scene_));
 
@@ -1566,6 +1576,9 @@
   hit_plane->SetSize(kSceneSize, kSceneSize);
   hit_plane->SetTranslate(0.0f, 0.0f, -kContentDistance);
   hit_plane->set_cursor_type(kCursorReposition);
+  Sounds sounds;
+  sounds.button_up = kSoundButtonClick;
+  hit_plane->SetSounds(sounds, audio_delegate_);
   EventHandlers event_handlers;
   event_handlers.button_up = base::BindRepeating(
       [](Model* m) {
@@ -1758,7 +1771,7 @@
   back_button->SetCornerRadii(
       {kUrlBarHeightDMM / 2, 0, kUrlBarHeightDMM / 2, 0});
   back_button->set_hover_offset(0.0f);
-  back_button->SetSounds(kSoundButtonHover, kSoundButtonClick, audio_delegate_);
+  back_button->SetSounds(CreateButtonSounds(), audio_delegate_);
   back_button->AddBinding(VR_BIND_FUNC(bool, Model, model_,
                                        model->can_navigate_back, Button,
                                        back_button.get(), set_enabled));
@@ -1862,8 +1875,7 @@
   overflow_button->SetCornerRadii(
       {0, kUrlBarHeightDMM / 2, 0, kUrlBarHeightDMM / 2});
   overflow_button->set_hover_offset(0.0f);
-  overflow_button->SetSounds(kSoundButtonHover, kSoundButtonClick,
-                             audio_delegate_);
+  overflow_button->SetSounds(CreateButtonSounds(), audio_delegate_);
   VR_BIND_BUTTON_COLORS(model_, overflow_button.get(),
                         &ColorScheme::back_button, &Button::SetButtonColors);
   scene_->AddUiElement(kUrlBarLayout, std::move(overflow_button));
@@ -2276,7 +2288,7 @@
                       kOmniboxTextFieldIconButtonSizeDMM);
   mic_button->set_hover_offset(kOmniboxTextFieldIconButtonHoverOffsetDMM);
   mic_button->set_corner_radius(kUrlBarItemCornerRadiusDMM);
-  mic_button->SetSounds(kSoundButtonHover, kSoundButtonClick, audio_delegate_);
+  mic_button->SetSounds(CreateButtonSounds(), audio_delegate_);
 
   VR_BIND_VISIBILITY(mic_button,
                      model->speech.has_or_can_request_audio_permission &&
diff --git a/chrome/common/channel_info.cc b/chrome/common/channel_info.cc
index 0eba8de..7345984 100644
--- a/chrome/common/channel_info.cc
+++ b/chrome/common/channel_info.cc
@@ -10,7 +10,7 @@
 namespace chrome {
 
 std::string GetVersionString() {
-  return version_info::GetVersionStringWithModifier(GetChannelString());
+  return version_info::GetVersionStringWithModifier(GetChannelName());
 }
 
 }  // namespace chrome
diff --git a/chrome/common/channel_info.h b/chrome/common/channel_info.h
index 010de41..89c5e00 100644
--- a/chrome/common/channel_info.h
+++ b/chrome/common/channel_info.h
@@ -26,9 +26,9 @@
 // In branded builds, when the channel cannot be determined, "unknown" will
 // be returned. In unbranded builds, the modifier is usually an empty string
 // (""), although on Linux, it may vary in certain distributions.
-// GetChannelString() is intended to be used for display purposes.
+// GetChannelName() is intended to be used for display purposes.
 // To simply test the channel, use GetChannel().
-std::string GetChannelString();
+std::string GetChannelName();
 
 // Returns the channel for the installation. In branded builds, this will be
 // version_info::Channel::{STABLE,BETA,DEV,CANARY}. In unbranded builds, or
@@ -36,6 +36,14 @@
 // version_info::Channel::UNKNOWN.
 version_info::Channel GetChannel();
 
+#if defined(OS_MACOSX)
+// Maps the name of the channel to version_info::Channel, always returning
+// Channel::UNKNOWN for unbranded builds. For branded builds defaults to
+// Channel::STABLE, if channel is empty, else matches the name and returns
+// {STABLE,BETA,DEV,CANARY, UNKNOWN}.
+version_info::Channel GetChannelByName(const std::string& channel);
+#endif
+
 #if defined(OS_CHROMEOS)
 // Sets channel before use.
 void SetChannel(const std::string& channel);
diff --git a/chrome/common/channel_info_android.cc b/chrome/common/channel_info_android.cc
index 53e4db4..478ffd7 100644
--- a/chrome/common/channel_info_android.cc
+++ b/chrome/common/channel_info_android.cc
@@ -12,7 +12,7 @@
 
 namespace chrome {
 
-std::string GetChannelString() {
+std::string GetChannelName() {
   switch (GetChannel()) {
     case version_info::Channel::UNKNOWN: return "unknown";
     case version_info::Channel::CANARY: return "canary";
diff --git a/chrome/common/channel_info_chromeos.cc b/chrome/common/channel_info_chromeos.cc
index 38e8cd3..e301bc4 100644
--- a/chrome/common/channel_info_chromeos.cc
+++ b/chrome/common/channel_info_chromeos.cc
@@ -10,7 +10,7 @@
 
 static version_info::Channel chromeos_channel = version_info::Channel::UNKNOWN;
 
-std::string GetChannelString() {
+std::string GetChannelName() {
 #if defined(GOOGLE_CHROME_BUILD)
   switch (chromeos_channel) {
     case version_info::Channel::STABLE:
diff --git a/chrome/common/channel_info_mac.mm b/chrome/common/channel_info_mac.mm
index d2cb34d4a..01246349 100644
--- a/chrome/common/channel_info_mac.mm
+++ b/chrome/common/channel_info_mac.mm
@@ -12,7 +12,7 @@
 
 namespace chrome {
 
-std::string GetChannelString() {
+std::string GetChannelName() {
 #if defined(GOOGLE_CHROME_BUILD)
   // Use the main Chrome application bundle and not the framework bundle.
   // Keystone keys don't live in the framework.
@@ -41,9 +41,9 @@
 #endif
 }
 
-version_info::Channel GetChannel() {
+version_info::Channel GetChannelByName(const std::string& channel) {
 #if defined(GOOGLE_CHROME_BUILD)
-  std::string channel = GetChannelString();
+
   if (channel.empty()) {
     return version_info::Channel::STABLE;
   } else if (channel == "beta") {
@@ -58,4 +58,8 @@
   return version_info::Channel::UNKNOWN;
 }
 
+version_info::Channel GetChannel() {
+  return GetChannelByName(GetChannelName());
+}
+
 }  // namespace chrome
diff --git a/chrome/common/channel_info_posix.cc b/chrome/common/channel_info_posix.cc
index 2b4e9792..7978d18 100644
--- a/chrome/common/channel_info_posix.cc
+++ b/chrome/common/channel_info_posix.cc
@@ -53,7 +53,7 @@
 
 }  // namespace
 
-std::string GetChannelString() {
+std::string GetChannelName() {
   std::string modifier;
   GetChannelImpl(&modifier, nullptr);
   return modifier;
diff --git a/chrome/common/channel_info_win.cc b/chrome/common/channel_info_win.cc
index 40d452a..a15dec0 100644
--- a/chrome/common/channel_info_win.cc
+++ b/chrome/common/channel_info_win.cc
@@ -11,7 +11,7 @@
 
 namespace chrome {
 
-std::string GetChannelString() {
+std::string GetChannelName() {
 #if defined(GOOGLE_CHROME_BUILD)
   base::string16 channel(install_static::GetChromeChannelName());
 #if defined(SYZYASAN)
diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc
index 9d1b909..0eca654 100644
--- a/chrome/common/pref_names.cc
+++ b/chrome/common/pref_names.cc
@@ -2538,6 +2538,9 @@
 #if !defined(OS_ANDROID)
 // Boolean that specifies whether media (audio/video) autoplay is allowed.
 const char kAutoplayAllowed[] = "media.autoplay_allowed";
+
+// Holds URL patterns that specify URLs that will be allowed to autoplay.
+const char kAutoplayWhitelist[] = "media.autoplay_whitelist";
 #endif  // !defined(OS_ANDROID)
 
 }  // namespace prefs
diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h
index 9fabc5b..b4a7eb0 100644
--- a/chrome/common/pref_names.h
+++ b/chrome/common/pref_names.h
@@ -911,6 +911,7 @@
 
 #if !defined(OS_ANDROID)
 extern const char kAutoplayAllowed[];
+extern const char kAutoplayWhitelist[];
 #endif
 
 }  // namespace prefs
diff --git a/chrome/common/webui_url_constants.cc b/chrome/common/webui_url_constants.cc
index 94844462..cb71167 100644
--- a/chrome/common/webui_url_constants.cc
+++ b/chrome/common/webui_url_constants.cc
@@ -35,8 +35,6 @@
 const char kChromeUIComponentsHost[] = "components";
 const char kChromeUIConflictsHost[] = "conflicts";
 const char kChromeUIConflictsURL[] = "chrome://conflicts/";
-const char kChromeUIConnectionHelpHost[] = "connection-help";
-const char kChromeUIConnectionHelpURL[] = "chrome://connection-help";
 const char kChromeUIConstrainedHTMLTestURL[] = "chrome://constrained-test/";
 const char kChromeUIContentSettingsURL[] = "chrome://settings/content";
 const char kChromeUICrashHost[] = "crash";
diff --git a/chrome/common/webui_url_constants.h b/chrome/common/webui_url_constants.h
index 3d601a7..0c22d762 100644
--- a/chrome/common/webui_url_constants.h
+++ b/chrome/common/webui_url_constants.h
@@ -42,8 +42,6 @@
 extern const char kChromeUIComponentsHost[];
 extern const char kChromeUIConflictsHost[];
 extern const char kChromeUIConflictsURL[];
-extern const char kChromeUIConnectionHelpHost[];
-extern const char kChromeUIConnectionHelpURL[];
 extern const char kChromeUIConstrainedHTMLTestURL[];
 extern const char kChromeUIContentSettingsURL[];
 extern const char kChromeUICrashHost[];
diff --git a/chrome/renderer/chrome_content_renderer_client.cc b/chrome/renderer/chrome_content_renderer_client.cc
index d6fee0d..e8c0ec3 100644
--- a/chrome/renderer/chrome_content_renderer_client.cc
+++ b/chrome/renderer/chrome_content_renderer_client.cc
@@ -1443,15 +1443,6 @@
 #endif
 }
 
-bool ChromeContentRendererClient::ShouldGatherSiteIsolationStats() const {
-  // Site isolation stats are gathered currently for non-extension renderer
-  // processes running a normal web page from the Internet.
-  // TODO(nick): https://crbug.com/268640 Gather stats for extension processes
-  // too; we would need to check the extension's manifest to know which sites
-  // it's allowed to access.
-  return !IsStandaloneExtensionProcess();
-}
-
 std::unique_ptr<blink::WebContentSettingsClient>
 ChromeContentRendererClient::CreateWorkerContentSettingsClient(
     content::RenderFrame* render_frame) {
diff --git a/chrome/renderer/chrome_content_renderer_client.h b/chrome/renderer/chrome_content_renderer_client.h
index 1b30fe68..c6ec0e87 100644
--- a/chrome/renderer/chrome_content_renderer_client.h
+++ b/chrome/renderer/chrome_content_renderer_client.h
@@ -176,7 +176,6 @@
       blink::WebSpeechSynthesizerClient* client) override;
   bool ShouldReportDetailedMessageForSource(
       const base::string16& source) const override;
-  bool ShouldGatherSiteIsolationStats() const override;
   std::unique_ptr<blink::WebContentSettingsClient>
   CreateWorkerContentSettingsClient(
       content::RenderFrame* render_frame) override;
diff --git a/chrome/renderer/url_loader_throttle_provider_impl.cc b/chrome/renderer/url_loader_throttle_provider_impl.cc
index e151989..4263abda 100644
--- a/chrome/renderer/url_loader_throttle_provider_impl.cc
+++ b/chrome/renderer/url_loader_throttle_provider_impl.cc
@@ -46,6 +46,22 @@
   return canceler->get();
 }
 
+void PrerenderThrottleDestructed(
+    scoped_refptr<base::SingleThreadTaskRunner> task_runner,
+    prerender::PrerenderDispatcher* prerender_dispatcher) {
+  // http://crbug.com/823306: nostateprefetch shouldn't be executing XHR since
+  // it's not supposed to be running scripts.
+  if (!task_runner->BelongsToCurrentThread()) {
+    task_runner->PostTask(
+        FROM_HERE,
+        base::BindOnce(&prerender::PrerenderDispatcher::DecrementPrefetchCount,
+                       base::Unretained(prerender_dispatcher)));
+    return;
+  }
+
+  prerender_dispatcher->DecrementPrefetchCount();
+}
+
 }  // namespace
 
 URLLoaderThrottleProviderImpl::URLLoaderThrottleProviderImpl(
@@ -116,8 +132,8 @@
             chrome_content_renderer_client_->prerender_dispatcher();
         prerender_dispatcher->IncrementPrefetchCount();
         throttle->set_destruction_closure(base::BindOnce(
-            &prerender::PrerenderDispatcher::DecrementPrefetchCount,
-            base::Unretained(prerender_dispatcher)));
+            PrerenderThrottleDestructed,
+            base::MessageLoop::current()->task_runner(), prerender_dispatcher));
       }
       throttles.push_back(std::move(throttle));
     }
diff --git a/chrome/test/data/media/autoplay_iframe.html b/chrome/test/data/media/autoplay_iframe.html
new file mode 100644
index 0000000..37a32057
--- /dev/null
+++ b/chrome/test/data/media/autoplay_iframe.html
@@ -0,0 +1,21 @@
+<html>
+<head>
+<title>Autoplay Test Page</title>
+</head>
+<body>
+<iframe id=subframe></iframe>
+<video id=video>
+  <source src=bigbuck.webm type=video/webm />
+</video>
+<script>
+function tryPlayback() {
+  const video = document.getElementById('video');
+  video.play().then(() => {
+    window.domAutomationController.send(true);
+  }, (e) => {
+    window.domAutomationController.send(e.name != 'NotAllowedError');
+  });
+}
+</script>
+</body>
+</html>
diff --git a/chrome/test/data/policy/policy_test_cases.json b/chrome/test/data/policy/policy_test_cases.json
index e245f30..d3b02f5 100644
--- a/chrome/test/data/policy/policy_test_cases.json
+++ b/chrome/test/data/policy/policy_test_cases.json
@@ -3633,6 +3633,18 @@
     ]
   },
 
+  "AutoplayWhitelist": {
+    "os": ["win", "linux", "mac", "chromeos"],
+    "test_policy": {
+      "AutoplayWhitelist": [
+        "https://mydomain.com", "https://test.mydomain.com"
+      ]
+    },
+    "pref_mappings": [
+      { "pref": "media.autoplay_whitelist" }
+    ]
+  },
+
   "----- Chrome Frame policies -------------------------------------------": {},
 
   "ChromeFrameRendererSettings": {
diff --git a/chromecast/browser/cast_browser_main_parts.cc b/chromecast/browser/cast_browser_main_parts.cc
index 5daa3fd4..807392c 100644
--- a/chromecast/browser/cast_browser_main_parts.cc
+++ b/chromecast/browser/cast_browser_main_parts.cc
@@ -254,6 +254,8 @@
     // Enable autoplay without requiring any user gesture.
     {switches::kAutoplayPolicy,
      switches::autoplay::kNoUserGestureRequiredPolicy},
+    // Disable pinch zoom gesture.
+    {switches::kDisablePinch, ""},
 };
 
 void AddDefaultCommandLineSwitches(base::CommandLine* command_line) {
diff --git a/components/password_manager/content/common/credential_manager_mojom_traits.cc b/components/password_manager/content/common/credential_manager_mojom_traits.cc
index e0e3a3f..8592c8d 100644
--- a/components/password_manager/content/common/credential_manager_mojom_traits.cc
+++ b/components/password_manager/content/common/credential_manager_mojom_traits.cc
@@ -4,6 +4,7 @@
 
 #include "components/password_manager/content/common/credential_manager_mojom_traits.h"
 
+#include "mojo/public/cpp/base/string16_mojom_traits.h"
 #include "url/mojom/origin_mojom_traits.h"
 #include "url/mojom/url_gurl_mojom_traits.h"
 
diff --git a/components/password_manager/content/common/credential_manager_mojom_traits.h b/components/password_manager/content/common/credential_manager_mojom_traits.h
index 23b982e..4748e17 100644
--- a/components/password_manager/content/common/credential_manager_mojom_traits.h
+++ b/components/password_manager/content/common/credential_manager_mojom_traits.h
@@ -5,6 +5,7 @@
 #ifndef COMPONENTS_PASSWORD_MANAGER_CONTENT_COMMON_CREDENTIAL_MANAGER_MOJOM_TRAITS_H_
 #define COMPONENTS_PASSWORD_MANAGER_CONTENT_COMMON_CREDENTIAL_MANAGER_MOJOM_TRAITS_H_
 
+#include "base/optional.h"
 #include "base/strings/string16.h"
 #include "components/password_manager/core/common/credential_manager_types.h"
 #include "mojo/public/cpp/bindings/struct_traits.h"
@@ -48,11 +49,13 @@
     return r.type;
   }
 
-  static const base::string16& id(const password_manager::CredentialInfo& r) {
+  static const base::Optional<base::string16>& id(
+      const password_manager::CredentialInfo& r) {
     return r.id;
   }
 
-  static const base::string16& name(const password_manager::CredentialInfo& r) {
+  static const base::Optional<base::string16>& name(
+      const password_manager::CredentialInfo& r) {
     return r.name;
   }
 
@@ -60,7 +63,7 @@
     return r.icon;
   }
 
-  static const base::string16& password(
+  static const base::Optional<base::string16>& password(
       const password_manager::CredentialInfo& r) {
     return r.password;
   }
diff --git a/components/password_manager/core/common/credential_manager_types.cc b/components/password_manager/core/common/credential_manager_types.cc
index 068d3ac7..f0cbe7b 100644
--- a/components/password_manager/core/common/credential_manager_types.cc
+++ b/components/password_manager/core/common/credential_manager_types.cc
@@ -72,11 +72,11 @@
 
   form.reset(new autofill::PasswordForm);
   form->icon_url = info.icon;
-  form->display_name = info.name;
+  form->display_name = info.name.value_or(base::string16());
   form->federation_origin = info.federation;
   form->origin = origin;
-  form->password_value = info.password;
-  form->username_value = info.id;
+  form->password_value = info.password.value_or(base::string16());
+  form->username_value = info.id.value_or(base::string16());
   form->scheme = autofill::PasswordForm::SCHEME_HTML;
   form->type = autofill::PasswordForm::TYPE_API;
 
@@ -84,7 +84,6 @@
       info.type == CredentialType::CREDENTIAL_TYPE_PASSWORD
           ? origin.spec()
           : "federation://" + origin.host() + "/" + info.federation.host();
-  form->username_value = info.id;
   return form;
 }
 
diff --git a/components/password_manager/core/common/credential_manager_types.h b/components/password_manager/core/common/credential_manager_types.h
index cc2a6d5..aa37364e 100644
--- a/components/password_manager/core/common/credential_manager_types.h
+++ b/components/password_manager/core/common/credential_manager_types.h
@@ -12,6 +12,7 @@
 #include <string>
 
 #include "base/compiler_specific.h"
+#include "base/optional.h"
 #include "base/strings/string16.h"
 #include "url/gurl.h"
 #include "url/origin.h"
@@ -57,18 +58,18 @@
 
   // An identifier (username, email address, etc). Corresponds to
   // WebCredential's id property.
-  base::string16 id;
+  base::Optional<base::string16> id;
 
   // An user-friendly name ("Jane Doe"). Corresponds to WebCredential's name
   // property.
-  base::string16 name;
+  base::Optional<base::string16> name;
 
   // The address of this credential's icon (e.g. the user's avatar).
   // Corresponds to WebCredential's icon property.
   GURL icon;
 
   // Corresponds to WebPasswordCredential's password property.
-  base::string16 password;
+  base::Optional<base::string16> password;
 
   // Corresponds to WebFederatedCredential's provider property.
   url::Origin federation;
diff --git a/components/policy/resources/policy_templates.json b/components/policy/resources/policy_templates.json
index 2a42008..96b9846 100644
--- a/components/policy/resources/policy_templates.json
+++ b/components/policy/resources/policy_templates.json
@@ -145,7 +145,7 @@
 #   persistent IDs for all fields (but not for groups!) are needed. These are
 #   specified by the 'id' keys of each policy. NEVER CHANGE EXISTING IDs,
 #   because doing so would break the deployed wire format!
-#   For your editing convenience: highest ID currently used: 430
+#   For your editing convenience: highest ID currently used: 431
 #   And don't forget to also update the EnterprisePolicies enum of
 #   histograms.xml (run 'python tools/metrics/histograms/update_policies.py').
 #
@@ -11509,11 +11509,39 @@
       'desc': '''Allows you to control if videos can play automatically (without user consent) with audio content in <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph>.
 
       If the policy is set to True, <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> is allowed to autoplay media.
-      If the policy is set to False, <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> is not allowed to autoplay media.
-      By default, <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> is not allowed to autoplay media.
+      If the policy is set to False, <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> is not allowed to autoplay media. The AutoplayWhitelist policy can be used to override this for certain URL patterns.
+      By default, <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> is not allowed to autoplay media. The AutoplayWhitelist policy can be used to override this for certain URL patterns.
 
       Note that if <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> is running and this policy changes, it will be applied only to new opened tabs. Therefore some tabs might still observe the previous behavior.
       ''',
+    },
+    {
+      'name': 'AutoplayWhitelist',
+      'type': 'list',
+      'schema': {
+        'type': 'array',
+        'items': { 'type': 'string' },
+      },
+      'supported_on': ['chrome.*:66-', 'chrome_os:66-'],
+      'features': {
+        'dynamic_refresh': True,
+        'per_profile': True,
+      },
+      'example_value': ['https://example.com', 'https://www.chromium.org'],
+      'id': 431,
+      'caption': '''Allows media autoplay on a whitelist of URL patterns''',
+      'tags': [],
+      'desc': '''Controls the whitelist of URL patterns that autoplay will always be enabled on.
+
+      If autoplay is enabled then videos can play automatically (without user consent) with audio content in <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph>.
+
+      A URL pattern has to be formatted according to https://www.chromium.org/administrators/url-blacklist-filter-format.
+
+      If the AutoplayAllowed policy is set to True then this policy will have no effect.
+
+      If the AutoplayAllowed policy is set to False then any URL patterns set in this policy will still be allowed to play.
+
+      Note that if <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> is running and this policy changes, it will be applied only to new opened tabs. Therefore some tabs might still observe the previous behavior.''',
     }
   ],
 
diff --git a/components/resources/security_interstitials_resources.grdp b/components/resources/security_interstitials_resources.grdp
index 1ca9152..d290349 100644
--- a/components/resources/security_interstitials_resources.grdp
+++ b/components/resources/security_interstitials_resources.grdp
@@ -1,8 +1,11 @@
 <?xml version="1.0" encoding="utf-8"?>
 <grit-part>
-  <include name="IDR_SECURITY_INTERSTITIAL_COMMON_CSS" file="../security_interstitials/core/common/resources/interstitial_common.css" type="BINDATA" />
-  <include name="IDR_SECURITY_INTERSTITIAL_CORE_CSS" file="../security_interstitials/core/common/resources/interstitial_core.css" type="BINDATA" />
+  <include name="IDR_SECURITY_INTERSTITIAL_COMMON_CSS" file="../security_interstitials/core/common/resources/interstitial_common.css" compress="gzip" type="BINDATA" />
+  <include name="IDR_SECURITY_INTERSTITIAL_CORE_CSS" file="../security_interstitials/core/common/resources/interstitial_core.css" compress="gzip" type="BINDATA" />
   <include name="IDR_SECURITY_INTERSTITIAL_UI_HTML" file="../security_interstitials/core/browser/resources/list_of_interstitials.html" flattenhtml="true" type="BINDATA" />
   <include name="IDR_SECURITY_INTERSTITIAL_HTML" file="../security_interstitials/core/browser/resources/interstitial_large.html" flattenhtml="true" type="BINDATA" />
   <include name="IDR_SECURITY_INTERSTITIAL_QUIET_HTML" file="../security_interstitials/core/browser/resources/interstitial_webview_quiet.html" flattenhtml="true" type="BINDATA" />
+  <include name="IDR_SECURITY_INTERSTITIAL_CONNECTION_HELP_HTML" file="../security_interstitials/content/resources/connection_help.html" compress="gzip" type="BINDATA" />
+  <include name="IDR_SECURITY_INTERSTITIAL_CONNECTION_HELP_CSS" file="../security_interstitials/content/resources/connection_help.css" compress="gzip" type="BINDATA" />
+  <include name="IDR_SECURITY_INTERSTITIAL_CONNECTION_HELP_JS" file="../security_interstitials/content/resources/connection_help.js" compress="gzip" type="BINDATA" />
 </grit-part>
diff --git a/components/security_interstitials/content/BUILD.gn b/components/security_interstitials/content/BUILD.gn
index 022d556..b3f383e 100644
--- a/components/security_interstitials/content/BUILD.gn
+++ b/components/security_interstitials/content/BUILD.gn
@@ -4,12 +4,16 @@
 
 static_library("security_interstitial_page") {
   sources = [
+    "connection_help_ui.cc",
+    "connection_help_ui.h",
     "security_interstitial_controller_client.cc",
     "security_interstitial_controller_client.h",
     "security_interstitial_page.cc",
     "security_interstitial_page.h",
     "unsafe_resource.cc",
     "unsafe_resource.h",
+    "urls.cc",
+    "urls.h",
   ]
 
   public_deps = [
@@ -24,6 +28,7 @@
     "//components/safe_browsing/db:hit_report",
     "//components/safe_browsing/db:util",
     "//components/security_interstitials/core:core",
+    "//components/strings:components_strings_grit",
     "//content/public/browser",
     "//content/public/common",
   ]
diff --git a/components/security_interstitials/content/connection_help_ui.cc b/components/security_interstitials/content/connection_help_ui.cc
new file mode 100644
index 0000000..980f96a
--- /dev/null
+++ b/components/security_interstitials/content/connection_help_ui.cc
@@ -0,0 +1,76 @@
+// 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 "components/security_interstitials/content/connection_help_ui.h"
+
+#include "components/grit/components_resources.h"
+#include "components/security_interstitials/content/urls.h"
+#include "components/strings/grit/components_strings.h"
+#include "content/public/browser/browser_context.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_ui.h"
+#include "content/public/browser/web_ui_data_source.h"
+#include "ui/base/l10n/l10n_util.h"
+
+namespace security_interstitials {
+
+ConnectionHelpUI::ConnectionHelpUI(content::WebUI* web_ui)
+    : content::WebUIController(web_ui) {
+  content::WebUIDataSource* html_source =
+      content::WebUIDataSource::Create(kChromeUIConnectionHelpHost);
+
+  html_source->AddLocalizedString("connectionHelpTitle",
+                                  IDS_CONNECTION_HELP_TITLE);
+  html_source->AddLocalizedString("connectionHelpHeading",
+                                  IDS_CONNECTION_HELP_HEADING);
+  html_source->AddLocalizedString("connectionHelpGeneralHelp",
+                                  IDS_CONNECTION_HELP_GENERAL_HELP);
+  html_source->AddLocalizedString("connectionHelpSpecificErrorHeading",
+                                  IDS_CONNECTION_HELP_SPECIFIC_ERROR_HEADING);
+  html_source->AddLocalizedString(
+      "connectionHelpConnectionNotPrivateTitle",
+      IDS_CONNECTION_HELP_CONNECTION_NOT_PRIVATE_TITLE);
+  html_source->AddLocalizedString(
+      "connectionHelpConnectionNotPrivateDetails",
+      IDS_CONNECTION_HELP_CONNECTION_NOT_PRIVATE_DETAILS);
+  html_source->AddLocalizedString("connectionHelpConnectToNetworkTitle",
+                                  IDS_CONNECTION_HELP_CONNECT_TO_NETWORK_TITLE);
+  html_source->AddLocalizedString(
+      "connectionHelpConnectToNetworkDetails",
+      IDS_CONNECTION_HELP_CONNECT_TO_NETWORK_DETAILS);
+  html_source->AddLocalizedString("connectionHelpIncorrectClockTitle",
+                                  IDS_CONNECTION_HELP_INCORRECT_CLOCK_TITLE);
+  html_source->AddLocalizedString("connectionHelpIncorrectClockDetails",
+                                  IDS_CONNECTION_HELP_INCORRECT_CLOCK_DETAILS);
+  html_source->AddLocalizedString("connectionHelpMitmSoftwareTitle",
+                                  IDS_CONNECTION_HELP_MITM_SOFTWARE_TITLE);
+  html_source->AddLocalizedString("connectionHelpMitmSoftwareDetails",
+                                  IDS_CONNECTION_HELP_MITM_SOFTWARE_DETAILS);
+  html_source->AddLocalizedString("connectionHelpShowMore",
+                                  IDS_CONNECTION_HELP_SHOW_MORE);
+  html_source->AddLocalizedString("connectionHelpShowLess",
+                                  IDS_CONNECTION_HELP_SHOW_LESS);
+
+  html_source->SetJsonPath("strings.js");
+
+  html_source->AddResourcePath("interstitial_core.css",
+                               IDR_SECURITY_INTERSTITIAL_CORE_CSS);
+  html_source->AddResourcePath("interstitial_common.css",
+                               IDR_SECURITY_INTERSTITIAL_COMMON_CSS);
+  html_source->AddResourcePath("connection_help.css",
+                               IDR_SECURITY_INTERSTITIAL_CONNECTION_HELP_CSS);
+  html_source->AddResourcePath("connection_help.js",
+                               IDR_SECURITY_INTERSTITIAL_CONNECTION_HELP_JS);
+  html_source->SetDefaultResource(
+      IDR_SECURITY_INTERSTITIAL_CONNECTION_HELP_HTML);
+  html_source->UseGzip();
+
+  content::BrowserContext* browser_context =
+      web_ui->GetWebContents()->GetBrowserContext();
+  content::WebUIDataSource::Add(browser_context, html_source);
+}
+
+ConnectionHelpUI::~ConnectionHelpUI() {}
+
+}  // namespace security_interstitials
diff --git a/components/security_interstitials/content/connection_help_ui.h b/components/security_interstitials/content/connection_help_ui.h
new file mode 100644
index 0000000..ca3e79f
--- /dev/null
+++ b/components/security_interstitials/content/connection_help_ui.h
@@ -0,0 +1,27 @@
+// 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 COMPONENTS_SECURITY_INTERSTITIALS_CONTENT_CONNECTION_HELP_UI_H_
+#define COMPONENTS_SECURITY_INTERSTITIALS_CONTENT_CONNECTION_HELP_UI_H_
+
+#include "base/macros.h"
+#include "content/public/browser/web_ui_controller.h"
+
+namespace security_interstitials {
+
+// The WebUI for chrome://connection-help, which provides help content to users
+// with network configuration problems that prevent them from making secure
+// connections.
+class ConnectionHelpUI : public content::WebUIController {
+ public:
+  explicit ConnectionHelpUI(content::WebUI* web_ui);
+  ~ConnectionHelpUI() override;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ConnectionHelpUI);
+};
+
+}  // namespace security_interstitials
+
+#endif  // COMPONENTS_SECURITY_INTERSTITIALS_CONTENT_CONNECTION_HELP_UI_H_
diff --git a/components/security_interstitials/content/resources/connection_help.css b/components/security_interstitials/content/resources/connection_help.css
new file mode 100644
index 0000000..f963ca4
--- /dev/null
+++ b/components/security_interstitials/content/resources/connection_help.css
@@ -0,0 +1,25 @@
+/* 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. */
+
+h2 {
+    margin-top: 2em;
+}
+
+ul.expandable li {
+    margin-bottom: 1em;
+    padding: 0.5em 0;
+}
+
+ul.expandable button {
+    background: rgba(0, 0, 0, 0);
+    border: 0;
+    color: rgb(105, 105, 105);
+    display: block;
+    float: none;
+    margin-top: 0.5em;
+    padding: 0;
+    text-align: left;
+    text-decoration: underline;
+    text-transform: uppercase;
+}
diff --git a/components/security_interstitials/content/resources/connection_help.html b/components/security_interstitials/content/resources/connection_help.html
new file mode 100644
index 0000000..a42fa384c
--- /dev/null
+++ b/components/security_interstitials/content/resources/connection_help.html
@@ -0,0 +1,54 @@
+<!DOCTYPE HTML>
+<html dir="$i18n{textdirection}">
+  <head>
+    <title>$i18n{connectionHelpTitle}</title>
+    <meta charset='utf-8'>
+    <meta name="viewport" content="initial-scale=1, minimum-scale=1, width=device-width">
+    <link rel="stylesheet" href="chrome://resources/css/text_defaults.css">
+    <link rel="stylesheet" href="interstitial_core.css">
+    <link rel="stylesheet" href="interstitial_common.css">
+    <link rel="stylesheet" href="connection_help.css">
+    <script src="chrome://resources/js/cr.js"></script>
+    <script src="chrome://resources/js/load_time_data.js"></script>
+    <script src="chrome://resources/js/util.js"></script>
+    <script src="strings.js"></script>
+    <script src="connection_help.js"></script>
+  </head>
+  <body>
+    <div class="interstitial-wrapper">
+      <h1>$i18n{connectionHelpHeading}</h1>
+      $i18nRaw{connectionHelpGeneralHelp}
+      <h2>$i18n{connectionHelpSpecificErrorHeading}</h2>
+      <ul class="expandable">
+        <li>
+          $i18nRaw{connectionHelpConnectionNotPrivateTitle}
+          <div id="details-certerror" class="hidden">
+            $i18nRaw{connectionHelpConnectionNotPrivateDetails}
+          </div>
+          <button id="details-certerror-button" class="small-link">$i18n{connectionHelpShowMore}</button>
+        </li>
+        <li>
+          $i18nRaw{connectionHelpConnectToNetworkTitle}
+          <div id="details-connectnetwork" class="hidden">
+            $i18nRaw{connectionHelpConnectToNetworkDetails}
+          </div>
+          <button id="details-connectnetwork-button" class="small-link">$i18n{connectionHelpShowMore}</button>
+        </li>
+        <li>
+          $i18nRaw{connectionHelpIncorrectClockTitle}
+          <div id="details-clock" class="hidden">
+            $i18nRaw{connectionHelpIncorrectClockDetails}
+          </div>
+          <button id="details-clock-button" class="small-link">$i18n{connectionHelpShowMore}</button>
+        </li>
+        <li>
+          $i18nRaw{connectionHelpMitmSoftwareTitle}
+          <div id="details-mitmsoftware" class="hidden">
+            $i18nRaw{connectionHelpMitmSoftwareDetails}
+          </div>
+          <button id="details-mitmsoftware-button" class="small-link">$i18n{connectionHelpShowMore}</button>
+        </li>
+      </ul>
+    </div>
+  </body>
+</html>
diff --git a/components/security_interstitials/content/resources/connection_help.js b/components/security_interstitials/content/resources/connection_help.js
new file mode 100644
index 0000000..cfe1740
--- /dev/null
+++ b/components/security_interstitials/content/resources/connection_help.js
@@ -0,0 +1,29 @@
+// 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.
+
+var HIDDEN_CLASS = 'hidden';
+
+function setupEvents() {
+  $('details-certerror-button').addEventListener('click', function(event) {
+    toggleHidden('details-certerror', 'details-certerror-button');
+  });
+  $('details-connectnetwork-button').addEventListener('click', function(event) {
+    toggleHidden('details-connectnetwork', 'details-connectnetwork-button');
+  });
+  $('details-clock-button').addEventListener('click', function(event) {
+    toggleHidden('details-clock', 'details-clock-button');
+  });
+  $('details-mitmsoftware-button').addEventListener('click', function(event) {
+    toggleHidden('details-mitmsoftware', 'details-mitmsoftware-button');
+  });
+}
+
+function toggleHidden(className, buttonName) {
+  var hiddenDetails = $(className).classList.toggle(HIDDEN_CLASS);
+  $(buttonName).innerText = hiddenDetails ?
+      loadTimeData.getString('connectionHelpShowMore') :
+      loadTimeData.getString('connectionHelpShowLess');
+}
+
+document.addEventListener('DOMContentLoaded', setupEvents);
diff --git a/components/security_interstitials/content/urls.cc b/components/security_interstitials/content/urls.cc
new file mode 100644
index 0000000..fc34cb9
--- /dev/null
+++ b/components/security_interstitials/content/urls.cc
@@ -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.
+
+#include "components/security_interstitials/content/urls.h"
+
+namespace security_interstitials {
+
+const char kChromeUIConnectionHelpHost[] = "connection-help";
+const char kChromeUIConnectionHelpURL[] = "chrome://connection-help";
+
+}  // namespace security_interstitials
diff --git a/components/security_interstitials/content/urls.h b/components/security_interstitials/content/urls.h
new file mode 100644
index 0000000..d5e6106
--- /dev/null
+++ b/components/security_interstitials/content/urls.h
@@ -0,0 +1,15 @@
+// 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 COMPONENTS_SECURITY_INTERSTITIALS_CONTENT_URLS_H_
+#define COMPONENTS_SECURITY_INTERSTITIALS_CONTENT_URLS_H_
+
+namespace security_interstitials {
+
+extern const char kChromeUIConnectionHelpHost[];
+extern const char kChromeUIConnectionHelpURL[];
+
+}  // namespace security_interstitials
+
+#endif  // COMPONENTS_SECURITY_INTERSTITIALS_CONTENT_URLS_H_
diff --git a/components/security_interstitials_strings.grdp b/components/security_interstitials_strings.grdp
index 4e853aa4..4f4752dc 100644
--- a/components/security_interstitials_strings.grdp
+++ b/components/security_interstitials_strings.grdp
@@ -302,23 +302,44 @@
   <message name="IDS_PHISHING_WEBVIEW_EXPLANATION_PARAGRAPH" desc="The explanation of why Safe Browsing has blocked the page. Allows the user to proceed using a link.">
     This content might try to trick you into installing software or revealing personal information. <ph name="BEGIN_LINK">&lt;a href="#" id="proceed-link"&gt;</ph>Show anyway<ph name="END_LINK">&lt;/a&gt;</ph>
   </message>
+  <message name="IDS_CONNECTION_HELP_SHOW_MORE" desc="The button label to expand sections for the chrome://connection-help site. Paired with IDS_CONNECTION_HELP_SHOW_LESS">
+    Show More
+  </message>
+  <message name="IDS_CONNECTION_HELP_SHOW_LESS" desc="The button label to collapse sections for the chrome://connection-help site. Paired with IDS_CONNECTION_HELP_SHOW_MORE">
+    Show Less
+  </message>
   <message name="IDS_CONNECTION_HELP_TITLE" desc="The title for the chrome://connection-help site">
     Connection Help
   </message>
-  <message name="IDS_CONNECTION_HELP_HTML" desc="The HTML for the chrome://connection-help site that is shown when visiting the online help center triggers an SSL interstitial, this is a simplified version of the content at https://support.google.com/chrome/answer/6098869.">
-    &lt;h1&gt;Fix connection errors&lt;/h1&gt;
-    &lt;p&gt;If you get an error message when you try to visit a website, try these fixes.&lt;/p&gt;
-    &lt;h2&gt;Fix most connection errors&lt;/h2&gt;
+  <message name="IDS_CONNECTION_HELP_HEADING" desc="The heading for chrome://connection-help. Matches the heading in https://support.google.com/chrome/answer/6098869">
+   Fix connection errors
+  </message>
+  <message name="IDS_CONNECTION_HELP_GENERAL_HELP" desc="First general help paragraph for chrome://connection-help. Matches the 'Fix most connection errors' section in https://support.google.com/chrome/answer/6098869">
     &lt;p&gt;If you try to visit a website and it doesn’t open, first try to fix the error with these troubleshooting steps:&lt;/p&gt;
     &lt;ol&gt;
     &lt;li&gt;Check the web address for typos.&lt;/li&gt;
     &lt;li&gt;Make sure your internet connection is working normally.&lt;/li&gt;
     &lt;li&gt;Contact the website owner.&lt;/li&gt;
     &lt;/ol&gt;
-    &lt;h2&gt;Get help with a specific error message&lt;/h2&gt;
-    &lt;h3&gt;"Your connection is not private" or "NET::ERR_CERT_AUTHORITY_INVALID" or "ERR_CERT_COMMON_NAME_INVALID" or "NET::ERR_CERT_WEAK_SIGNATURE_ALGORITHM" or "SSL certificate error"&lt;/h3&gt;
+  </message>
+  <message name="IDS_CONNECTION_HELP_SPECIFIC_ERROR_HEADING" desc="Heading for individual errors section in chrome://connection-help. Matches the heading for the specific error section in https://support.google.com/chrome/answer/6098869">
+    Get help with a specific error message
+  </message>
+  <message name="IDS_CONNECTION_HELP_CONNECTION_NOT_PRIVATE_TITLE" desc="Title for your connection is not private section in chrome://connection-help. Matches the heading for the third section in https://support.google.com/chrome/answer/6098869">
+    "Your connection is not private" or "&lt;span class="error-code"&gt;NET::ERR_CERT_AUTHORITY_INVALID&lt;/span&gt;" or "&lt;span class="error-code"&gt;ERR_CERT_COMMON_NAME_INVALID&lt;/span&gt;" or "&lt;span class="error-code"&gt;NET::ERR_CERT_WEAK_SIGNATURE_ALGORITHM&lt;/span&gt;" or "SSL certificate error"
+  </message>
+  <message name="IDS_CONNECTION_HELP_CONNECT_TO_NETWORK_TITLE" desc="Title for connect to network section in chrome://connection-help. Matches the heading for the fourth section in https://support.google.com/chrome/answer/6098869">
+    "Connect to network"
+  </message>
+  <message name="IDS_CONNECTION_HELP_INCORRECT_CLOCK_TITLE" desc="Title for incorrect clock section in chrome://connection-help. Matches the heading for the fifth section in https://support.google.com/chrome/answer/6098869">
+    "Your clock is behind" or "Your clock is ahead" or "&lt;span class="error-code"&gt;NET::ERR_CERT_DATE_INVALID&lt;/span&gt;"
+  </message>
+  <message name="IDS_CONNECTION_HELP_MITM_SOFTWARE_TITLE" desc="Title for MITM software section in chrome://connection-help. Matches the heading for the eight section in https://support.google.com/chrome/answer/6098869">
+    "Software on your computer is stopping Chrome from safely connecting to the web" (Windows computers only)
+  </message>
+  <message name="IDS_CONNECTION_HELP_CONNECTION_NOT_PRIVATE_DETAILS" desc="Details for your connection is not private section in chrome://connection-help. Matches the third section in https://support.google.com/chrome/answer/6098869">
     &lt;h4&gt;Step 1: Sign in to the portal&lt;/h4&gt;
-    &lt;p&gt;Wi-Fi networks at places like cafes or airports need you to sign in. To see the sign-in page, visit a page that uses&lt;code&gt;http://&lt;/code&gt;.&lt;/p&gt;
+    &lt;p&gt;Wi-Fi networks at places like cafes or airports need you to sign in. To see the sign-in page, visit a page that uses &lt;code&gt;http://&lt;/code&gt;.&lt;/p&gt;
     &lt;ol&gt;
     &lt;li&gt;Go to any website starting with &lt;code&gt;http://&lt;/code&gt;, like &lt;a href="http://example.com" target="_blank"&gt;http://example.com&lt;/a&gt;.&lt;/li&gt;
     &lt;li&gt;On the sign-in page that opens, sign in to use the internet.&lt;/li&gt;
@@ -334,13 +355,16 @@
     &lt;p&gt;Remember to turn your antivirus program back on when you're done.&lt;/p&gt;
     &lt;h4&gt;Step 5: Get extra help&lt;/h4&gt;
     &lt;p&gt;If you still see the error, contact the website owner.&lt;/p&gt;
-    &lt;h3&gt;"Connect to network"&lt;/h3&gt;
+  </message>
+  <message name="IDS_CONNECTION_HELP_CONNECT_TO_NETWORK_DETAILS" desc="Details for connect to network section in chrome://connection-help. Matches the fourth section in https://support.google.com/chrome/answer/6098869">
     &lt;p&gt;You'll see this error if you're using a Wi-Fi portal where you have to sign in before you can get online.&lt;/p&gt;
     &lt;p&gt;To fix the error, click &lt;strong&gt;Connect&lt;/strong&gt; on the page you're trying to open.&lt;/p&gt;
-    &lt;h3&gt;"Your clock is behind" or "Your clock is ahead" or "NET::ERR_CERT_DATE_INVALID"&lt;/h3&gt;
+  </message>
+  <message name="IDS_CONNECTION_HELP_INCORRECT_CLOCK_DETAILS" desc="Details for incorrect clock section in chrome://connection-help. Matches the fifth section in https://support.google.com/chrome/answer/6098869">
     &lt;p&gt;You'll see this error if your computer or mobile device's date and time are inaccurate.&lt;/p&gt;
     &lt;p&gt;To fix the error, open your device's clock. Make sure the time and date are correct.&lt;/p&gt;
-    &lt;h3&gt;"Software on your computer is stopping Chrome from safely connecting to the web" (Windows computers only)&lt;/h3&gt;
+  </message>
+  <message name="IDS_CONNECTION_HELP_MITM_SOFTWARE_DETAILS" desc="Details for MITM software section in chrome://connection-help. Matches the eight section in https://support.google.com/chrome/answer/6098869">
     &lt;p&gt;You'll see this error if you have Superfish software on your Windows computer.&lt;/p&gt;
     &lt;p&gt;Follow these steps to temporarily disable the software so you can get on the web. You'll need administrator privileges.&lt;/p&gt;
     &lt;ol&gt;
diff --git a/components/sync/BUILD.gn b/components/sync/BUILD.gn
index 1d6f4d6..74d4553 100644
--- a/components/sync/BUILD.gn
+++ b/components/sync/BUILD.gn
@@ -824,6 +824,7 @@
     "driver/model_type_controller_unittest.cc",
     "driver/shared_change_processor_unittest.cc",
     "driver/startup_controller_unittest.cc",
+    "driver/sync_service_utils_unittest.cc",
     "driver/sync_stopped_reporter_unittest.cc",
     "driver/sync_util_unittest.cc",
     "engine/cycle/sync_cycle_snapshot_unittest.cc",
diff --git a/components/sync/driver/about_sync_util.cc b/components/sync/driver/about_sync_util.cc
index 6333744f..1f2572e 100644
--- a/components/sync/driver/about_sync_util.cc
+++ b/components/sync/driver/about_sync_util.cc
@@ -180,7 +180,7 @@
 std::string GetVersionString(version_info::Channel channel) {
   // Build a version string that matches syncer::MakeUserAgentForSync with the
   // addition of channel info and proper OS names.
-  // chrome::GetChannelString() returns empty string for stable channel or
+  // chrome::GetChannelName() returns empty string for stable channel or
   // unofficial builds, the channel string otherwise. We want to have "-devel"
   // for unofficial builds only.
   std::string version_modifier = version_info::GetChannelString(channel);
diff --git a/components/sync/driver/sync_service.cc b/components/sync/driver/sync_service.cc
index 7b65570..0ad23f7d 100644
--- a/components/sync/driver/sync_service.cc
+++ b/components/sync/driver/sync_service.cc
@@ -4,8 +4,6 @@
 
 #include "components/sync/driver/sync_service.h"
 
-#include "components/sync/engine/sync_manager.h"
-
 namespace syncer {
 
 SyncSetupInProgressHandle::SyncSetupInProgressHandle(base::Closure on_destroy)
diff --git a/components/sync/driver/sync_service.h b/components/sync/driver/sync_service.h
index d539b4fe..b03cc20 100644
--- a/components/sync/driver/sync_service.h
+++ b/components/sync/driver/sync_service.h
@@ -126,7 +126,7 @@
   // Returns true if sync is fully initialized and active. This implies that
   // an initial configuration has successfully completed, although there may
   // be datatype specific, auth, or other transient errors. To see which
-  // datetypes are actually syncing, see GetActiveTypes() below.
+  // datatypes are actually syncing, see GetActiveDataTypes() below.
   virtual bool IsSyncActive() const = 0;
 
   // Returns true if the local sync backend server has been enabled through a
diff --git a/components/sync/driver/sync_service_utils.cc b/components/sync/driver/sync_service_utils.cc
index 7755b4c..9e6ab81 100644
--- a/components/sync/driver/sync_service_utils.cc
+++ b/components/sync/driver/sync_service_utils.cc
@@ -18,4 +18,21 @@
          !sync_service->GetEncryptedDataTypes().Has(SESSIONS);
 }
 
+UploadState GetUploadToGoogleState(const SyncService* sync_service,
+                                   ModelType type) {
+  // Note: Before configuration is done, GetPreferredDataTypes returns
+  // "everything" (i.e. the default setting). If a data type is missing there,
+  // it must be because the user explicitly disabled it.
+  if (!sync_service->CanSyncStart() || sync_service->IsLocalSyncEnabled() ||
+      !sync_service->GetPreferredDataTypes().Has(type) ||
+      sync_service->GetAuthError().IsPersistentError() ||
+      sync_service->IsUsingSecondaryPassphrase()) {
+    return UploadState::NOT_ACTIVE;
+  }
+  if (!sync_service->IsSyncActive() || !sync_service->ConfigurationDone()) {
+    return UploadState::INITIALIZING;
+  }
+  return UploadState::ACTIVE;
+}
+
 }  // namespace syncer
diff --git a/components/sync/driver/sync_service_utils.h b/components/sync/driver/sync_service_utils.h
index 672fafc..4f6340c 100644
--- a/components/sync/driver/sync_service_utils.h
+++ b/components/sync/driver/sync_service_utils.h
@@ -5,6 +5,8 @@
 #ifndef COMPONENTS_SYNC_DRIVER_SYNC_SERVICE_UTILS_H_
 #define COMPONENTS_SYNC_DRIVER_SYNC_SERVICE_UTILS_H_
 
+#include "components/sync/base/model_type.h"
+
 class PrefService;
 
 namespace syncer {
@@ -16,6 +18,31 @@
 bool IsTabSyncEnabledAndUnencrypted(SyncService* sync_service,
                                     PrefService* pref_service);
 
+// Indicates whether uploading of data to Google is enabled, i.e. the user has
+// given consent to upload this data.
+enum class UploadState {
+  // Syncing is enabled in principle, but the sync service is still
+  // initializing, so e.g. we don't know about any auth errors yet.
+  INITIALIZING,
+  // We are not syncing to Google, and the caller should assume that we do not
+  // have consent to do so. This can have a number of reasons: e.g. sync as a
+  // whole is disabled, or the given model type is disabled, or we're in
+  // "local sync" mode, or encryption with a custom passphrase is enabled (in
+  // which case we're technically still uploading, but Google can't inspect the
+  // data), or we're in a persistent auth error state. As one special case of an
+  // auth error, sync may be "paused" because the user signed out of the content
+  // area.
+  NOT_ACTIVE,
+  // We're actively syncing data to Google servers.
+  ACTIVE
+};
+
+// Returns whether |type| is being uploaded to Google. This is useful for
+// features that depend on user consent for uploading data (e.g. history) to
+// Google.
+UploadState GetUploadToGoogleState(const SyncService* sync_service,
+                                   ModelType type);
+
 }  // namespace syncer
 
 #endif  // COMPONENTS_SYNC_DRIVER_SYNC_SERVICE_UTILS_H_
diff --git a/components/sync/driver/sync_service_utils_unittest.cc b/components/sync/driver/sync_service_utils_unittest.cc
new file mode 100644
index 0000000..862adee
--- /dev/null
+++ b/components/sync/driver/sync_service_utils_unittest.cc
@@ -0,0 +1,201 @@
+// 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 "components/sync/driver/sync_service_utils.h"
+
+#include "components/sync/base/model_type.h"
+#include "components/sync/driver/fake_sync_service.h"
+#include "components/sync/driver/sync_service.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace syncer {
+
+class TestSyncService : public FakeSyncService {
+ public:
+  TestSyncService() = default;
+  ~TestSyncService() override = default;
+
+  void SetSyncAllowed(bool allowed) { sync_allowed_ = allowed; }
+  void SetSyncActive(bool active) { sync_active_ = active; }
+  void SetLocalSyncEnabled(bool local) { local_sync_enabled_ = local; }
+  void SetPreferredDataTypes(const ModelTypeSet& types) {
+    preferred_data_types_ = types;
+  }
+  void SetConfigurationDone(bool done) { configuration_done_ = done; }
+  void SetCustomPassphraseEnabled(bool enabled) {
+    custom_passphrase_enabled_ = enabled;
+  }
+
+  // SyncService implementation.
+  bool IsSyncAllowed() const override { return sync_allowed_; }
+  bool CanSyncStart() const override { return sync_allowed_; }
+  bool IsSyncActive() const override { return sync_active_; }
+  bool IsLocalSyncEnabled() const override { return local_sync_enabled_; }
+  ModelTypeSet GetPreferredDataTypes() const override {
+    return preferred_data_types_;
+  }
+  ModelTypeSet GetActiveDataTypes() const override {
+    if (!sync_active_)
+      return ModelTypeSet();
+    return preferred_data_types_;
+  }
+  ModelTypeSet GetEncryptedDataTypes() const override {
+    if (!custom_passphrase_enabled_)
+      return ModelTypeSet(syncer::PASSWORDS);
+    return preferred_data_types_;
+  }
+  bool ConfigurationDone() const override { return configuration_done_; }
+  bool IsUsingSecondaryPassphrase() const override {
+    return custom_passphrase_enabled_;
+  }
+
+ private:
+  bool sync_allowed_ = false;
+  bool sync_active_ = false;
+  bool local_sync_enabled_ = false;
+  ModelTypeSet preferred_data_types_;
+  bool configuration_done_ = false;
+  bool custom_passphrase_enabled_ = false;
+};
+
+TEST(SyncServiceUtilsTest, UploadToGoogleDisabledIfSyncNotAllowed) {
+  TestSyncService service;
+
+  // If sync is not allowed, uploading should never be enabled, even if
+  // configuration is done and all the data types are enabled.
+  service.SetSyncAllowed(false);
+
+  service.SetConfigurationDone(true);
+  service.SetPreferredDataTypes(ProtocolTypes());
+
+  EXPECT_EQ(UploadState::NOT_ACTIVE,
+            GetUploadToGoogleState(&service, syncer::BOOKMARKS));
+
+  // Once sync gets allowed (e.g. policy is updated), uploading should not be
+  // disabled anymore (though not necessarily active yet).
+  service.SetSyncAllowed(true);
+
+  EXPECT_NE(UploadState::NOT_ACTIVE,
+            GetUploadToGoogleState(&service, syncer::BOOKMARKS));
+}
+
+TEST(SyncServiceUtilsTest, UploadToGoogleInitializingUntilConfiguredAndActive) {
+  TestSyncService service;
+  service.SetSyncAllowed(true);
+  service.SetPreferredDataTypes(ProtocolTypes());
+
+  // By default, if sync isn't disabled, we should be INITIALIZING.
+  EXPECT_EQ(UploadState::INITIALIZING,
+            GetUploadToGoogleState(&service, syncer::BOOKMARKS));
+
+  // Finished configuration is not enough, still INITIALIZING.
+  service.SetConfigurationDone(true);
+  EXPECT_EQ(UploadState::INITIALIZING,
+            GetUploadToGoogleState(&service, syncer::BOOKMARKS));
+
+  // Only after sync is both configured and active is upload actually ACTIVE.
+  service.SetSyncActive(true);
+  EXPECT_EQ(UploadState::ACTIVE,
+            GetUploadToGoogleState(&service, syncer::BOOKMARKS));
+}
+
+TEST(SyncServiceUtilsTest, UploadToGoogleDisabledForModelType) {
+  TestSyncService service;
+  service.SetSyncAllowed(true);
+  service.SetConfigurationDone(true);
+  service.SetSyncActive(true);
+
+  // Sync is enabled only for a specific model type.
+  service.SetPreferredDataTypes(ModelTypeSet(syncer::BOOKMARKS));
+
+  // Sanity check: Upload is ACTIVE for this model type.
+  ASSERT_EQ(UploadState::ACTIVE,
+            GetUploadToGoogleState(&service, syncer::BOOKMARKS));
+
+  // ...but not for other types.
+  EXPECT_EQ(
+      UploadState::NOT_ACTIVE,
+      GetUploadToGoogleState(&service, syncer::HISTORY_DELETE_DIRECTIVES));
+  EXPECT_EQ(UploadState::NOT_ACTIVE,
+            GetUploadToGoogleState(&service, syncer::PREFERENCES));
+}
+
+TEST(SyncServiceUtilsTest, UploadToGoogleDisabledIfLocalSyncEnabled) {
+  TestSyncService service;
+  service.SetSyncAllowed(true);
+  service.SetPreferredDataTypes(ProtocolTypes());
+  service.SetSyncActive(true);
+  service.SetConfigurationDone(true);
+
+  // If we're in "local sync" mode, uploading should never be enabled, even if
+  // configuration is done and all the data types are enabled.
+  service.SetLocalSyncEnabled(true);
+
+  EXPECT_EQ(UploadState::NOT_ACTIVE,
+            GetUploadToGoogleState(&service, syncer::BOOKMARKS));
+}
+
+TEST(SyncServiceUtilsTest, UploadToGoogleDisabledOnPersistentAuthError) {
+  TestSyncService service;
+  service.SetSyncAllowed(true);
+  service.SetPreferredDataTypes(ProtocolTypes());
+  service.SetSyncActive(true);
+  service.SetConfigurationDone(true);
+
+  // Sanity check: Upload is active now.
+  ASSERT_EQ(UploadState::ACTIVE,
+            GetUploadToGoogleState(&service, syncer::BOOKMARKS));
+
+  // On a transient error, uploading remains active.
+  GoogleServiceAuthError transient_error(
+      GoogleServiceAuthError::CONNECTION_FAILED);
+  ASSERT_TRUE(transient_error.IsTransientError());
+  service.set_auth_error(transient_error);
+
+  EXPECT_EQ(UploadState::ACTIVE,
+            GetUploadToGoogleState(&service, syncer::BOOKMARKS));
+
+  // On a persistent error, uploading is not considered active anymore (even
+  // though Sync may still be considered active).
+  GoogleServiceAuthError persistent_error(
+      GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS);
+  ASSERT_TRUE(persistent_error.IsPersistentError());
+  service.set_auth_error(persistent_error);
+
+  EXPECT_EQ(UploadState::NOT_ACTIVE,
+            GetUploadToGoogleState(&service, syncer::BOOKMARKS));
+
+  // Once the auth error is resolved (e.g. user re-authenticated), uploading is
+  // active again.
+  service.set_auth_error(GoogleServiceAuthError(GoogleServiceAuthError::NONE));
+
+  EXPECT_EQ(UploadState::ACTIVE,
+            GetUploadToGoogleState(&service, syncer::BOOKMARKS));
+}
+
+TEST(SyncServiceUtilsTest, UploadToGoogleDisabledIfCustomPassphraseInUse) {
+  TestSyncService service;
+  service.SetSyncAllowed(true);
+  service.SetPreferredDataTypes(ProtocolTypes());
+  service.SetSyncActive(true);
+  service.SetConfigurationDone(true);
+
+  // Sanity check: Upload is ACTIVE, even for data types that are always
+  // encrypted implicitly (PASSWORDS).
+  ASSERT_EQ(UploadState::ACTIVE,
+            GetUploadToGoogleState(&service, syncer::BOOKMARKS));
+  ASSERT_EQ(UploadState::ACTIVE,
+            GetUploadToGoogleState(&service, syncer::PASSWORDS));
+
+  // Once a custom passphrase is in use, upload should be considered disabled:
+  // Even if we're technically still uploading, Google can't inspect the data.
+  service.SetCustomPassphraseEnabled(true);
+
+  EXPECT_EQ(UploadState::NOT_ACTIVE,
+            GetUploadToGoogleState(&service, syncer::BOOKMARKS));
+  EXPECT_EQ(UploadState::NOT_ACTIVE,
+            GetUploadToGoogleState(&service, syncer::PASSWORDS));
+}
+
+}  // namespace syncer
diff --git a/components/ukm/ukm_recorder_impl.cc b/components/ukm/ukm_recorder_impl.cc
index 25a3a6885..4da7241 100644
--- a/components/ukm/ukm_recorder_impl.cc
+++ b/components/ukm/ukm_recorder_impl.cc
@@ -350,6 +350,7 @@
       RecordDroppedSource(DroppedDataReason::EXTENSION_NOT_SYNCED);
       return;
     }
+    url = url.GetWithEmptyPath();
   }
 
   // Update the pre-existing source if there is any. This happens when the
diff --git a/components/ukm/ukm_service_unittest.cc b/components/ukm/ukm_service_unittest.cc
index e01283f7..f5efded 100644
--- a/components/ukm/ukm_service_unittest.cc
+++ b/components/ukm/ukm_service_unittest.cc
@@ -1139,6 +1139,8 @@
       {"http://google.ca/?foo=bar", "http://google.ca/?foo=bar"},
       {"https://google.ca/?foo=bar", "https://google.ca/?foo=bar"},
       {"ftp://google.ca/?foo=bar", "ftp://google.ca/?foo=bar"},
+      {"chrome-extension://bhcnanendmgjjeghamaccjnochlnhcgj/foo.html?a=b",
+       "chrome-extension://bhcnanendmgjjeghamaccjnochlnhcgj/"},
   };
 
   for (const auto& test : test_cases) {
@@ -1146,10 +1148,13 @@
 
     UkmService service(&prefs_, &client_);
     TestRecordingHelper recorder(&service);
+    service.SetIsWebstoreExtensionCallback(
+        base::BindRepeating(&TestIsWebstoreExtension));
+
     EXPECT_EQ(0, GetPersistedLogCount());
     service.Initialize();
     task_runner_->RunUntilIdle();
-    service.EnableRecording(/*extensions=*/false);
+    service.EnableRecording(/*extensions=*/true);
     service.EnableReporting();
 
     auto id = GetWhitelistedSourceId(0);
diff --git a/components/viz/OWNERS b/components/viz/OWNERS
index 2abbeb1d..e0c77509 100644
--- a/components/viz/OWNERS
+++ b/components/viz/OWNERS
@@ -8,6 +8,7 @@
 # display / resources / quads / passes
 danakj@chromium.org
 enne@chromium.org
+ericrk@chromium.org
 piman@chromium.org
 vmpstr@chromium.org
 weiliangc@chromium.org
@@ -28,6 +29,7 @@
 
 # gpu
 danakj@chromium.org
+ericrk@chromium.org
 piman@chromium.org
 sadrul@chromium.org
 
diff --git a/components/viz/common/features.cc b/components/viz/common/features.cc
index 8f02ddf..b2364574 100644
--- a/components/viz/common/features.cc
+++ b/components/viz/common/features.cc
@@ -13,7 +13,7 @@
 // Enables running draw occlusion algorithm to remove Draw Quads that are not
 // shown on screen from CompositorFrame.
 const base::Feature kEnableDrawOcclusion{"DrawOcclusion",
-                                         base::FEATURE_ENABLED_BY_DEFAULT};
+                                         base::FEATURE_DISABLED_BY_DEFAULT};
 
 #if defined(USE_AURA) || defined(OS_MACOSX)
 const base::Feature kEnableSurfaceSynchronization{
diff --git a/components/viz/common/surfaces/child_local_surface_id_allocator.cc b/components/viz/common/surfaces/child_local_surface_id_allocator.cc
index b996adfe..29024df 100644
--- a/components/viz/common/surfaces/child_local_surface_id_allocator.cc
+++ b/components/viz/common/surfaces/child_local_surface_id_allocator.cc
@@ -19,17 +19,15 @@
     const LocalSurfaceId& parent_allocated_local_surface_id) {
   DCHECK_GE(parent_allocated_local_surface_id.parent_sequence_number(),
             last_known_local_surface_id_.parent_sequence_number());
-  // Thie verifies that we only update the nonce if the parent sequence number
-  // has changed.
-  DCHECK(parent_allocated_local_surface_id.parent_sequence_number() >
-             last_known_local_surface_id_.parent_sequence_number() ||
-         parent_allocated_local_surface_id.nonce() ==
-             last_known_local_surface_id_.nonce());
+  if (!last_known_local_surface_id_.embed_token().is_empty()) {
+    DCHECK_EQ(parent_allocated_local_surface_id.embed_token(),
+              last_known_local_surface_id_.embed_token());
+  }
 
   last_known_local_surface_id_.parent_sequence_number_ =
       parent_allocated_local_surface_id.parent_sequence_number_;
-  last_known_local_surface_id_.nonce_ =
-      parent_allocated_local_surface_id.nonce_;
+  last_known_local_surface_id_.embed_token_ =
+      parent_allocated_local_surface_id.embed_token_;
   return last_known_local_surface_id_;
 }
 
diff --git a/components/viz/common/surfaces/child_local_surface_id_allocator_unittest.cc b/components/viz/common/surfaces/child_local_surface_id_allocator_unittest.cc
index cda296e0f..be75b12 100644
--- a/components/viz/common/surfaces/child_local_surface_id_allocator_unittest.cc
+++ b/components/viz/common/surfaces/child_local_surface_id_allocator_unittest.cc
@@ -75,7 +75,7 @@
 }
 
 // UpdateFromParent() on a child allocator should accept the parent's sequence
-// number and nonce. But it should continue to use its own child sequence
+// number and embed_token. But it should continue to use its own child sequence
 // number.
 TEST(ChildLocalSurfaceIdAllocatorTest,
      UpdateFromParentOnlyUpdatesExpectedLocalSurfaceIdComponents) {
@@ -88,8 +88,8 @@
             parent_allocated_local_surface_id.parent_sequence_number());
   EXPECT_NE(preupdate_local_surface_id.child_sequence_number(),
             parent_allocated_local_surface_id.child_sequence_number());
-  EXPECT_NE(preupdate_local_surface_id.nonce(),
-            parent_allocated_local_surface_id.nonce());
+  EXPECT_NE(preupdate_local_surface_id.embed_token(),
+            parent_allocated_local_surface_id.embed_token());
 
   const LocalSurfaceId& returned_local_surface_id =
       parent_updated_child_allocator.UpdateFromParent(
@@ -101,8 +101,8 @@
             parent_allocated_local_surface_id.parent_sequence_number());
   EXPECT_NE(postupdate_local_surface_id.child_sequence_number(),
             parent_allocated_local_surface_id.child_sequence_number());
-  EXPECT_EQ(postupdate_local_surface_id.nonce(),
-            parent_allocated_local_surface_id.nonce());
+  EXPECT_EQ(postupdate_local_surface_id.embed_token(),
+            parent_allocated_local_surface_id.embed_token());
   EXPECT_EQ(returned_local_surface_id,
             parent_updated_child_allocator.last_known_local_surface_id());
 }
@@ -125,8 +125,8 @@
             postgenerateid_local_surface_id.parent_sequence_number());
   EXPECT_EQ(pregenerateid_local_surface_id.child_sequence_number() + 1,
             postgenerateid_local_surface_id.child_sequence_number());
-  EXPECT_EQ(pregenerateid_local_surface_id.nonce(),
-            postgenerateid_local_surface_id.nonce());
+  EXPECT_EQ(pregenerateid_local_surface_id.embed_token(),
+            postgenerateid_local_surface_id.embed_token());
   EXPECT_EQ(returned_local_surface_id,
             generating_child_allocator.last_known_local_surface_id());
 }
@@ -151,18 +151,19 @@
 
 ::testing::AssertionResult NonceIsEmpty(
     const LocalSurfaceId& local_surface_id) {
-  if (local_surface_id.nonce().is_empty())
+  if (local_surface_id.embed_token().is_empty())
     return ::testing::AssertionSuccess();
 
-  return ::testing::AssertionFailure() << "nonce() is not empty";
+  return ::testing::AssertionFailure() << "embed_token() is not empty";
 }
 
 LocalSurfaceId GetFakeParentAllocatedLocalSurfaceId() {
   constexpr uint32_t kParentSequenceNumber = 3;
   constexpr uint32_t kChildSequenceNumber = 2;
-  const base::UnguessableToken nonce = base::UnguessableToken::Create();
+  const base::UnguessableToken embed_token = base::UnguessableToken::Create();
 
-  return LocalSurfaceId(kParentSequenceNumber, kChildSequenceNumber, nonce);
+  return LocalSurfaceId(kParentSequenceNumber, kChildSequenceNumber,
+                        embed_token);
 }
 
 ChildLocalSurfaceIdAllocator GetParentUpdatedAllocator() {
diff --git a/components/viz/common/surfaces/local_surface_id.cc b/components/viz/common/surfaces/local_surface_id.cc
index 97577b0..8fa2770 100644
--- a/components/viz/common/surfaces/local_surface_id.cc
+++ b/components/viz/common/surfaces/local_surface_id.cc
@@ -9,12 +9,13 @@
 namespace viz {
 
 std::string LocalSurfaceId::ToString() const {
-  std::string nonce = VLOG_IS_ON(1) ? nonce_.ToString()
-                                    : nonce_.ToString().substr(0, 4) + "...";
+  std::string embed_token = VLOG_IS_ON(1)
+                                ? embed_token_.ToString()
+                                : embed_token_.ToString().substr(0, 4) + "...";
 
   return base::StringPrintf("LocalSurfaceId(%d, %d, %s)",
                             parent_sequence_number_, child_sequence_number_,
-                            nonce.c_str());
+                            embed_token.c_str());
 }
 
 std::ostream& operator<<(std::ostream& out,
diff --git a/components/viz/common/surfaces/local_surface_id.h b/components/viz/common/surfaces/local_surface_id.h
index 3d2e86f..133eaa32 100644
--- a/components/viz/common/surfaces/local_surface_id.h
+++ b/components/viz/common/surfaces/local_surface_id.h
@@ -40,12 +40,16 @@
 //
 // - child_sequence_number: This part is incremented by the client itself.
 //
-// - nonce: An UnguessableToken generated by the embedder. The purpose of this
-//   value is to make SurfaceIds unguessable, because FrameSinkIds and
+// - embed_token: An UnguessableToken generated by the embedder. The purpose of
+//   this value is to make SurfaceIds unguessable, because FrameSinkIds and
 //   LocalSurfaceIds are otherwise predictable and clients might exploit this
 //   fact to embed surfaces they're not allowed to. This value is generated once
 //   by ParentLocalSurfaceIdAllocator and remains constant during the lifetime
-//   of the allocator.
+//   of the embedding, even if a new LocalSurfaceId is generated for the
+//   embedded client because of some change in its state (e.g. size,
+//   device scale factor, etc.), or for other reasons. If a client is
+//   re-parented, then the new parent allocates a new LocalSurfaceId, with a new
+//   embed token, and communicates that to the embedded client.
 //
 // The embedder uses ParentLocalSurfaceIdAllocator to generate LocalSurfaceIds
 // for the embedee. If Surface Synchronization is on, the embedee uses
@@ -62,25 +66,25 @@
   constexpr LocalSurfaceId(const LocalSurfaceId& other)
       : parent_sequence_number_(other.parent_sequence_number_),
         child_sequence_number_(other.child_sequence_number_),
-        nonce_(other.nonce_) {}
+        embed_token_(other.embed_token_) {}
 
   constexpr LocalSurfaceId(uint32_t parent_sequence_number,
-                           const base::UnguessableToken& nonce)
+                           const base::UnguessableToken& embed_token)
       : parent_sequence_number_(parent_sequence_number),
         child_sequence_number_(kInitialChildSequenceNumber),
-        nonce_(nonce) {}
+        embed_token_(embed_token) {}
 
   constexpr LocalSurfaceId(uint32_t parent_sequence_number,
                            uint32_t child_sequence_number,
-                           const base::UnguessableToken& nonce)
+                           const base::UnguessableToken& embed_token)
       : parent_sequence_number_(parent_sequence_number),
         child_sequence_number_(child_sequence_number),
-        nonce_(nonce) {}
+        embed_token_(embed_token) {}
 
   constexpr bool is_valid() const {
     return parent_sequence_number_ != kInvalidParentSequenceNumber &&
            child_sequence_number_ != kInvalidChildSequenceNumber &&
-           !nonce_.is_empty();
+           !embed_token_.is_empty();
   }
 
   constexpr uint32_t parent_sequence_number() const {
@@ -91,12 +95,14 @@
     return child_sequence_number_;
   }
 
-  constexpr const base::UnguessableToken& nonce() const { return nonce_; }
+  constexpr const base::UnguessableToken& embed_token() const {
+    return embed_token_;
+  }
 
   bool operator==(const LocalSurfaceId& other) const {
     return parent_sequence_number_ == other.parent_sequence_number_ &&
            child_sequence_number_ == other.child_sequence_number_ &&
-           nonce_ == other.nonce_;
+           embed_token_ == other.embed_token_;
   }
 
   bool operator!=(const LocalSurfaceId& other) const {
@@ -108,7 +114,7 @@
     return base::HashInts(
         static_cast<uint64_t>(
             base::HashInts(parent_sequence_number_, child_sequence_number_)),
-        static_cast<uint64_t>(base::UnguessableTokenHash()(nonce_)));
+        static_cast<uint64_t>(base::UnguessableTokenHash()(embed_token_)));
   }
 
   std::string ToString() const;
@@ -123,7 +129,7 @@
 
   uint32_t parent_sequence_number_;
   uint32_t child_sequence_number_;
-  base::UnguessableToken nonce_;
+  base::UnguessableToken embed_token_;
 };
 
 VIZ_COMMON_EXPORT std::ostream& operator<<(
@@ -132,9 +138,9 @@
 
 inline bool operator<(const LocalSurfaceId& lhs, const LocalSurfaceId& rhs) {
   return std::tie(lhs.parent_sequence_number_, lhs.child_sequence_number_,
-                  lhs.nonce_) < std::tie(rhs.parent_sequence_number_,
-                                         rhs.child_sequence_number_,
-                                         rhs.nonce_);
+                  lhs.embed_token_) < std::tie(rhs.parent_sequence_number_,
+                                               rhs.child_sequence_number_,
+                                               rhs.embed_token_);
 }
 
 inline bool operator>(const LocalSurfaceId& lhs, const LocalSurfaceId& rhs) {
diff --git a/components/viz/common/surfaces/parent_local_surface_id_allocator_unittest.cc b/components/viz/common/surfaces/parent_local_surface_id_allocator_unittest.cc
index 20489514..5a0491a 100644
--- a/components/viz/common/surfaces/parent_local_surface_id_allocator_unittest.cc
+++ b/components/viz/common/surfaces/parent_local_surface_id_allocator_unittest.cc
@@ -29,9 +29,9 @@
 
 }  // namespace
 
-// The default constructor should generate a nonce and initialize the sequence
-// number of the last known LocalSurfaceId to an invalid state. Allocation
-// should not be suppressed.
+// The default constructor should generate a embed_token and initialize the
+// sequence number of the last known LocalSurfaceId to an invalid state.
+// Allocation should not be suppressed.
 TEST(ParentLocalSurfaceIdAllocatorTest,
      DefaultConstructorShouldNotSetLocalSurfaceIdComponents) {
   ParentLocalSurfaceIdAllocator default_constructed_parent_allocator;
@@ -81,7 +81,7 @@
 
 // UpdateFromChild() on a parent allocator should accept the child's sequence
 // number. But it should continue to use its own parent sequence number and
-// nonce.
+// embed_token.
 TEST(ParentLocalSurfaceIdAllocatorTest,
      UpdateFromChildOnlyUpdatesExpectedLocalSurfaceIdComponents) {
   ParentLocalSurfaceIdAllocator child_updated_parent_allocator;
@@ -93,8 +93,8 @@
             child_allocated_local_surface_id.parent_sequence_number());
   EXPECT_NE(preupdate_local_surface_id.child_sequence_number(),
             child_allocated_local_surface_id.child_sequence_number());
-  EXPECT_NE(preupdate_local_surface_id.nonce(),
-            child_allocated_local_surface_id.nonce());
+  EXPECT_NE(preupdate_local_surface_id.embed_token(),
+            child_allocated_local_surface_id.embed_token());
 
   const LocalSurfaceId& returned_local_surface_id =
       child_updated_parent_allocator.UpdateFromChild(
@@ -106,15 +106,15 @@
             child_allocated_local_surface_id.parent_sequence_number());
   EXPECT_EQ(postupdate_local_surface_id.child_sequence_number(),
             child_allocated_local_surface_id.child_sequence_number());
-  EXPECT_NE(postupdate_local_surface_id.nonce(),
-            child_allocated_local_surface_id.nonce());
+  EXPECT_NE(postupdate_local_surface_id.embed_token(),
+            child_allocated_local_surface_id.embed_token());
   EXPECT_EQ(returned_local_surface_id,
             child_updated_parent_allocator.last_known_local_surface_id());
   EXPECT_FALSE(child_updated_parent_allocator.is_allocation_suppressed());
 }
 
 // GenerateId() on a parent allocator should monotonically increment the parent
-// sequence number and use the previous nonce.
+// sequence number and use the previous embed_token.
 TEST(ParentLocalSurfaceIdAllocatorTest,
      GenerateIdOnlyUpdatesExpectedLocalSurfaceIdComponents) {
   ParentLocalSurfaceIdAllocator generating_parent_allocator =
@@ -131,8 +131,8 @@
             postgenerateid_local_surface_id.parent_sequence_number());
   EXPECT_EQ(pregenerateid_local_surface_id.child_sequence_number(),
             postgenerateid_local_surface_id.child_sequence_number());
-  EXPECT_EQ(pregenerateid_local_surface_id.nonce(),
-            postgenerateid_local_surface_id.nonce());
+  EXPECT_EQ(pregenerateid_local_surface_id.embed_token(),
+            postgenerateid_local_surface_id.embed_token());
   EXPECT_EQ(returned_local_surface_id,
             generating_parent_allocator.last_known_local_surface_id());
   EXPECT_FALSE(generating_parent_allocator.is_allocation_suppressed());
@@ -160,7 +160,7 @@
   LocalSurfaceId generated_id =
       default_constructed_parent_allocator.GenerateId();
 
-  EXPECT_EQ(generated_id.nonce(), new_local_surface_id.nonce());
+  EXPECT_EQ(generated_id.embed_token(), new_local_surface_id.embed_token());
   EXPECT_EQ(generated_id.child_sequence_number(),
             new_local_surface_id.child_sequence_number());
   EXPECT_EQ(generated_id.parent_sequence_number(),
@@ -187,18 +187,19 @@
 
 ::testing::AssertionResult NonceIsEmpty(
     const LocalSurfaceId& local_surface_id) {
-  if (local_surface_id.nonce().is_empty())
+  if (local_surface_id.embed_token().is_empty())
     return ::testing::AssertionSuccess();
 
-  return ::testing::AssertionFailure() << "nonce() is not empty";
+  return ::testing::AssertionFailure() << "embed_token() is not empty";
 }
 
 LocalSurfaceId GetFakeChildAllocatedLocalSurfaceId() {
   constexpr uint32_t kParentSequenceNumber = 1;
   constexpr uint32_t kChildSequenceNumber = 3;
-  const base::UnguessableToken nonce = base::UnguessableToken::Create();
+  const base::UnguessableToken embed_token = base::UnguessableToken::Create();
 
-  return LocalSurfaceId(kParentSequenceNumber, kChildSequenceNumber, nonce);
+  return LocalSurfaceId(kParentSequenceNumber, kChildSequenceNumber,
+                        embed_token);
 }
 
 ParentLocalSurfaceIdAllocator GetChildUpdatedAllocator() {
diff --git a/components/viz/service/surfaces/surface_manager.cc b/components/viz/service/surfaces/surface_manager.cc
index 48b4b4e..67d1d6b 100644
--- a/components/viz/service/surfaces/surface_manager.cc
+++ b/components/viz/service/surfaces/surface_manager.cc
@@ -462,12 +462,12 @@
       continue;
     }
 
-    // If the nonce doesn't match the primary or fallback's then the parent does
-    // not have permission to embed this surface.
-    if (local_surface_id.nonce() !=
-            fallback_surface_id.local_surface_id().nonce() &&
-        local_surface_id.nonce() !=
-            primary_surface_id.local_surface_id().nonce()) {
+    // If the embed_token doesn't match the primary or fallback's then the
+    // parent does not have permission to embed this surface.
+    if (local_surface_id.embed_token() !=
+            fallback_surface_id.local_surface_id().embed_token() &&
+        local_surface_id.embed_token() !=
+            primary_surface_id.local_surface_id().embed_token()) {
       continue;
     }
 
diff --git a/components/zucchini/encoded_view.h b/components/zucchini/encoded_view.h
index 7ecf59e..852c4a83 100644
--- a/components/zucchini/encoded_view.h
+++ b/components/zucchini/encoded_view.h
@@ -50,15 +50,15 @@
     using reference = size_t;
     using pointer = size_t*;
 
-    Iterator(const EncodedView& encoded_view, difference_type pos)
+    Iterator(const EncodedView* encoded_view, difference_type pos)
         : encoded_view_(encoded_view), pos_(pos) {}
 
     value_type operator*() const {
-      return encoded_view_.Projection(static_cast<offset_t>(pos_));
+      return encoded_view_->Projection(static_cast<offset_t>(pos_));
     }
 
     value_type operator[](difference_type n) const {
-      return encoded_view_.Projection(static_cast<offset_t>(pos_ + n));
+      return encoded_view_->Projection(static_cast<offset_t>(pos_ + n));
     }
 
     Iterator& operator++() {
@@ -93,6 +93,12 @@
       return *this;
     }
 
+    Iterator& operator=(const Iterator& it) {
+      encoded_view_ = it.encoded_view_;
+      pos_ = it.pos_;
+      return *this;
+    }
+
     friend bool operator==(Iterator a, Iterator b) { return a.pos_ == b.pos_; }
 
     friend bool operator!=(Iterator a, Iterator b) { return !(a == b); }
@@ -120,7 +126,7 @@
     }
 
    private:
-    const EncodedView& encoded_view_;
+    const EncodedView* encoded_view_;
     difference_type pos_;
   };
 
@@ -154,10 +160,10 @@
   // Range functions.
   size_type size() const { return size_type(image_index_.size()); }
   const_iterator begin() const {
-    return const_iterator{*this, difference_type(0)};
+    return const_iterator{this, difference_type(0)};
   }
   const_iterator end() const {
-    return const_iterator{*this, difference_type(size())};
+    return const_iterator{this, difference_type(size())};
   }
 
  private:
diff --git a/content/browser/accessibility/accessibility_tree_formatter_blink.cc b/content/browser/accessibility/accessibility_tree_formatter_blink.cc
index 9e36b55..5c10a5b 100644
--- a/content/browser/accessibility/accessibility_tree_formatter_blink.cc
+++ b/content/browser/accessibility/accessibility_tree_formatter_blink.cc
@@ -212,7 +212,8 @@
        attr_index <= static_cast<int32_t>(ax::mojom::FloatAttribute::kLast);
        ++attr_index) {
     auto attr = static_cast<ax::mojom::FloatAttribute>(attr_index);
-    if (node.HasFloatAttribute(attr) && isfinite(node.GetFloatAttribute(attr)))
+    if (node.HasFloatAttribute(attr) &&
+        std::isfinite(node.GetFloatAttribute(attr)))
       dict->SetDouble(ui::ToString(attr), node.GetFloatAttribute(attr));
   }
 
diff --git a/content/browser/android/synchronous_compositor_host.cc b/content/browser/android/synchronous_compositor_host.cc
index 46209b4..633f35c 100644
--- a/content/browser/android/synchronous_compositor_host.cc
+++ b/content/browser/android/synchronous_compositor_host.cc
@@ -560,6 +560,8 @@
 
 void SynchronousCompositorHost::OnComputeScroll(
     base::TimeTicks animation_time) {
+  on_compute_scroll_called_ = true;
+
   if (!need_animate_scroll_)
     return;
   need_animate_scroll_ = false;
diff --git a/content/browser/android/synchronous_compositor_host.h b/content/browser/android/synchronous_compositor_host.h
index dbe31477..f027eee 100644
--- a/content/browser/android/synchronous_compositor_host.h
+++ b/content/browser/android/synchronous_compositor_host.h
@@ -88,6 +88,8 @@
   void UpdateState(const SyncCompositorCommonRendererParams& params) override;
   void SetNeedsBeginFrames(bool needs_begin_frames) override;
 
+  bool on_compute_scroll_called() { return on_compute_scroll_called_; }
+
  private:
   class ScopedSendZeroMemory;
   struct SharedMemoryWithSize;
@@ -139,6 +141,11 @@
   // Updated by both renderer and browser.
   gfx::ScrollOffset root_scroll_offset_;
 
+  // Indicates that whether OnComputeScroll is called or overridden. The
+  // fling_controller should advance the fling only when OnComputeScroll is not
+  // overridden.
+  bool on_compute_scroll_called_ = false;
+
   // From renderer.
   uint32_t renderer_param_version_;
   bool need_animate_scroll_;
diff --git a/content/browser/renderer_host/input/fling_controller.cc b/content/browser/renderer_host/input/fling_controller.cc
index 3c6c797..95a42332 100644
--- a/content/browser/renderer_host/input/fling_controller.cc
+++ b/content/browser/renderer_host/input/fling_controller.cc
@@ -59,8 +59,7 @@
   if (fling_in_progress_)
     return !fling_booster_->fling_cancellation_is_deferred();
 
-  // Touchpad fling with wheel scroll latching disabled, touchscreen, and
-  // auto-scroll flings are still handled by renderer.
+  // Auto-scroll flings are still handled by renderer.
   return !gesture_event_queue_->ShouldDiscardFlingCancelEvent(gesture_event);
 }
 
@@ -136,16 +135,6 @@
     InputEventAckState ack_result) {
   bool processed = (INPUT_EVENT_ACK_STATE_CONSUMED == ack_result);
   switch (acked_event.event.GetType()) {
-    case WebInputEvent::kGestureFlingCancel: {
-      blink::WebGestureDevice source_device = acked_event.event.SourceDevice();
-      if (source_device == blink::kWebGestureDeviceTouchscreen) {
-        touchscreen_tap_suppression_controller_.GestureFlingCancelAck(
-            processed);
-      } else if (source_device == blink::kWebGestureDeviceTouchpad) {
-        touchpad_tap_suppression_controller_.GestureFlingCancelAck(processed);
-      }
-      break;
-    }
     case WebInputEvent::kGestureScrollUpdate:
       if (acked_event.event.data.scroll_update.inertial_phase ==
               WebGestureEvent::kMomentumPhase &&
@@ -180,29 +169,32 @@
 void FlingController::ProcessGestureFlingCancel(
     const GestureEventWithLatencyInfo& gesture_event) {
   fling_in_progress_ = false;
+  bool processed = false;
   if (fling_curve_) {
     CancelCurrentFling();
-
-    // FlingCancelEvent handled without being sent to the renderer.
-    touchpad_tap_suppression_controller_.GestureFlingCancelAck(true);
-    return;
+    processed = true;
   }
-
-  // FlingCancelEvent ignored without being sent to the renderer.
-  touchpad_tap_suppression_controller_.GestureFlingCancelAck(false);
+  // FlingCancelEvent handled without being sent to the renderer.
+  blink::WebGestureDevice source_device = gesture_event.event.SourceDevice();
+  if (source_device == blink::kWebGestureDeviceTouchscreen) {
+    touchscreen_tap_suppression_controller_.GestureFlingCancelAck(processed);
+  } else if (source_device == blink::kWebGestureDeviceTouchpad) {
+    touchpad_tap_suppression_controller_.GestureFlingCancelAck(processed);
+  }
 }
 
-void FlingController::ProgressFling(base::TimeTicks current_time) {
+gfx::Vector2dF FlingController::ProgressFling(base::TimeTicks current_time) {
   if (!fling_curve_)
-    return;
+    return gfx::Vector2dF();
 
   DCHECK(fling_booster_);
   fling_booster_->set_last_fling_animation_time(
       (current_time - base::TimeTicks()).InSecondsF());
   if (fling_booster_->MustCancelDeferredFling()) {
     CancelCurrentFling();
-    return;
+    return gfx::Vector2dF();
   }
+
   if (!has_fling_animation_started_) {
     // Guard against invalid, future or sufficiently stale start times, as there
     // are no guarantees fling event and progress timestamps are compatible.
@@ -212,29 +204,26 @@
                             kMaxMicrosecondsFromFlingTimestampToFirstProgress) {
       current_fling_parameters_.start_time = current_time;
       ScheduleFlingProgress();
-      return;
+      return current_fling_parameters_.velocity;
     }
   }
 
-  gfx::Vector2dF current_velocity;
   gfx::Vector2dF delta_to_scroll;
   bool fling_is_active = fling_curve_->Advance(
       (current_time - current_fling_parameters_.start_time).InSecondsF(),
-      current_velocity, delta_to_scroll);
+      current_fling_parameters_.velocity, delta_to_scroll);
   if (fling_is_active) {
     if (delta_to_scroll != gfx::Vector2d()) {
-      blink::WebMouseWheelEvent::Phase phase =
-          has_fling_animation_started_
-              ? blink::WebMouseWheelEvent::kPhaseChanged
-              : blink::WebMouseWheelEvent::kPhaseBegan;
-      GenerateAndSendWheelEvents(delta_to_scroll, phase);
+      GenerateAndSendFlingProgressEvents(delta_to_scroll);
       has_fling_animation_started_ = true;
     }
     // As long as the fling curve is active, the fling progress must get
     // scheduled even when the last delta to scroll was zero.
     ScheduleFlingProgress();
+    return current_fling_parameters_.velocity;
   } else {  // !is_fling_active
     CancelCurrentFling();
+    return gfx::Vector2dF();
   }
 }
 
@@ -246,7 +235,7 @@
 }
 
 void FlingController::GenerateAndSendWheelEvents(
-    gfx::Vector2dF delta,
+    const gfx::Vector2dF& delta,
     blink::WebMouseWheelEvent::Phase phase) {
   MouseWheelEventWithLatencyInfo synthetic_wheel(
       WebInputEvent::kMouseWheel, current_fling_parameters_.modifiers,
@@ -273,56 +262,132 @@
   client_->SendGeneratedWheelEvent(synthetic_wheel);
 }
 
+void FlingController::GenerateAndSendGestureScrollEvents(
+    WebInputEvent::Type type,
+    const gfx::Vector2dF& delta /* = gfx::Vector2dF() */) {
+  GestureEventWithLatencyInfo synthetic_gesture(
+      type, current_fling_parameters_.modifiers,
+      ui::EventTimeStampToSeconds(base::TimeTicks::Now()),
+      ui::LatencyInfo(ui::SourceEventType::TOUCH));
+  synthetic_gesture.event.SetPositionInWidget(current_fling_parameters_.point);
+  synthetic_gesture.event.SetPositionInScreen(
+      current_fling_parameters_.global_point);
+  synthetic_gesture.event.primary_pointer_type =
+      blink::WebPointerProperties::PointerType::kTouch;
+  synthetic_gesture.event.SetSourceDevice(blink::kWebGestureDeviceTouchscreen);
+  if (type == WebInputEvent::kGestureScrollUpdate) {
+    synthetic_gesture.event.data.scroll_update.delta_x = delta.x();
+    synthetic_gesture.event.data.scroll_update.delta_y = delta.y();
+    synthetic_gesture.event.data.scroll_update.inertial_phase =
+        WebGestureEvent::kMomentumPhase;
+  } else {
+    DCHECK_EQ(WebInputEvent::kGestureScrollEnd, type);
+    synthetic_gesture.event.data.scroll_end.inertial_phase =
+        WebGestureEvent::kMomentumPhase;
+  }
+  client_->SendGeneratedGestureScrollEvents(synthetic_gesture);
+}
+
+void FlingController::GenerateAndSendFlingProgressEvents(
+    const gfx::Vector2dF& delta) {
+  switch (current_fling_parameters_.source_device) {
+    case blink::kWebGestureDeviceTouchpad: {
+      blink::WebMouseWheelEvent::Phase phase =
+          has_fling_animation_started_
+              ? blink::WebMouseWheelEvent::kPhaseChanged
+              : blink::WebMouseWheelEvent::kPhaseBegan;
+      GenerateAndSendWheelEvents(delta, phase);
+      break;
+    }
+    case blink::kWebGestureDeviceTouchscreen:
+      GenerateAndSendGestureScrollEvents(WebInputEvent::kGestureScrollUpdate,
+                                         delta);
+      break;
+    default:
+      NOTREACHED()
+          << "Fling controller doesn't handle flings with source device:"
+          << current_fling_parameters_.source_device;
+  }
+}
+
+void FlingController::GenerateAndSendFlingEndEvents() {
+  switch (current_fling_parameters_.source_device) {
+    case blink::kWebGestureDeviceTouchpad:
+      GenerateAndSendWheelEvents(gfx::Vector2d(),
+                                 blink::WebMouseWheelEvent::kPhaseEnded);
+      break;
+    case blink::kWebGestureDeviceTouchscreen:
+      GenerateAndSendGestureScrollEvents(WebInputEvent::kGestureScrollEnd);
+      break;
+    default:
+      NOTREACHED()
+          << "Fling controller doesn't handle flings with source device:"
+          << current_fling_parameters_.source_device;
+  }
+}
+
 void FlingController::CancelCurrentFling() {
+  bool had_active_fling = !!fling_curve_;
   fling_curve_.reset();
   has_fling_animation_started_ = false;
   fling_in_progress_ = false;
-  GenerateAndSendWheelEvents(gfx::Vector2d(),
-                             blink::WebMouseWheelEvent::kPhaseEnded);
+  gesture_event_queue_->FlingHasBeenHalted();
+
+  // Extract the last event filtered by the fling booster if it exists.
+  bool fling_cancellation_is_deferred =
+      fling_booster_ && fling_booster_->fling_cancellation_is_deferred();
+  WebGestureEvent last_fling_boost_event;
+  if (fling_cancellation_is_deferred)
+    last_fling_boost_event = fling_booster_->last_boost_event();
+
+  // Reset the state of the fling.
+  fling_booster_.reset();
+  GenerateAndSendFlingEndEvents();
   current_fling_parameters_ = ActiveFlingParameters();
 
-  if (fling_booster_) {
-    if (fling_booster_->fling_cancellation_is_deferred()) {
-      WebGestureEvent last_fling_boost_event =
-          fling_booster_->last_boost_event();
-      fling_booster_.reset();
-      if (last_fling_boost_event.GetType() ==
-              WebInputEvent::kGestureScrollBegin ||
-          last_fling_boost_event.GetType() ==
-              WebInputEvent::kGestureScrollUpdate) {
-        // Synthesize a GestureScrollBegin, as the original event was
-        // suppressed.
-        WebGestureEvent scroll_begin_event = last_fling_boost_event;
-        scroll_begin_event.SetType(WebInputEvent::kGestureScrollBegin);
-        scroll_begin_event.SetTimeStampSeconds(
-            ui::EventTimeStampToSeconds(base::TimeTicks::Now()));
-        bool is_update = last_fling_boost_event.GetType() ==
-                         WebInputEvent::kGestureScrollUpdate;
-        float delta_x_hint =
-            is_update ? last_fling_boost_event.data.scroll_update.delta_x
-                      : last_fling_boost_event.data.scroll_begin.delta_x_hint;
-        float delta_y_hint =
-            is_update ? last_fling_boost_event.data.scroll_update.delta_y
-                      : last_fling_boost_event.data.scroll_begin.delta_y_hint;
-        scroll_begin_event.data.scroll_begin.delta_x_hint = delta_x_hint;
-        scroll_begin_event.data.scroll_begin.delta_y_hint = delta_y_hint;
-        gesture_event_queue_->QueueEvent(GestureEventWithLatencyInfo(
-            scroll_begin_event, ui::LatencyInfo(ui::SourceEventType::WHEEL)));
-      }
-    } else {
-      fling_booster_.reset();
+  // Synthesize a GestureScrollBegin, as the original event was suppressed. It
+  // is important to send the GSB after resetting the fling_booster_ otherwise
+  // it will get filtered by the booster again.
+  if (fling_cancellation_is_deferred &&
+      (last_fling_boost_event.GetType() == WebInputEvent::kGestureScrollBegin ||
+       last_fling_boost_event.GetType() ==
+           WebInputEvent::kGestureScrollUpdate)) {
+    WebGestureEvent scroll_begin_event = last_fling_boost_event;
+    scroll_begin_event.SetType(WebInputEvent::kGestureScrollBegin);
+    scroll_begin_event.SetTimeStampSeconds(
+        ui::EventTimeStampToSeconds(base::TimeTicks::Now()));
+    bool is_update =
+        last_fling_boost_event.GetType() == WebInputEvent::kGestureScrollUpdate;
+    float delta_x_hint =
+        is_update ? last_fling_boost_event.data.scroll_update.delta_x
+                  : last_fling_boost_event.data.scroll_begin.delta_x_hint;
+    float delta_y_hint =
+        is_update ? last_fling_boost_event.data.scroll_update.delta_y
+                  : last_fling_boost_event.data.scroll_begin.delta_y_hint;
+    scroll_begin_event.data.scroll_begin.delta_x_hint = delta_x_hint;
+    scroll_begin_event.data.scroll_begin.delta_y_hint = delta_y_hint;
+    ui::SourceEventType latency_source_event_type =
+        ui::SourceEventType::UNKNOWN;
+    if (scroll_begin_event.SourceDevice() ==
+        blink::kWebGestureDeviceTouchscreen) {
+      latency_source_event_type = ui::SourceEventType::TOUCH;
+    } else if (scroll_begin_event.SourceDevice() ==
+               blink::kWebGestureDeviceTouchpad) {
+      latency_source_event_type = ui::SourceEventType::WHEEL;
     }
+
+    client_->SendGeneratedGestureScrollEvents(GestureEventWithLatencyInfo(
+        scroll_begin_event, ui::LatencyInfo(latency_source_event_type)));
   }
+
+  if (had_active_fling)
+    client_->DidStopFlingingOnBrowser();
 }
 
 bool FlingController::UpdateCurrentFlingState(
     const WebGestureEvent& fling_start_event,
     const gfx::Vector2dF& velocity) {
   DCHECK_EQ(WebInputEvent::kGestureFlingStart, fling_start_event.GetType());
-  if (velocity.IsZero()) {
-    CancelCurrentFling();
-    return false;
-  }
 
   current_fling_parameters_.velocity = velocity;
   current_fling_parameters_.point = fling_start_event.PositionInWidget();
@@ -332,6 +397,12 @@
   current_fling_parameters_.start_time =
       base::TimeTicks() +
       base::TimeDelta::FromSecondsD(fling_start_event.TimeStampSeconds());
+
+  if (velocity.IsZero()) {
+    CancelCurrentFling();
+    return false;
+  }
+
   fling_curve_ = std::unique_ptr<blink::WebGestureCurve>(
       ui::WebGestureCurveImpl::CreateFromDefaultPlatformCurve(
           current_fling_parameters_.source_device,
@@ -340,6 +411,15 @@
   return true;
 }
 
+bool FlingController::FlingCancellationIsDeferred() const {
+  return fling_booster_ && fling_booster_->fling_cancellation_is_deferred();
+}
+
+bool FlingController::TouchscreenFlingInProgress() const {
+  return fling_in_progress_ && current_fling_parameters_.source_device ==
+                                   blink::kWebGestureDeviceTouchscreen;
+}
+
 TouchpadTapSuppressionController*
 FlingController::GetTouchpadTapSuppressionController() {
   return &touchpad_tap_suppression_controller_;
diff --git a/content/browser/renderer_host/input/fling_controller.h b/content/browser/renderer_host/input/fling_controller.h
index 07a176c3..c762b57 100644
--- a/content/browser/renderer_host/input/fling_controller.h
+++ b/content/browser/renderer_host/input/fling_controller.h
@@ -21,7 +21,8 @@
 
 class GestureEventQueue;
 
-// Interface with which the FlingController can forward generated wheel events.
+// Interface with which the FlingController can forward generated fling progress
+// events.
 class CONTENT_EXPORT FlingControllerClient {
  public:
   virtual ~FlingControllerClient() {}
@@ -29,7 +30,12 @@
   virtual void SendGeneratedWheelEvent(
       const MouseWheelEventWithLatencyInfo& wheel_event) = 0;
 
+  virtual void SendGeneratedGestureScrollEvents(
+      const GestureEventWithLatencyInfo& gesture_event) = 0;
+
   virtual void SetNeedsBeginFrameForFlingProgress() = 0;
+
+  virtual void DidStopFlingingOnBrowser() = 0;
 };
 
 class CONTENT_EXPORT FlingController {
@@ -62,8 +68,9 @@
 
   ~FlingController();
 
-  // Used to progress an active fling on every begin frame.
-  void ProgressFling(base::TimeTicks current_time);
+  // Used to progress an active fling on every begin frame and return the
+  // current fling velocity.
+  gfx::Vector2dF ProgressFling(base::TimeTicks current_time);
 
   // Used to halt an active fling progress whenever needed.
   void StopFling();
@@ -81,6 +88,10 @@
 
   bool fling_in_progress() const { return fling_in_progress_; }
 
+  bool FlingCancellationIsDeferred() const;
+
+  bool TouchscreenFlingInProgress() const;
+
   // Returns the |TouchpadTapSuppressionController| instance.
   TouchpadTapSuppressionController* GetTouchpadTapSuppressionController();
 
@@ -104,9 +115,25 @@
   void ScheduleFlingProgress();
 
   // Used to generate synthetic wheel events from touchpad fling and send them.
-  void GenerateAndSendWheelEvents(gfx::Vector2dF delta,
+  void GenerateAndSendWheelEvents(const gfx::Vector2dF& delta,
                                   blink::WebMouseWheelEvent::Phase phase);
 
+  // Used to generate synthetic gesture scroll events from touchscreen fling and
+  // send them.
+  void GenerateAndSendGestureScrollEvents(
+      blink::WebInputEvent::Type type,
+      const gfx::Vector2dF& delta = gfx::Vector2dF());
+
+  // Calls one of the GenerateAndSendWheelEvents or
+  // GenerateAndSendGestureScrollEvents functions depending on the source
+  // device of the current_fling_parameters_. We send GSU and wheel events
+  // to progress flings with touchscreen and touchpad source respectively.
+  // The reason for this difference is that during the touchpad fling we still
+  // send wheel events to JS and generating GSU events directly is not enough.
+  void GenerateAndSendFlingProgressEvents(const gfx::Vector2dF& delta);
+
+  void GenerateAndSendFlingEndEvents();
+
   void CancelCurrentFling();
 
   bool UpdateCurrentFlingState(const blink::WebGestureEvent& fling_start_event,
@@ -131,8 +158,7 @@
 
   ActiveFlingParameters current_fling_parameters_;
 
-  // True while no GestureFlingCancel has arrived after the FlingController has
-  // processed a GestureFlingStart.
+  // True when a fling is active.
   bool fling_in_progress_;
 
   // Whether an active fling has seen a |ProgressFling()| call. This is useful
diff --git a/content/browser/renderer_host/input/fling_controller_unittest.cc b/content/browser/renderer_host/input/fling_controller_unittest.cc
index 2e8310ff..a522dc6 100644
--- a/content/browser/renderer_host/input/fling_controller_unittest.cc
+++ b/content/browser/renderer_host/input/fling_controller_unittest.cc
@@ -70,10 +70,17 @@
       const MouseWheelEventWithLatencyInfo& wheel_event) override {
     last_sent_wheel_ = wheel_event.event;
   }
+  void SendGeneratedGestureScrollEvents(
+      const GestureEventWithLatencyInfo& gesture_event) override {
+    last_sent_gesture_ = gesture_event.event;
+  }
   void SetNeedsBeginFrameForFlingProgress() override {
     DCHECK(!scheduled_next_fling_progress_);
     scheduled_next_fling_progress_ = true;
   }
+  void DidStopFlingingOnBrowser() override {
+    notified_client_after_fling_stop_ = true;
+  }
 
   void SimulateFlingStart(blink::WebGestureDevice source_device,
                           const gfx::Vector2dF& velocity) {
@@ -89,6 +96,7 @@
   }
 
   void SimulateFlingCancel(blink::WebGestureDevice source_device) {
+    notified_client_after_fling_stop_ = false;
     WebGestureEvent fling_cancel(
         WebInputEvent::kGestureFlingCancel, 0,
         ui::EventTimeStampToSeconds(base::TimeTicks::Now()), source_device);
@@ -111,8 +119,10 @@
  protected:
   std::unique_ptr<FakeFlingController> fling_controller_;
   WebMouseWheelEvent last_sent_wheel_;
+  WebGestureEvent last_sent_gesture_;
   bool last_fling_cancel_filtered_;
   bool scheduled_next_fling_progress_;
+  bool notified_client_after_fling_stop_;
 
  private:
   base::test::ScopedTaskEnvironment scoped_task_environment_;
@@ -120,7 +130,8 @@
   base::test::ScopedFeatureList feature_list_;
 };
 
-TEST_F(FlingControllerTest, ControllerSendsWheelEndOnFlingWithZeroVelocity) {
+TEST_F(FlingControllerTest,
+       ControllerSendsWheelEndOnTouchpadFlingWithZeroVelocity) {
   SimulateFlingStart(blink::kWebGestureDeviceTouchpad, gfx::Vector2dF());
   // The controller doesn't start a fling and sends a wheel end event
   // immediately.
@@ -130,7 +141,15 @@
   EXPECT_EQ(0.f, last_sent_wheel_.delta_y);
 }
 
-TEST_F(FlingControllerTest, ControllerHandlesGestureFling) {
+TEST_F(FlingControllerTest,
+       ControllerSendsGSEOnTouchscreenFlingWithZeroVelocity) {
+  SimulateFlingStart(blink::kWebGestureDeviceTouchscreen, gfx::Vector2dF());
+  // The controller doesn't start a fling and sends a GSE immediately.
+  EXPECT_FALSE(FlingInProgress());
+  EXPECT_EQ(WebInputEvent::kGestureScrollEnd, last_sent_gesture_.GetType());
+}
+
+TEST_F(FlingControllerTest, ControllerHandlesTouchpadGestureFling) {
   base::TimeTicks progress_time = base::TimeTicks::Now();
   SimulateFlingStart(blink::kWebGestureDeviceTouchpad, gfx::Vector2dF(1000, 0));
   EXPECT_TRUE(FlingInProgress());
@@ -153,7 +172,33 @@
   EXPECT_EQ(0.f, last_sent_wheel_.delta_y);
 }
 
-TEST_F(FlingControllerTest, ControllerSendsWheelEndWhenFlingIsOver) {
+TEST_F(FlingControllerTest, ControllerHandlesTouchscreenGestureFling) {
+  base::TimeTicks progress_time = base::TimeTicks::Now();
+  SimulateFlingStart(blink::kWebGestureDeviceTouchscreen,
+                     gfx::Vector2dF(1000, 0));
+  EXPECT_TRUE(FlingInProgress());
+
+  // The fling progress will generate and send GSU events with inertial state.
+  progress_time += base::TimeDelta::FromMilliseconds(17);
+  ProgressFling(progress_time);
+  ASSERT_EQ(WebInputEvent::kGestureScrollUpdate, last_sent_gesture_.GetType());
+  EXPECT_EQ(WebGestureEvent::kMomentumPhase,
+            last_sent_gesture_.data.scroll_update.inertial_phase);
+  EXPECT_GT(last_sent_gesture_.data.scroll_update.delta_x, 0.f);
+
+  // Now cancel the fling. The GFC will get suppressed by fling booster.
+  SimulateFlingCancel(blink::kWebGestureDeviceTouchscreen);
+  EXPECT_TRUE(last_fling_cancel_filtered_);
+  EXPECT_TRUE(FlingInProgress());
+
+  // Wait for the boosting timer to expire. The delayed cancelation must work.
+  progress_time += base::TimeDelta::FromMilliseconds(500);
+  ProgressFling(progress_time);
+  EXPECT_FALSE(FlingInProgress());
+  EXPECT_EQ(WebInputEvent::kGestureScrollEnd, last_sent_gesture_.GetType());
+}
+
+TEST_F(FlingControllerTest, ControllerSendsWheelEndWhenTouchpadFlingIsOver) {
   base::TimeTicks progress_time = base::TimeTicks::Now();
   SimulateFlingStart(blink::kWebGestureDeviceTouchpad, gfx::Vector2dF(100, 0));
   EXPECT_TRUE(FlingInProgress());
@@ -177,7 +222,29 @@
   EXPECT_EQ(0.f, last_sent_wheel_.delta_y);
 }
 
-TEST_F(FlingControllerTest, EarlyFlingCancelationOnInertialGSUAckNotConsumed) {
+TEST_F(FlingControllerTest, ControllerSendsGSEWhenTouchscreenFlingIsOver) {
+  base::TimeTicks progress_time = base::TimeTicks::Now();
+  SimulateFlingStart(blink::kWebGestureDeviceTouchscreen,
+                     gfx::Vector2dF(100, 0));
+  EXPECT_TRUE(FlingInProgress());
+
+  progress_time += base::TimeDelta::FromMilliseconds(17);
+  ProgressFling(progress_time);
+  while (FlingInProgress()) {
+    ASSERT_EQ(WebInputEvent::kGestureScrollUpdate,
+              last_sent_gesture_.GetType());
+    EXPECT_EQ(WebGestureEvent::kMomentumPhase,
+              last_sent_gesture_.data.scroll_update.inertial_phase);
+    EXPECT_GT(last_sent_gesture_.data.scroll_update.delta_x, 0.f);
+    progress_time += base::TimeDelta::FromMilliseconds(17);
+    ProgressFling(progress_time);
+  }
+
+  EXPECT_EQ(WebInputEvent::kGestureScrollEnd, last_sent_gesture_.GetType());
+}
+
+TEST_F(FlingControllerTest,
+       EarlyTouchpadFlingCancelationOnInertialGSUAckNotConsumed) {
   base::TimeTicks progress_time = base::TimeTicks::Now();
   SimulateFlingStart(blink::kWebGestureDeviceTouchpad, gfx::Vector2dF(1000, 0));
   EXPECT_TRUE(FlingInProgress());
@@ -202,7 +269,34 @@
   EXPECT_EQ(0.f, last_sent_wheel_.delta_y);
 }
 
-TEST_F(FlingControllerTest, EarlyFlingCancelationOnFlingStop) {
+TEST_F(FlingControllerTest,
+       EarlyTouchscreenFlingCancelationOnInertialGSUAckNotConsumed) {
+  base::TimeTicks progress_time = base::TimeTicks::Now();
+  SimulateFlingStart(blink::kWebGestureDeviceTouchscreen,
+                     gfx::Vector2dF(1000, 0));
+  EXPECT_TRUE(FlingInProgress());
+  progress_time += base::TimeDelta::FromMilliseconds(17);
+  ProgressFling(progress_time);
+  ASSERT_EQ(WebInputEvent::kGestureScrollUpdate, last_sent_gesture_.GetType());
+  EXPECT_EQ(WebGestureEvent::kMomentumPhase,
+            last_sent_gesture_.data.scroll_update.inertial_phase);
+  EXPECT_GT(last_sent_gesture_.data.scroll_update.delta_x, 0.f);
+
+  // A non-consumed GSU ack in inertial state cancels out the rest of the fling.
+  WebGestureEvent scroll_update(
+      WebInputEvent::kGestureScrollUpdate, 0,
+      ui::EventTimeStampToSeconds(base::TimeTicks::Now()));
+  scroll_update.data.scroll_update.inertial_phase =
+      WebGestureEvent::kMomentumPhase;
+
+  fling_controller_->OnGestureEventAck(
+      GestureEventWithLatencyInfo(scroll_update),
+      INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+  EXPECT_FALSE(FlingInProgress());
+  EXPECT_EQ(WebInputEvent::kGestureScrollEnd, last_sent_gesture_.GetType());
+}
+
+TEST_F(FlingControllerTest, EarlyTouchpadFlingCancelationOnFlingStop) {
   base::TimeTicks progress_time = base::TimeTicks::Now();
   SimulateFlingStart(blink::kWebGestureDeviceTouchpad, gfx::Vector2dF(1000, 0));
   EXPECT_TRUE(FlingInProgress());
@@ -218,9 +312,96 @@
   EXPECT_EQ(0.f, last_sent_wheel_.delta_y);
 }
 
+TEST_F(FlingControllerTest, EarlyTouchscreenFlingCancelationOnFlingStop) {
+  base::TimeTicks progress_time = base::TimeTicks::Now();
+  SimulateFlingStart(blink::kWebGestureDeviceTouchscreen,
+                     gfx::Vector2dF(1000, 0));
+  EXPECT_TRUE(FlingInProgress());
+
+  // progress fling must send GSU events.
+  progress_time += base::TimeDelta::FromMilliseconds(17);
+  ProgressFling(progress_time);
+  ASSERT_EQ(WebInputEvent::kGestureScrollUpdate, last_sent_gesture_.GetType());
+  EXPECT_EQ(WebGestureEvent::kMomentumPhase,
+            last_sent_gesture_.data.scroll_update.inertial_phase);
+  EXPECT_GT(last_sent_gesture_.data.scroll_update.delta_x, 0.f);
+
+  fling_controller_->StopFling();
+  EXPECT_FALSE(FlingInProgress());
+  EXPECT_EQ(WebInputEvent::kGestureScrollEnd, last_sent_gesture_.GetType());
+}
+
+TEST_F(FlingControllerTest, GestureFlingCancelsFiltered) {
+  // GFC without previous GFS is dropped.
+  SimulateFlingCancel(blink::kWebGestureDeviceTouchscreen);
+  EXPECT_TRUE(last_fling_cancel_filtered_);
+
+  // GFC after previous GFS is filtered by fling booster.
+  SimulateFlingStart(blink::kWebGestureDeviceTouchscreen,
+                     gfx::Vector2dF(1000, 0));
+  EXPECT_TRUE(FlingInProgress());
+  SimulateFlingCancel(blink::kWebGestureDeviceTouchscreen);
+  EXPECT_TRUE(last_fling_cancel_filtered_);
+  EXPECT_TRUE(FlingInProgress());
+
+  // Any other GFC while the fling cancelation is deferred gets filtered.
+  SimulateFlingCancel(blink::kWebGestureDeviceTouchscreen);
+  EXPECT_TRUE(last_fling_cancel_filtered_);
+}
+
+TEST_F(FlingControllerTest, GestureFlingNotCancelledBySmallTimeDelta) {
+  base::TimeTicks progress_time = base::TimeTicks::Now();
+  SimulateFlingStart(blink::kWebGestureDeviceTouchscreen,
+                     gfx::Vector2dF(1000, 0));
+  EXPECT_TRUE(FlingInProgress());
+
+  // If we the first progress tick happens too close to the fling_start time,
+  // the controller won't send any GSU events, but the fling is still active.
+  // progress_time += base::TimeDelta::FromMilliseconds(1);
+  ProgressFling(progress_time);
+  EXPECT_EQ(blink::kWebGestureDeviceUninitialized,
+            last_sent_gesture_.SourceDevice());
+  EXPECT_TRUE(FlingInProgress());
+
+  // The rest of the progress flings must advance the fling normally.
+  progress_time += base::TimeDelta::FromMilliseconds(17);
+  ProgressFling(progress_time);
+  EXPECT_EQ(blink::kWebGestureDeviceTouchscreen,
+            last_sent_gesture_.SourceDevice());
+  ASSERT_EQ(WebInputEvent::kGestureScrollUpdate, last_sent_gesture_.GetType());
+  EXPECT_EQ(WebGestureEvent::kMomentumPhase,
+            last_sent_gesture_.data.scroll_update.inertial_phase);
+  EXPECT_GT(last_sent_gesture_.data.scroll_update.delta_x, 0.f);
+}
+
+TEST_F(FlingControllerTest, GestureFlingWithNegativeTimeDelta) {
+  base::TimeTicks progress_time = base::TimeTicks::Now();
+  SimulateFlingStart(blink::kWebGestureDeviceTouchscreen,
+                     gfx::Vector2dF(1000, 0));
+  EXPECT_TRUE(FlingInProgress());
+
+  // If we get a negative time delta, that is, the Progress tick time happens
+  // before the fling's start time then we should *not* try progressing the
+  // fling and instead reset the fling start time.
+  progress_time -= base::TimeDelta::FromMilliseconds(5);
+  ProgressFling(progress_time);
+  EXPECT_EQ(blink::kWebGestureDeviceUninitialized,
+            last_sent_gesture_.SourceDevice());
+
+  // The rest of the progress flings must advance the fling normally.
+  progress_time += base::TimeDelta::FromMilliseconds(17);
+  ProgressFling(progress_time);
+  EXPECT_EQ(blink::kWebGestureDeviceTouchscreen,
+            last_sent_gesture_.SourceDevice());
+  ASSERT_EQ(WebInputEvent::kGestureScrollUpdate, last_sent_gesture_.GetType());
+  EXPECT_EQ(WebGestureEvent::kMomentumPhase,
+            last_sent_gesture_.data.scroll_update.inertial_phase);
+  EXPECT_GT(last_sent_gesture_.data.scroll_update.delta_x, 0.f);
+}
+
 // TODO(sahel): Enable the test once boosting is enabled for touchpad fling.
 // https://crbug.com/249063
-TEST_F(FlingControllerTest, DISABLED_ControllerBoostsFling) {
+TEST_F(FlingControllerTest, DISABLED_ControllerBoostsTouchpadFling) {
   base::TimeTicks progress_time = base::TimeTicks::Now();
   SimulateFlingStart(blink::kWebGestureDeviceTouchpad, gfx::Vector2dF(1000, 0));
   EXPECT_TRUE(FlingInProgress());
@@ -247,4 +428,50 @@
   EXPECT_TRUE(FlingBoosted());
 }
 
+TEST_F(FlingControllerTest, ControllerBoostsTouchscreenFling) {
+  base::TimeTicks progress_time = base::TimeTicks::Now();
+  SimulateFlingStart(blink::kWebGestureDeviceTouchscreen,
+                     gfx::Vector2dF(1000, 0));
+  EXPECT_TRUE(FlingInProgress());
+
+  // Fling progress must send GSU events.
+  progress_time += base::TimeDelta::FromMilliseconds(17);
+  ProgressFling(progress_time);
+  ASSERT_EQ(WebInputEvent::kGestureScrollUpdate, last_sent_gesture_.GetType());
+  EXPECT_EQ(WebGestureEvent::kMomentumPhase,
+            last_sent_gesture_.data.scroll_update.inertial_phase);
+  EXPECT_GT(last_sent_gesture_.data.scroll_update.delta_x, 0.f);
+
+  // Now cancel the fling. The GFC will get suppressed by fling booster.
+  SimulateFlingCancel(blink::kWebGestureDeviceTouchscreen);
+  EXPECT_TRUE(last_fling_cancel_filtered_);
+  EXPECT_TRUE(FlingInProgress());
+
+  // The second GFS will boost the current active fling.
+  SimulateFlingStart(blink::kWebGestureDeviceTouchscreen,
+                     gfx::Vector2dF(1000, 0));
+  EXPECT_TRUE(FlingInProgress());
+  EXPECT_TRUE(FlingBoosted());
+}
+
+TEST_F(FlingControllerTest, ControllerNotifiesTheClientAfterFlingStart) {
+  base::TimeTicks progress_time = base::TimeTicks::Now();
+  SimulateFlingStart(blink::kWebGestureDeviceTouchscreen,
+                     gfx::Vector2dF(1000, 0));
+  EXPECT_TRUE(FlingInProgress());
+
+  // Now cancel the fling. The GFC will get suppressed by fling booster.
+  SimulateFlingCancel(blink::kWebGestureDeviceTouchscreen);
+  EXPECT_TRUE(last_fling_cancel_filtered_);
+  EXPECT_TRUE(FlingInProgress());
+
+  // Wait for the boosting timer to expire. The delayed cancelation must work
+  // and the client must be notified after fling cancelation.
+  progress_time += base::TimeDelta::FromMilliseconds(500);
+  ProgressFling(progress_time);
+  EXPECT_FALSE(FlingInProgress());
+  EXPECT_EQ(WebInputEvent::kGestureScrollEnd, last_sent_gesture_.GetType());
+  EXPECT_TRUE(notified_client_after_fling_stop_);
+}
+
 }  // namespace content
diff --git a/content/browser/renderer_host/input/gesture_event_queue.cc b/content/browser/renderer_host/input/gesture_event_queue.cc
index cca647599..4044c2e8 100644
--- a/content/browser/renderer_host/input/gesture_event_queue.cc
+++ b/content/browser/renderer_host/input/gesture_event_queue.cc
@@ -57,13 +57,15 @@
     return false;
   }
 
-  // fling_controller_ is in charge of handling GFS events from touchpad source
-  // when wheel scroll latching is enabled. In this case instead of queuing the
-  // GFS event to be sent to the renderer, the controller processes the fling
-  // and generates wheel events with momentum phase which are handled in the
-  // renderer normally.
+  // fling_controller_ is in charge of handling GFS events from touchpad and
+  // touchscreen sources. In these cases instead of queuing the GFS event to be
+  // sent to the renderer, the controller processes the fling and generates
+  // fling progress events (wheel events for touchpad and GSU events for
+  // touchscreen) which are handled normally.
   if (gesture_event.event.GetType() == WebInputEvent::kGestureFlingStart &&
-      gesture_event.event.SourceDevice() == blink::kWebGestureDeviceTouchpad) {
+      (gesture_event.event.SourceDevice() == blink::kWebGestureDeviceTouchpad ||
+       gesture_event.event.SourceDevice() ==
+           blink::kWebGestureDeviceTouchscreen)) {
     fling_controller_.ProcessGestureFlingStart(gesture_event);
     fling_in_progress_ = true;
     return false;
@@ -82,8 +84,8 @@
   return true;
 }
 
-void GestureEventQueue::ProgressFling(base::TimeTicks current_time) {
-  fling_controller_.ProgressFling(current_time);
+gfx::Vector2dF GestureEventQueue::ProgressFling(base::TimeTicks current_time) {
+  return fling_controller_.ProgressFling(current_time);
 }
 
 void GestureEventQueue::StopFling() {
@@ -91,6 +93,14 @@
   fling_controller_.StopFling();
 }
 
+bool GestureEventQueue::FlingCancellationIsDeferred() const {
+  return fling_controller_.FlingCancellationIsDeferred();
+}
+
+bool GestureEventQueue::TouchscreenFlingInProgress() const {
+  return fling_controller_.TouchscreenFlingInProgress();
+}
+
 bool GestureEventQueue::ShouldDiscardFlingCancelEvent(
     const GestureEventWithLatencyInfo& gesture_event) const {
   // When the GFS is processed by the fling_controller_ the controller handles
diff --git a/content/browser/renderer_host/input/gesture_event_queue.h b/content/browser/renderer_host/input/gesture_event_queue.h
index 451730a..6a687b9 100644
--- a/content/browser/renderer_host/input/gesture_event_queue.h
+++ b/content/browser/renderer_host/input/gesture_event_queue.h
@@ -110,12 +110,16 @@
       const GestureEventWithLatencyInfo& gesture_event) const;
 
   // Calls |fling_controller_.ProgressFling| to advance an active fling on every
-  // begin frame.
-  void ProgressFling(base::TimeTicks current_time);
+  // begin frame and returns the current fling velocity if a fling is active.
+  gfx::Vector2dF ProgressFling(base::TimeTicks current_time);
 
   // Calls |fling_controller_.StopFling| to halt an active fling if such exists.
   void StopFling();
 
+  bool FlingCancellationIsDeferred() const;
+
+  bool TouchscreenFlingInProgress() const;
+
   void set_debounce_interval_time_ms_for_testing(int interval_ms) {
     debounce_interval_ = base::TimeDelta::FromMilliseconds(interval_ms);
   }
diff --git a/content/browser/renderer_host/input/gesture_event_queue_unittest.cc b/content/browser/renderer_host/input/gesture_event_queue_unittest.cc
index f32bdcc..0bcb8dc92 100644
--- a/content/browser/renderer_host/input/gesture_event_queue_unittest.cc
+++ b/content/browser/renderer_host/input/gesture_event_queue_unittest.cc
@@ -108,7 +108,10 @@
   // FlingControllerClient
   void SendGeneratedWheelEvent(
       const MouseWheelEventWithLatencyInfo& wheel_event) override {}
+  void SendGeneratedGestureScrollEvents(
+      const GestureEventWithLatencyInfo& gesture_event) override {}
   void SetNeedsBeginFrameForFlingProgress() override {}
+  void DidStopFlingingOnBrowser() override {}
 
  protected:
   static GestureEventQueue::Config DefaultConfig() {
@@ -995,99 +998,6 @@
   EXPECT_EQ(0U, GetAndResetSentGestureEventCount());
 }
 
-TEST_P(GestureEventQueueWithSourceTest, GestureFlingCancelsFiltered) {
-  WebGestureDevice source_device = GetParam();
-
-  // GFS and GFC events with touchpad source are not queued since fling
-  // controller handles them.
-  if (source_device == blink::kWebGestureDeviceTouchpad)
-    return;
-
-  // GFC without previous GFS is dropped.
-  SimulateGestureEvent(WebInputEvent::kGestureFlingCancel, source_device);
-  EXPECT_EQ(0U, GetAndResetSentGestureEventCount());
-  EXPECT_EQ(0U, GestureEventQueueSize());
-
-  // GFC after previous GFS is dispatched and acked.
-  SimulateGestureFlingStartEvent(0, -10, source_device);
-  EXPECT_TRUE(FlingInProgress());
-  SendInputEventACK(WebInputEvent::kGestureFlingStart,
-                    INPUT_EVENT_ACK_STATE_CONSUMED);
-  RunUntilIdle();
-  EXPECT_EQ(1U, GetAndResetAckedGestureEventCount());
-  SimulateGestureEvent(WebInputEvent::kGestureFlingCancel, source_device);
-  EXPECT_FALSE(FlingInProgress());
-  EXPECT_EQ(2U, GetAndResetSentGestureEventCount());
-  SendInputEventACK(WebInputEvent::kGestureFlingCancel,
-                    INPUT_EVENT_ACK_STATE_CONSUMED);
-  RunUntilIdle();
-  EXPECT_EQ(1U, GetAndResetAckedGestureEventCount());
-  EXPECT_EQ(0U, GestureEventQueueSize());
-
-  // GFC before previous GFS is acked.
-  SimulateGestureFlingStartEvent(0, -10, source_device);
-  EXPECT_TRUE(FlingInProgress());
-  SimulateGestureEvent(WebInputEvent::kGestureFlingCancel, source_device);
-  EXPECT_FALSE(FlingInProgress());
-  EXPECT_EQ(1U, GetAndResetSentGestureEventCount());
-  EXPECT_EQ(2U, GestureEventQueueSize());
-
-  // Advance state realistically.
-  SendInputEventACK(WebInputEvent::kGestureFlingStart,
-                    INPUT_EVENT_ACK_STATE_CONSUMED);
-  RunUntilIdle();
-  EXPECT_EQ(1U, GetAndResetSentGestureEventCount());
-  SendInputEventACK(WebInputEvent::kGestureFlingCancel,
-                    INPUT_EVENT_ACK_STATE_CONSUMED);
-  RunUntilIdle();
-  EXPECT_EQ(2U, GetAndResetAckedGestureEventCount());
-  EXPECT_EQ(0U, GetAndResetSentGestureEventCount());
-  EXPECT_EQ(0U, GestureEventQueueSize());
-
-  // GFS is added to the queue if another event is pending
-  SimulateGestureScrollUpdateEvent(8, -7, 0);
-  SimulateGestureFlingStartEvent(0, -10, source_device);
-  EXPECT_EQ(2U, GestureEventQueueSize());
-  EXPECT_EQ(1U, GetAndResetSentGestureEventCount());
-  WebGestureEvent merged_event = GestureEventLastQueueEvent();
-  EXPECT_EQ(WebInputEvent::kGestureFlingStart, merged_event.GetType());
-  EXPECT_TRUE(FlingInProgress());
-  EXPECT_EQ(2U, GestureEventQueueSize());
-
-  // GFS in queue means that a GFC is added to the queue
-  SimulateGestureEvent(WebInputEvent::kGestureFlingCancel, source_device);
-  merged_event = GestureEventLastQueueEvent();
-  EXPECT_EQ(WebInputEvent::kGestureFlingCancel, merged_event.GetType());
-  EXPECT_FALSE(FlingInProgress());
-  EXPECT_EQ(3U, GestureEventQueueSize());
-
-  // Adding a second GFC is dropped.
-  SimulateGestureEvent(WebInputEvent::kGestureFlingCancel, source_device);
-  EXPECT_FALSE(FlingInProgress());
-  EXPECT_EQ(3U, GestureEventQueueSize());
-
-  // Adding another GFS will add it to the queue.
-  SimulateGestureFlingStartEvent(0, -10, source_device);
-  merged_event = GestureEventLastQueueEvent();
-  EXPECT_EQ(WebInputEvent::kGestureFlingStart, merged_event.GetType());
-  EXPECT_TRUE(FlingInProgress());
-  EXPECT_EQ(4U, GestureEventQueueSize());
-
-  // GFS in queue means that a GFC is added to the queue
-  SimulateGestureEvent(WebInputEvent::kGestureFlingCancel, source_device);
-  merged_event = GestureEventLastQueueEvent();
-  EXPECT_EQ(WebInputEvent::kGestureFlingCancel, merged_event.GetType());
-  EXPECT_FALSE(FlingInProgress());
-  EXPECT_EQ(5U, GestureEventQueueSize());
-
-  // Adding another GFC with a GFC already there is dropped.
-  SimulateGestureEvent(WebInputEvent::kGestureFlingCancel, source_device);
-  merged_event = GestureEventLastQueueEvent();
-  EXPECT_EQ(WebInputEvent::kGestureFlingCancel, merged_event.GetType());
-  EXPECT_FALSE(FlingInProgress());
-  EXPECT_EQ(5U, GestureEventQueueSize());
-}
-
 INSTANTIATE_TEST_CASE_P(AllSources,
                         GestureEventQueueWithSourceTest,
                         testing::Values(blink::kWebGestureDeviceTouchscreen,
@@ -1252,25 +1162,24 @@
   SetUpForTapSuppression(400, 200);
   SimulateGestureFlingStartEvent(0, -10, blink::kWebGestureDeviceTouchscreen);
   EXPECT_TRUE(FlingInProgress());
-  SendInputEventACK(WebInputEvent::kGestureFlingStart,
-                    INPUT_EVENT_ACK_STATE_CONSUMED);
-  EXPECT_EQ(1U, GetAndResetSentGestureEventCount());
-  EXPECT_EQ(1U, GetAndResetAckedGestureEventCount());
+  // The fling start event is not sent to the renderer.
+  EXPECT_EQ(0U, GetAndResetSentGestureEventCount());
+  EXPECT_EQ(0U, GetAndResetAckedGestureEventCount());
   RunUntilIdle();
 
+  // Simulate a fling cancel event before sending a gesture tap down event. The
+  // fling cancel event is not sent to the renderer.
   SimulateGestureEvent(WebInputEvent::kGestureFlingCancel,
                        blink::kWebGestureDeviceTouchscreen);
   EXPECT_FALSE(FlingInProgress());
-  EXPECT_EQ(1U, GetAndResetSentGestureEventCount());
-  EXPECT_EQ(1U, GestureEventQueueSize());
+  EXPECT_EQ(0U, GetAndResetSentGestureEventCount());
+  EXPECT_EQ(0U, GestureEventQueueSize());
   RunUntilIdle();
 
-  // Simulate a fling cancelling tap down by sending a gesture tap down event
-  // before arrival of the fling cancel ack. The tap down must get suppressed.
+  // Simulate a fling cancelling tap down. The tap down must get suppressed
+  // since the fling cancel event is processed by the fling controller.
   SimulateGestureEvent(WebInputEvent::kGestureTapDown,
                        blink::kWebGestureDeviceTouchscreen);
-  SendInputEventACK(WebInputEvent::kGestureFlingCancel,
-                    INPUT_EVENT_ACK_STATE_CONSUMED);
   EXPECT_EQ(0U, GestureEventQueueSize());
 
   // The tap event must get suppressed since its corresponding tap down event
diff --git a/content/browser/renderer_host/input/input_router.h b/content/browser/renderer_host/input/input_router.h
index 1bed5fa..01645d1 100644
--- a/content/browser/renderer_host/input/input_router.h
+++ b/content/browser/renderer_host/input/input_router.h
@@ -72,6 +72,9 @@
 
   // Used to stop an active fling if such exists.
   virtual void StopFling() = 0;
+
+  // Used to check if a fling cancellation is deferred due to boosting or not.
+  virtual bool FlingCancellationIsDeferred() = 0;
 };
 
 }  // namespace content
diff --git a/content/browser/renderer_host/input/input_router_client.h b/content/browser/renderer_host/input/input_router_client.h
index dfd8960..abf83c7d 100644
--- a/content/browser/renderer_host/input/input_router_client.h
+++ b/content/browser/renderer_host/input/input_router_client.h
@@ -54,6 +54,9 @@
   // Called when a renderer fling has terminated.
   virtual void DidStopFlinging() = 0;
 
+  // Called when a GSB has started scrolling a viewport.
+  virtual void DidStartScrollingViewport() = 0;
+
   // Called when the input router generates an event. It is intended that the
   // client will do some processing on |gesture_event| and then send it back
   // to the InputRouter via SendGestureEvent.
diff --git a/content/browser/renderer_host/input/input_router_impl.cc b/content/browser/renderer_host/input/input_router_impl.cc
index 1fd1ae0c..b54fbd55 100644
--- a/content/browser/renderer_host/input/input_router_impl.cc
+++ b/content/browser/renderer_host/input/input_router_impl.cc
@@ -117,6 +117,7 @@
 
 void InputRouterImpl::SendKeyboardEvent(
     const NativeWebKeyboardEventWithLatencyInfo& key_event) {
+  gesture_event_queue_.StopFling();
   gesture_event_queue_.FlingHasBeenHalted();
   mojom::WidgetInputHandler::DispatchEventCallback callback = base::BindOnce(
       &InputRouterImpl::KeyboardEventHandled, weak_this_, key_event);
@@ -126,7 +127,8 @@
 
 void InputRouterImpl::SendGestureEvent(
     const GestureEventWithLatencyInfo& original_gesture_event) {
-  input_stream_validator_.Validate(original_gesture_event.event);
+  input_stream_validator_.Validate(original_gesture_event.event,
+                                   FlingCancellationIsDeferred());
 
   GestureEventWithLatencyInfo gesture_event(original_gesture_event);
 
@@ -209,13 +211,22 @@
 }
 
 void InputRouterImpl::ProgressFling(base::TimeTicks current_time) {
-  gesture_event_queue_.ProgressFling(current_time);
+  current_fling_velocity_ = gesture_event_queue_.ProgressFling(current_time);
 }
 
 void InputRouterImpl::StopFling() {
   gesture_event_queue_.StopFling();
 }
 
+bool InputRouterImpl::FlingCancellationIsDeferred() {
+  return gesture_event_queue_.FlingCancellationIsDeferred();
+}
+
+void InputRouterImpl::DidStopFlingingOnBrowser() {
+  current_fling_velocity_ = gfx::Vector2dF();
+  client_->DidStopFlinging();
+}
+
 void InputRouterImpl::CancelTouchTimeout() {
   touch_event_queue_.SetAckTimeoutEnabled(false);
 }
@@ -231,7 +242,10 @@
 }
 
 void InputRouterImpl::DidOverscroll(const ui::DidOverscrollParams& params) {
-  client_->DidOverscroll(params);
+  // Touchpad and Touchscreen flings are handled on the browser side.
+  ui::DidOverscrollParams fling_updated_params = params;
+  fling_updated_params.current_fling_velocity = current_fling_velocity_;
+  client_->DidOverscroll(fling_updated_params);
 }
 
 void InputRouterImpl::DidStopFlinging() {
@@ -243,6 +257,10 @@
   client_->DidStopFlinging();
 }
 
+void InputRouterImpl::DidStartScrollingViewport() {
+  client_->DidStartScrollingViewport();
+}
+
 void InputRouterImpl::ImeCancelComposition() {
   client_->OnImeCancelComposition();
 }
@@ -341,6 +359,10 @@
   output_stream_validator_.Validate(touch_event);
 }
 
+bool InputRouterImpl::TouchscreenFlingInProgress() {
+  return gesture_event_queue_.TouchscreenFlingInProgress();
+}
+
 void InputRouterImpl::SendGestureEventImmediately(
     const GestureEventWithLatencyInfo& gesture_event) {
   mojom::WidgetInputHandler::DispatchEventCallback callback = base::BindOnce(
@@ -363,6 +385,12 @@
                                             wheel_event.latency);
 }
 
+void InputRouterImpl::SendGeneratedGestureScrollEvents(
+    const GestureEventWithLatencyInfo& gesture_event) {
+  client_->ForwardGestureEventWithLatencyInfo(gesture_event.event,
+                                              gesture_event.latency);
+}
+
 void InputRouterImpl::SetNeedsBeginFrameForFlingProgress() {
   client_->SetNeedsBeginFrameForFlingProgress();
 }
diff --git a/content/browser/renderer_host/input/input_router_impl.h b/content/browser/renderer_host/input/input_router_impl.h
index 5f476e7..5b62b9a 100644
--- a/content/browser/renderer_host/input/input_router_impl.h
+++ b/content/browser/renderer_host/input/input_router_impl.h
@@ -81,6 +81,8 @@
                 bool frame_handler) override;
   void ProgressFling(base::TimeTicks current_time) override;
   void StopFling() override;
+  bool FlingCancellationIsDeferred() override;
+  void DidStopFlingingOnBrowser() override;
 
   // InputHandlerHost impl
   void CancelTouchTimeout() override;
@@ -90,6 +92,7 @@
   void DidOverscroll(const ui::DidOverscrollParams& params) override;
   void DidStopFlinging() override;
   void ImeCancelComposition() override;
+  void DidStartScrollingViewport() override;
   void ImeCompositionRangeChanged(
       const gfx::Range& range,
       const std::vector<gfx::Rect>& bounds) override;
@@ -114,6 +117,7 @@
                        InputEventAckSource ack_source,
                        InputEventAckState ack_result) override;
   void OnFilteringTouchEvent(const blink::WebTouchEvent& touch_event) override;
+  bool TouchscreenFlingInProgress() override;
 
   // GestureEventFilterClient
   void SendGestureEventImmediately(
@@ -125,6 +129,8 @@
   // FlingControllerClient
   void SendGeneratedWheelEvent(
       const MouseWheelEventWithLatencyInfo& wheel_event) override;
+  void SendGeneratedGestureScrollEvents(
+      const GestureEventWithLatencyInfo& gesture_event) override;
   void SetNeedsBeginFrameForFlingProgress() override;
 
   // MouseWheelEventQueueClient
@@ -212,6 +218,8 @@
 
   float device_scale_factor_;
 
+  gfx::Vector2dF current_fling_velocity_;
+
   // Last touch position relative to screen. Used to compute movementX/Y.
   base::flat_map<int, gfx::Point> global_touch_position_;
 
diff --git a/content/browser/renderer_host/input/input_router_impl_unittest.cc b/content/browser/renderer_host/input/input_router_impl_unittest.cc
index c4b2f4ca..9c25e2a 100644
--- a/content/browser/renderer_host/input/input_router_impl_unittest.cc
+++ b/content/browser/renderer_host/input/input_router_impl_unittest.cc
@@ -144,6 +144,10 @@
 
   void DidStopFlinging() override { input_router_client_.DidStopFlinging(); }
 
+  void DidStartScrollingViewport() override {
+    input_router_client_.DidStartScrollingViewport();
+  }
+
   void SetNeedsBeginFrameForFlingProgress() override {
     input_router_client_.SetNeedsBeginFrameForFlingProgress();
   }
@@ -968,22 +972,30 @@
       SimulateGestureEvent(type, blink::kWebGestureDeviceTouchscreen);
       DispatchedMessages dispatched_messages = GetAndResetDispatchedMessages();
 
-      if (type == WebInputEvent::kGestureScrollUpdate)
-        EXPECT_EQ(2U, dispatched_messages.size());
-      else
-        EXPECT_EQ(1U, dispatched_messages.size());
-      EXPECT_EQ(0U, disposition_handler_->GetAndResetAckCount());
-      EXPECT_EQ(1, client_->in_flight_event_count());
-      EXPECT_TRUE(HasPendingEvents());
-      ASSERT_TRUE(
-          dispatched_messages[dispatched_messages.size() - 1]->ToEvent());
+      if (type != WebInputEvent::kGestureFlingStart &&
+          type != WebInputEvent::kGestureFlingCancel) {
+        if (type == WebInputEvent::kGestureScrollUpdate)
+          EXPECT_EQ(2U, dispatched_messages.size());
+        else
+          EXPECT_EQ(1U, dispatched_messages.size());
+        EXPECT_EQ(0U, disposition_handler_->GetAndResetAckCount());
+        EXPECT_EQ(1, client_->in_flight_event_count());
+        EXPECT_TRUE(HasPendingEvents());
+        ASSERT_TRUE(
+            dispatched_messages[dispatched_messages.size() - 1]->ToEvent());
 
-      dispatched_messages[dispatched_messages.size() - 1]
-          ->ToEvent()
-          ->CallCallback(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+        dispatched_messages[dispatched_messages.size() - 1]
+            ->ToEvent()
+            ->CallCallback(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+      }
 
       EXPECT_EQ(0U, GetAndResetDispatchedMessages().size());
-      EXPECT_EQ(1U, disposition_handler_->GetAndResetAckCount());
+      if (type == WebInputEvent::kGestureFlingCancel) {
+        // fling controller generates and sends a GSE while handling the GFC.
+        EXPECT_EQ(2U, disposition_handler_->GetAndResetAckCount());
+      } else {
+        EXPECT_EQ(1U, disposition_handler_->GetAndResetAckCount());
+      }
       EXPECT_EQ(0, client_->in_flight_event_count());
       EXPECT_FALSE(HasPendingEvents());
       continue;
@@ -1813,8 +1825,11 @@
             client_overscroll.accumulated_overscroll);
   EXPECT_EQ(overscroll.latest_overscroll_delta,
             client_overscroll.latest_overscroll_delta);
-  EXPECT_EQ(overscroll.current_fling_velocity,
-            client_overscroll.current_fling_velocity);
+  // With browser side fling, the fling velocity doesn't come from overscroll
+  // params of the renderer, instead the input router sets the
+  // params.current_fling_velocity based on the velocity received from the fling
+  // controller.
+  EXPECT_EQ(gfx::Vector2dF(), client_overscroll.current_fling_velocity);
 
   DidOverscrollParams wheel_overscroll;
   wheel_overscroll.accumulated_overscroll = gfx::Vector2dF(7, -7);
@@ -1838,8 +1853,11 @@
             client_overscroll.accumulated_overscroll);
   EXPECT_EQ(wheel_overscroll.latest_overscroll_delta,
             client_overscroll.latest_overscroll_delta);
-  EXPECT_EQ(wheel_overscroll.current_fling_velocity,
-            client_overscroll.current_fling_velocity);
+  // With browser side fling, the fling velocity doesn't come from overscroll
+  // params of the renderer, instead the input router sets the
+  // params.current_fling_velocity based on the velocity received from the fling
+  // controller.
+  EXPECT_EQ(gfx::Vector2dF(), client_overscroll.current_fling_velocity);
 }
 
 TEST_F(InputRouterImplTest, OverscrollDispatch) {
@@ -2349,25 +2367,33 @@
   const gfx::PointF orig(10, 20), scaled(20, 40);
   WebGestureEvent event =
       BuildGestureEvent(WebInputEvent::kGestureFlingStart, orig);
-  // Set the source device to touchscreen to make sure that the event gets
-  // dispatched to the renderer. When wheel scroll latching is enabled touchpad
-  // flings are not dispatched to the renderer, instead they are handled on the
-  // browser side.
   event.SetSourceDevice(blink::kWebGestureDeviceTouchscreen);
   event.data.fling_start.velocity_x = 30;
   event.data.fling_start.velocity_y = 40;
   SimulateGestureEvent(event);
-  FlushGestureEvent(WebInputEvent::kGestureFlingStart);
+  // Fling events don't get sent to the renderer.
+  UpdateDispatchedMessages();
+  ASSERT_EQ(0u, dispatched_messages_.size());
 
-  const WebGestureEvent* sent_event = GetSentWebInputEvent<WebGestureEvent>();
+  // Progress the fling and check the first GestureScrollUpdate generated by
+  // fling progress, note that |at(0)| is TouchScrollStarted.
+  base::TimeTicks progress_time =
+      base::TimeTicks::Now() + base::TimeDelta::FromMilliseconds(17);
+  input_router_->ProgressFling(progress_time);
+  UpdateDispatchedMessages();
+  ASSERT_EQ(2u, dispatched_messages_.size());
+  const WebGestureEvent* sent_event = static_cast<const WebGestureEvent*>(
+      dispatched_messages_[1]->ToEvent()->Event()->web_event.get());
   TestLocationInSentEvent(sent_event, orig, scaled);
-  EXPECT_EQ(60, sent_event->data.fling_start.velocity_x);
-  EXPECT_EQ(80, sent_event->data.fling_start.velocity_y);
+  float sent_delta_x = sent_event->data.scroll_update.delta_x;
+  float sent_delta_y = sent_event->data.scroll_update.delta_y;
+  EXPECT_LT(0, sent_delta_x);
+  EXPECT_LT(0, sent_delta_y);
 
   const WebGestureEvent* filter_event =
       GetFilterWebInputEvent<WebGestureEvent>();
   TestLocationInFilterEvent(filter_event, orig);
-  EXPECT_EQ(30, filter_event->data.fling_start.velocity_x);
-  EXPECT_EQ(40, filter_event->data.fling_start.velocity_y);
+  EXPECT_FLOAT_EQ(sent_delta_x, 2 * filter_event->data.scroll_update.delta_x);
+  EXPECT_FLOAT_EQ(sent_delta_y, 2 * filter_event->data.scroll_update.delta_y);
 }
 }  // namespace content
diff --git a/content/browser/renderer_host/input/legacy_input_router_impl.cc b/content/browser/renderer_host/input/legacy_input_router_impl.cc
index 8237c18..4af1d6c 100644
--- a/content/browser/renderer_host/input/legacy_input_router_impl.cc
+++ b/content/browser/renderer_host/input/legacy_input_router_impl.cc
@@ -129,7 +129,8 @@
 
 void LegacyInputRouterImpl::SendGestureEvent(
     const GestureEventWithLatencyInfo& original_gesture_event) {
-  input_stream_validator_.Validate(original_gesture_event.event);
+  input_stream_validator_.Validate(original_gesture_event.event,
+                                   FlingCancellationIsDeferred());
 
   GestureEventWithLatencyInfo gesture_event(original_gesture_event);
 
@@ -208,13 +209,22 @@
 }
 
 void LegacyInputRouterImpl::ProgressFling(base::TimeTicks current_time) {
-  gesture_event_queue_.ProgressFling(current_time);
+  current_fling_velocity_ = gesture_event_queue_.ProgressFling(current_time);
 }
 
 void LegacyInputRouterImpl::StopFling() {
   gesture_event_queue_.StopFling();
 }
 
+bool LegacyInputRouterImpl::FlingCancellationIsDeferred() {
+  return gesture_event_queue_.FlingCancellationIsDeferred();
+}
+
+void LegacyInputRouterImpl::DidStopFlingingOnBrowser() {
+  current_fling_velocity_ = gfx::Vector2dF();
+  client_->DidStopFlinging();
+}
+
 bool LegacyInputRouterImpl::OnMessageReceived(const IPC::Message& message) {
   bool handled = true;
   IPC_BEGIN_MESSAGE_MAP(LegacyInputRouterImpl, message)
@@ -230,6 +240,8 @@
     IPC_MESSAGE_HANDLER(InputHostMsg_SetWhiteListedTouchAction,
                         OnSetWhiteListedTouchAction)
     IPC_MESSAGE_HANDLER(InputHostMsg_DidStopFlinging, OnDidStopFlinging)
+    IPC_MESSAGE_HANDLER(InputHostMsg_DidStartScrollingViewport,
+                        OnDidStartScrollingViewport)
     IPC_MESSAGE_UNHANDLED(handled = false)
   IPC_END_MESSAGE_MAP()
 
@@ -268,6 +280,10 @@
   output_stream_validator_.Validate(touch_event);
 }
 
+bool LegacyInputRouterImpl::TouchscreenFlingInProgress() {
+  return gesture_event_queue_.TouchscreenFlingInProgress();
+}
+
 void LegacyInputRouterImpl::OnGestureEventAck(
     const GestureEventWithLatencyInfo& event,
     InputEventAckSource ack_source,
@@ -288,6 +304,12 @@
                                             wheel_event.latency);
 }
 
+void LegacyInputRouterImpl::SendGeneratedGestureScrollEvents(
+    const GestureEventWithLatencyInfo& gesture_event) {
+  client_->ForwardGestureEventWithLatencyInfo(gesture_event.event,
+                                              gesture_event.latency);
+}
+
 void LegacyInputRouterImpl::SetNeedsBeginFrameForFlingProgress() {
   client_->SetNeedsBeginFrameForFlingProgress();
 }
@@ -452,7 +474,10 @@
 
 void LegacyInputRouterImpl::OnDidOverscroll(
     const ui::DidOverscrollParams& params) {
-  client_->DidOverscroll(params);
+  // Touchpad and Touchscreen flings are handled on the browser side.
+  ui::DidOverscrollParams fling_updated_params = params;
+  fling_updated_params.current_fling_velocity = current_fling_velocity_;
+  client_->DidOverscroll(fling_updated_params);
 }
 
 void LegacyInputRouterImpl::OnMsgMoveCaretAck() {
@@ -523,6 +548,10 @@
   client_->DidStopFlinging();
 }
 
+void LegacyInputRouterImpl::OnDidStartScrollingViewport() {
+  client_->DidStartScrollingViewport();
+}
+
 void LegacyInputRouterImpl::ProcessInputEventAck(
     WebInputEvent::Type event_type,
     InputEventAckSource ack_source,
diff --git a/content/browser/renderer_host/input/legacy_input_router_impl.h b/content/browser/renderer_host/input/legacy_input_router_impl.h
index b762f814..d6412d6 100644
--- a/content/browser/renderer_host/input/legacy_input_router_impl.h
+++ b/content/browser/renderer_host/input/legacy_input_router_impl.h
@@ -77,6 +77,8 @@
                 bool frame_handler) override;
   void ProgressFling(base::TimeTicks current_time) override;
   void StopFling() override;
+  bool FlingCancellationIsDeferred() override;
+  void DidStopFlingingOnBrowser() override;
 
   // IPC::Listener
   bool OnMessageReceived(const IPC::Message& message) override;
@@ -110,6 +112,7 @@
                        InputEventAckSource ack_source,
                        InputEventAckState ack_result) override;
   void OnFilteringTouchEvent(const blink::WebTouchEvent& touch_event) override;
+  bool TouchscreenFlingInProgress() override;
 
   // GestureEventFilterClient
   void SendGestureEventImmediately(
@@ -121,6 +124,8 @@
   // FlingControllerClient
   void SendGeneratedWheelEvent(
       const MouseWheelEventWithLatencyInfo& wheel_event) override;
+  void SendGeneratedGestureScrollEvents(
+      const GestureEventWithLatencyInfo& gesture_event) override;
   void SetNeedsBeginFrameForFlingProgress() override;
 
   // MouseWheelEventQueueClient
@@ -168,6 +173,7 @@
                                    uint32_t unique_touch_event_id,
                                    InputEventAckState ack_result);
   void OnDidStopFlinging();
+  void OnDidStartScrollingViewport();
 
   // Note: This function may result in |this| being deleted, and as such
   // should be the last method called in any internal chain of event handling.
@@ -270,6 +276,8 @@
   // Last touch position relative to screen. Used to compute movementX/Y.
   std::map<int, gfx::Point> global_touch_position_;
 
+  gfx::Vector2dF current_fling_velocity_;
+
   DISALLOW_COPY_AND_ASSIGN(LegacyInputRouterImpl);
 };
 
diff --git a/content/browser/renderer_host/input/legacy_input_router_impl_perftest.cc b/content/browser/renderer_host/input/legacy_input_router_impl_perftest.cc
index c8afe30..97d32e7e 100644
--- a/content/browser/renderer_host/input/legacy_input_router_impl_perftest.cc
+++ b/content/browser/renderer_host/input/legacy_input_router_impl_perftest.cc
@@ -98,6 +98,7 @@
   void OnSetWhiteListedTouchAction(
       cc::TouchAction white_listed_touch_action) override {}
   void DidStopFlinging() override {}
+  void DidStartScrollingViewport() override {}
   void ForwardWheelEventWithLatencyInfo(
       const blink::WebMouseWheelEvent& event,
       const ui::LatencyInfo& latency_info) override {}
diff --git a/content/browser/renderer_host/input/legacy_input_router_impl_unittest.cc b/content/browser/renderer_host/input/legacy_input_router_impl_unittest.cc
index 4016d94..5a6f958 100644
--- a/content/browser/renderer_host/input/legacy_input_router_impl_unittest.cc
+++ b/content/browser/renderer_host/input/legacy_input_router_impl_unittest.cc
@@ -1085,17 +1085,31 @@
     WebInputEvent::Type type = eventTypes[i];
     if (ShouldBlockEventStream(GetEventWithType(type))) {
       SimulateGestureEvent(type, blink::kWebGestureDeviceTouchscreen);
-      if (type == WebInputEvent::kGestureScrollUpdate)
-        EXPECT_EQ(2U, GetSentMessageCountAndResetSink());
-      else
+      if (type == WebInputEvent::kGestureFlingStart) {
+        // Fling start event is not sent to the renderer.
+        EXPECT_EQ(0U, GetSentMessageCountAndResetSink());
+        EXPECT_EQ(0U, disposition_handler_->GetAndResetAckCount());
+      } else if (type == WebInputEvent::kGestureFlingCancel) {
+        // The fling controller processes the GFC to generate and send a GSE.
         EXPECT_EQ(1U, GetSentMessageCountAndResetSink());
-      EXPECT_EQ(0U, disposition_handler_->GetAndResetAckCount());
-      EXPECT_EQ(1, client_->in_flight_event_count());
-      EXPECT_TRUE(HasPendingEvents());
+        EXPECT_EQ(1U, disposition_handler_->GetAndResetAckCount());
+        EXPECT_EQ(WebInputEvent::kGestureScrollEnd,
+                  disposition_handler_->acked_gesture_event().GetType());
+      } else {  // type!=WebInputEvent::kGestureFlingStart && type !=
+                // WebInputEvent::kGestureFlingCancel)
+        if (type == WebInputEvent::kGestureScrollUpdate)
+          EXPECT_EQ(2U, GetSentMessageCountAndResetSink());
+        else
+          EXPECT_EQ(1U, GetSentMessageCountAndResetSink());
+        EXPECT_EQ(0U, disposition_handler_->GetAndResetAckCount());
+        EXPECT_EQ(1, client_->in_flight_event_count());
+        EXPECT_TRUE(HasPendingEvents());
 
-      SendInputEventACK(type, INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
-      EXPECT_EQ(0U, GetSentMessageCountAndResetSink());
-      EXPECT_EQ(1U, disposition_handler_->GetAndResetAckCount());
+        SendInputEventACK(type, INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+
+        EXPECT_EQ(0U, GetSentMessageCountAndResetSink());
+        EXPECT_EQ(1U, disposition_handler_->GetAndResetAckCount());
+      }
       EXPECT_EQ(0, client_->in_flight_event_count());
       EXPECT_FALSE(HasPendingEvents());
       continue;
@@ -1800,8 +1814,11 @@
             client_overscroll.accumulated_overscroll);
   EXPECT_EQ(overscroll.latest_overscroll_delta,
             client_overscroll.latest_overscroll_delta);
-  EXPECT_EQ(overscroll.current_fling_velocity,
-            client_overscroll.current_fling_velocity);
+  // With browser side fling, the fling velocity doesn't come from overscroll
+  // params of the renderer, instead the input router sets the
+  // params.current_fling_velocity based on the velocity received from the fling
+  // controller.
+  EXPECT_EQ(gfx::Vector2dF(), client_overscroll.current_fling_velocity);
 
   DidOverscrollParams wheel_overscroll;
   wheel_overscroll.accumulated_overscroll = gfx::Vector2dF(7, -7);
@@ -1822,8 +1839,11 @@
             client_overscroll.accumulated_overscroll);
   EXPECT_EQ(wheel_overscroll.latest_overscroll_delta,
             client_overscroll.latest_overscroll_delta);
-  EXPECT_EQ(wheel_overscroll.current_fling_velocity,
-            client_overscroll.current_fling_velocity);
+  // With browser side fling, the fling velocity doesn't come from overscroll
+  // params of the renderer, instead the input router sets the
+  // params.current_fling_velocity based on the velocity received from the fling
+  // controller.
+  EXPECT_EQ(gfx::Vector2dF(), client_overscroll.current_fling_velocity);
 }
 TEST_F(LegacyInputRouterImplTest, OverscrollDispatch) {
   OverscrollDispatch();
@@ -2302,25 +2322,32 @@
   const gfx::PointF orig(10, 20), scaled(20, 40);
   WebGestureEvent event =
       BuildGestureEvent(WebInputEvent::kGestureFlingStart, orig);
-  // Set the source device to touchscreen to make sure that the event gets
-  // dispatched to the renderer. When wheel scroll latching is enabled touchpad
-  // flings are not dispatched to the renderer, instead they are handled on the
-  // browser side.
   event.SetSourceDevice(blink::kWebGestureDeviceTouchscreen);
   event.data.fling_start.velocity_x = 30;
   event.data.fling_start.velocity_y = 40;
   SimulateGestureEvent(event);
+  // Fling events don't get sent to the renderer.
+  EXPECT_EQ(0u, process_->sink().message_count());
 
-  const WebGestureEvent* sent_event = GetSentWebInputEvent<WebGestureEvent>();
+  // Progress the fling and check the first GestureScrollUpdate generated by
+  // fling progress, note that |at(0)| is TouchScrollStarted.
+  base::TimeTicks progress_time =
+      base::TimeTicks::Now() + base::TimeDelta::FromMilliseconds(17);
+  input_router_->ProgressFling(progress_time);
+  EXPECT_EQ(2u, process_->sink().message_count());
+  const WebGestureEvent* sent_event = static_cast<const WebGestureEvent*>(
+      GetInputEventFromMessage(*process_->sink().GetMessageAt(1)));
   TestLocationInSentEvent(sent_event, orig, scaled);
-  EXPECT_EQ(60, sent_event->data.fling_start.velocity_x);
-  EXPECT_EQ(80, sent_event->data.fling_start.velocity_y);
+  float sent_delta_x = sent_event->data.scroll_update.delta_x;
+  float sent_delta_y = sent_event->data.scroll_update.delta_y;
+  EXPECT_LT(0, sent_delta_x);
+  EXPECT_LT(0, sent_delta_y);
 
   const WebGestureEvent* filter_event =
       GetFilterWebInputEvent<WebGestureEvent>();
   TestLocationInFilterEvent(filter_event, orig);
-  EXPECT_EQ(30, filter_event->data.fling_start.velocity_x);
-  EXPECT_EQ(40, filter_event->data.fling_start.velocity_y);
+  EXPECT_FLOAT_EQ(sent_delta_x, 2 * filter_event->data.scroll_update.delta_x);
+  EXPECT_FLOAT_EQ(sent_delta_y, 2 * filter_event->data.scroll_update.delta_y);
 }
 
 }  // namespace content
diff --git a/content/browser/renderer_host/input/mock_input_router_client.cc b/content/browser/renderer_host/input/mock_input_router_client.cc
index 203b668..c9716092 100644
--- a/content/browser/renderer_host/input/mock_input_router_client.cc
+++ b/content/browser/renderer_host/input/mock_input_router_client.cc
@@ -63,6 +63,8 @@
 void MockInputRouterClient::DidStopFlinging() {
 }
 
+void MockInputRouterClient::DidStartScrollingViewport() {}
+
 void MockInputRouterClient::SetNeedsBeginFrameForFlingProgress() {}
 
 void MockInputRouterClient::ForwardGestureEventWithLatencyInfo(
diff --git a/content/browser/renderer_host/input/mock_input_router_client.h b/content/browser/renderer_host/input/mock_input_router_client.h
index 5ce892b..057c571 100644
--- a/content/browser/renderer_host/input/mock_input_router_client.h
+++ b/content/browser/renderer_host/input/mock_input_router_client.h
@@ -32,6 +32,7 @@
   void DidOverscroll(const ui::DidOverscrollParams& params) override;
   void OnSetWhiteListedTouchAction(cc::TouchAction touch_action) override;
   void DidStopFlinging() override;
+  void DidStartScrollingViewport() override;
   void SetNeedsBeginFrameForFlingProgress() override;
   void ForwardWheelEventWithLatencyInfo(
       const blink::WebMouseWheelEvent& wheel_event,
diff --git a/content/browser/renderer_host/input/non_blocking_event_browsertest.cc b/content/browser/renderer_host/input/non_blocking_event_browsertest.cc
index 7369507..06cc129 100644
--- a/content/browser/renderer_host/input/non_blocking_event_browsertest.cc
+++ b/content/browser/renderer_host/input/non_blocking_event_browsertest.cc
@@ -26,6 +26,7 @@
 #include "content/public/test/test_utils.h"
 #include "content/shell/browser/shell.h"
 #include "third_party/WebKit/public/platform/WebInputEvent.h"
+#include "ui/events/base_event_utils.h"
 #include "ui/events/event_switches.h"
 #include "ui/latency/latency_info.h"
 
@@ -75,6 +76,23 @@
     "  document.title='ready';"
     "</script>";
 
+const char kBlockingTouchStartDataURL[] =
+    "data:text/html;charset=utf-8,"
+    "<!DOCTYPE html>"
+    "<meta name='viewport' content='width=device-width'/>"
+    "<style>"
+    "html, body {"
+    "  margin: 0;"
+    "}"
+    ".spacer { height: 10000px; }"
+    "</style>"
+    "<div class=spacer></div>"
+    "<script>"
+    "  document.addEventListener('touchstart', function(e) { while(true) {} }, "
+    "{'passive': false});"
+    "  document.title='ready';"
+    "</script>";
+
 }  // namespace
 
 namespace content {
@@ -206,6 +224,61 @@
 
 // Disabled on MacOS because it doesn't support touch input.
 #if defined(OS_MACOSX)
+#define MAYBE_TouchStartDuringFling DISABLED_TouchStartDuringFling
+#else
+#define MAYBE_TouchStartDuringFling TouchStartDuringFling
+#endif
+IN_PROC_BROWSER_TEST_F(NonBlockingEventBrowserTest,
+                       MAYBE_TouchStartDuringFling) {
+  LoadURL(kBlockingTouchStartDataURL);
+
+  // Send GSB to start scrolling sequence.
+  blink::WebGestureEvent gesture_scroll_begin(
+      blink::WebGestureEvent::kGestureScrollBegin,
+      blink::WebInputEvent::kNoModifiers,
+      ui::EventTimeStampToSeconds(ui::EventTimeForNow()));
+  gesture_scroll_begin.SetSourceDevice(blink::kWebGestureDeviceTouchscreen);
+  gesture_scroll_begin.data.scroll_begin.delta_hint_units =
+      blink::WebGestureEvent::ScrollUnits::kPrecisePixels;
+  gesture_scroll_begin.data.scroll_begin.delta_x_hint = 0.f;
+  gesture_scroll_begin.data.scroll_begin.delta_y_hint = -5.f;
+  GetWidgetHost()->ForwardGestureEvent(gesture_scroll_begin);
+
+  //  Send a GFS and wait for the page to scroll making sure that fling progress
+  //  has started.
+  blink::WebGestureEvent gesture_fling_start(
+      blink::WebGestureEvent::kGestureFlingStart,
+      blink::WebInputEvent::kNoModifiers,
+      ui::EventTimeStampToSeconds(ui::EventTimeForNow()));
+  gesture_fling_start.SetSourceDevice(blink::kWebGestureDeviceTouchscreen);
+  gesture_fling_start.data.fling_start.velocity_x = 0.f;
+  gesture_fling_start.data.fling_start.velocity_y = -2000.f;
+  GetWidgetHost()->ForwardGestureEvent(gesture_fling_start);
+  RenderFrameSubmissionObserver observer(
+      GetWidgetHost()->render_frame_metadata_provider());
+  gfx::Vector2dF default_scroll_offset;
+  while (observer.LastRenderFrameMetadata()
+             .root_scroll_offset.value_or(default_scroll_offset)
+             .y() <= 0)
+    observer.WaitForMetadataChange();
+
+  // Send a touch start event and wait for its ack. The touch start must be
+  // uncancelable since there is an on-going fling with touchscreen source. The
+  // test will timeout if the touch start event is cancelable since there is a
+  // busy loop in the blocking touch start event listener.
+  InputEventAckWaiter touch_start_ack_observer(GetWidgetHost(),
+                                               WebInputEvent::kTouchStart);
+  SyntheticWebTouchEvent touch_event;
+  touch_event.PressPoint(50, 50);
+  touch_event.SetTimeStampSeconds(
+      ui::EventTimeStampToSeconds(ui::EventTimeForNow()));
+  GetWidgetHost()->ForwardTouchEventWithLatencyInfo(touch_event,
+                                                    ui::LatencyInfo());
+  touch_start_ack_observer.Wait();
+}
+
+// Disabled on MacOS because it doesn't support touch input.
+#if defined(OS_MACOSX)
 #define MAYBE_PassiveTouchStartBlockingTouchEnd \
   DISABLED_PassiveTouchStartBlockingTouchEnd
 #else
diff --git a/content/browser/renderer_host/input/passthrough_touch_event_queue.cc b/content/browser/renderer_host/input/passthrough_touch_event_queue.cc
index 2a5358c..2058f2e 100644
--- a/content/browser/renderer_host/input/passthrough_touch_event_queue.cc
+++ b/content/browser/renderer_host/input/passthrough_touch_event_queue.cc
@@ -245,8 +245,13 @@
       touch->event.GetType() != WebInputEvent::kTouchStart)
     touch->event.dispatch_type = WebInputEvent::kEventNonBlocking;
 
-  if (touch->event.GetType() == WebInputEvent::kTouchStart)
+  if (touch->event.GetType() == WebInputEvent::kTouchStart) {
     touch->event.touch_start_or_first_touch_move = true;
+    // Touch start events should be uncancelable during an active touchscreen
+    // fling.
+    if (client_->TouchscreenFlingInProgress())
+      touch->event.dispatch_type = WebInputEvent::kEventNonBlocking;
+  }
 
   // For touchmove events, compare touch points position from current event
   // to last sent event and update touch points state.
diff --git a/content/browser/renderer_host/input/passthrough_touch_event_queue.h b/content/browser/renderer_host/input/passthrough_touch_event_queue.h
index 65d881e..bc5f793 100644
--- a/content/browser/renderer_host/input/passthrough_touch_event_queue.h
+++ b/content/browser/renderer_host/input/passthrough_touch_event_queue.h
@@ -33,6 +33,8 @@
 
   virtual void OnFilteringTouchEvent(
       const blink::WebTouchEvent& touch_event) = 0;
+
+  virtual bool TouchscreenFlingInProgress() = 0;
 };
 
 // A queue that processes a touch-event and forwards it on to the
diff --git a/content/browser/renderer_host/input/passthrough_touch_event_queue_unittest.cc b/content/browser/renderer_host/input/passthrough_touch_event_queue_unittest.cc
index e8c7daf..bf5d50ff 100644
--- a/content/browser/renderer_host/input/passthrough_touch_event_queue_unittest.cc
+++ b/content/browser/renderer_host/input/passthrough_touch_event_queue_unittest.cc
@@ -95,6 +95,8 @@
   void OnFilteringTouchEvent(const blink::WebTouchEvent& touch_event) override {
   }
 
+  bool TouchscreenFlingInProgress() override { return false; }
+
  protected:
   void SetUpForTouchMoveSlopTesting(double slop_length_dips) {
     slop_length_dips_ = slop_length_dips;
diff --git a/content/browser/renderer_host/pepper/pepper_network_monitor_host.cc b/content/browser/renderer_host/pepper/pepper_network_monitor_host.cc
index 79e5e7f..ed62e219f 100644
--- a/content/browser/renderer_host/pepper/pepper_network_monitor_host.cc
+++ b/content/browser/renderer_host/pepper/pepper_network_monitor_host.cc
@@ -64,10 +64,14 @@
 }
 
 PepperNetworkMonitorHost::~PepperNetworkMonitorHost() {
-  net::NetworkChangeNotifier::RemoveIPAddressObserver(this);
+  net::NetworkChangeNotifier::RemoveNetworkChangeObserver(this);
 }
 
-void PepperNetworkMonitorHost::OnIPAddressChanged() { GetAndSendNetworkList(); }
+void PepperNetworkMonitorHost::OnNetworkChanged(
+    net::NetworkChangeNotifier::ConnectionType type) {
+  if (type == net::NetworkChangeNotifier::GetConnectionType())
+    GetAndSendNetworkList();
+}
 
 void PepperNetworkMonitorHost::OnPermissionCheckResult(
     bool can_use_network_monitor) {
@@ -77,7 +81,7 @@
     return;
   }
 
-  net::NetworkChangeNotifier::AddIPAddressObserver(this);
+  net::NetworkChangeNotifier::AddNetworkChangeObserver(this);
   GetAndSendNetworkList();
 }
 
diff --git a/content/browser/renderer_host/pepper/pepper_network_monitor_host.h b/content/browser/renderer_host/pepper/pepper_network_monitor_host.h
index c04d499..5e61b20f 100644
--- a/content/browser/renderer_host/pepper/pepper_network_monitor_host.h
+++ b/content/browser/renderer_host/pepper/pepper_network_monitor_host.h
@@ -21,7 +21,7 @@
 // The host for PPB_NetworkMonitor. This class lives on the IO thread.
 class CONTENT_EXPORT PepperNetworkMonitorHost
     : public ppapi::host::ResourceHost,
-      public net::NetworkChangeNotifier::IPAddressObserver {
+      public net::NetworkChangeNotifier::NetworkChangeObserver {
  public:
   PepperNetworkMonitorHost(BrowserPpapiHostImpl* host,
                            PP_Instance instance,
@@ -29,8 +29,9 @@
 
   ~PepperNetworkMonitorHost() override;
 
-  // net::NetworkChangeNotifier::IPAddressObserver interface.
-  void OnIPAddressChanged() override;
+  // net::NetworkChangeNotifier::NetworkChangeObserver interface.
+  void OnNetworkChanged(
+      net::NetworkChangeNotifier::ConnectionType type) override;
 
  private:
   void OnPermissionCheckResult(bool can_use_network_monitor);
diff --git a/content/browser/renderer_host/render_widget_host_impl.cc b/content/browser/renderer_host/render_widget_host_impl.cc
index 2f4acaa..5bd3fee 100644
--- a/content/browser/renderer_host/render_widget_host_impl.cc
+++ b/content/browser/renderer_host/render_widget_host_impl.cc
@@ -1184,13 +1184,25 @@
 
   bool scroll_update_needs_wrapping = false;
   if (gesture_event.GetType() == blink::WebInputEvent::kGestureScrollBegin) {
-    DCHECK(!is_in_gesture_scroll_[gesture_event.SourceDevice()]);
+    // When a user starts scrolling while a fling is active, the GSB will arrive
+    // when is_in_gesture_scroll_[gesture_event.SourceDevice()] is still true.
+    // This is because the fling controller defers handling the GFC event
+    // arrived before the GSB and doesn't send a GSE to end the fling; Instead,
+    // it waits for a second GFS to arrive and boost the current active fling if
+    // possible. While GFC handling is deferred the controller suppresses the
+    // GSB and GSU events instead of sending them to the renderer and continues
+    // to progress the fling. So, the renderer doesn't receive two GSB events
+    // without any GSE in between.
+    DCHECK(!is_in_gesture_scroll_[gesture_event.SourceDevice()] ||
+           FlingCancellationIsDeferred());
     is_in_gesture_scroll_[gesture_event.SourceDevice()] = true;
   } else if (gesture_event.GetType() ==
              blink::WebInputEvent::kGestureScrollEnd) {
     DCHECK(is_in_gesture_scroll_[gesture_event.SourceDevice()]);
     is_in_gesture_scroll_[gesture_event.SourceDevice()] = false;
     is_in_touchpad_gesture_fling_ = false;
+    if (view_)
+      view_->set_is_currently_scrolling_viewport(false);
   } else if (gesture_event.GetType() ==
              blink::WebInputEvent::kGestureFlingStart) {
     if (gesture_event.SourceDevice() ==
@@ -1232,8 +1244,17 @@
       }
 
       is_in_touchpad_gesture_fling_ = true;
-    } else {  // gesture_event.SourceDevice() !=
-              // blink::WebGestureDevice::kWebGestureDeviceTouchpad
+    } else if (gesture_event.SourceDevice() ==
+               blink::WebGestureDevice::kWebGestureDeviceTouchscreen) {
+      DCHECK(is_in_gesture_scroll_[gesture_event.SourceDevice()]);
+
+      // The FlingController handles GFS with touchscreen source and sends GSU
+      // events with inertial state to the renderer to progress the fling.
+      // is_in_gesture_scroll must stay true till the fling progress is
+      // finished. Then the FlingController will generate and send a GSE which
+      // shows the end of a scroll sequence and resets is_in_gesture_scroll_.
+    } else {
+      // Autoscroll fling is still handled on renderer.
       DCHECK(is_in_gesture_scroll_[gesture_event.SourceDevice()]);
       is_in_gesture_scroll_[gesture_event.SourceDevice()] = false;
     }
@@ -2347,7 +2368,12 @@
     view_->DidStopFlinging();
 }
 
+void RenderWidgetHostImpl::DidStartScrollingViewport() {
+  if (view_)
+    view_->set_is_currently_scrolling_viewport(true);
+}
 void RenderWidgetHostImpl::SetNeedsBeginFrameForFlingProgress() {
+  browser_fling_needs_begin_frame_ = true;
   SetNeedsBeginFrame(true);
 }
 
@@ -2719,9 +2745,9 @@
   if (needs_begin_frames_ == needs_begin_frames)
     return;
 
-  needs_begin_frames_ = needs_begin_frames;
+  needs_begin_frames_ = needs_begin_frames || browser_fling_needs_begin_frame_;
   if (view_)
-    view_->SetNeedsBeginFrames(needs_begin_frames);
+    view_->SetNeedsBeginFrames(needs_begin_frames_);
 }
 
 void RenderWidgetHostImpl::SetWantsAnimateOnlyBeginFrames() {
@@ -2989,6 +3015,7 @@
 }
 
 void RenderWidgetHostImpl::ProgressFling(base::TimeTicks current_time) {
+  browser_fling_needs_begin_frame_ = false;
   if (input_router_)
     input_router_->ProgressFling(current_time);
 }
@@ -3015,6 +3042,13 @@
     input_router_->StopFling();
 }
 
+bool RenderWidgetHostImpl::FlingCancellationIsDeferred() const {
+  if (input_router_)
+    return input_router_->FlingCancellationIsDeferred();
+
+  return false;
+}
+
 void RenderWidgetHostImpl::SetScreenOrientationForTesting(
     uint16_t angle,
     ScreenOrientationValues type) {
diff --git a/content/browser/renderer_host/render_widget_host_impl.h b/content/browser/renderer_host/render_widget_host_impl.h
index 6206a2bb..c06fe24d 100644
--- a/content/browser/renderer_host/render_widget_host_impl.h
+++ b/content/browser/renderer_host/render_widget_host_impl.h
@@ -654,6 +654,7 @@
 
   void ProgressFling(base::TimeTicks current_time);
   void StopFling();
+  bool FlingCancellationIsDeferred() const;
 
   void DidReceiveFirstFrameAfterNavigation();
 
@@ -796,6 +797,7 @@
   void OnHasTouchEventHandlers(bool has_handlers) override;
   void DidOverscroll(const ui::DidOverscrollParams& params) override;
   void DidStopFlinging() override;
+  void DidStartScrollingViewport() override;
   void OnSetWhiteListedTouchAction(
       cc::TouchAction white_listed_touch_action) override {}
   void SetNeedsBeginFrameForFlingProgress() override;
@@ -1017,6 +1019,10 @@
   // consistent with the state in the renderer, so this host handles it.
   bool needs_begin_frames_ = false;
 
+  // This is used to make sure that when the fling controller sets
+  // needs_begin_frames_ it doesn't get overriden by the renderer.
+  bool browser_fling_needs_begin_frame_ = false;
+
   // This value indicates how long to wait before we consider a renderer hung.
   base::TimeDelta hung_renderer_delay_;
 
diff --git a/content/browser/renderer_host/render_widget_host_input_event_router.cc b/content/browser/renderer_host/render_widget_host_input_event_router.cc
index ae6478c..4a67197 100644
--- a/content/browser/renderer_host/render_widget_host_input_event_router.cc
+++ b/content/browser/renderer_host/render_widget_host_input_event_router.cc
@@ -363,7 +363,7 @@
   if ((event.GetType() == blink::WebInputEvent::kMouseLeave ||
        event.GetType() == blink::WebInputEvent::kMouseMove) &&
       target != last_mouse_move_target_) {
-    SendMouseEnterOrLeaveEvents(event, target, root_view);
+    SendMouseEnterOrLeaveEvents(mouse_event, target, root_view);
     if (root_view->GetCursorManager())
       root_view->GetCursorManager()->UpdateViewUnderCursor(target);
   }
diff --git a/content/browser/renderer_host/render_widget_host_input_event_router.h b/content/browser/renderer_host/render_widget_host_input_event_router.h
index f14d4ff2..ffb43fc 100644
--- a/content/browser/renderer_host/render_widget_host_input_event_router.h
+++ b/content/browser/renderer_host/render_widget_host_input_event_router.h
@@ -166,7 +166,7 @@
   // in different processes for MouseEnter and MouseLeave event handlers to
   // properly fire. This method determines which RenderWidgetHostViews other
   // than the actual target require notification, and sends the appropriate
-  // events to them.
+  // events to them. |event| should be in |root_view|'s coordinate space.
   void SendMouseEnterOrLeaveEvents(const blink::WebMouseEvent& event,
                                    RenderWidgetHostViewBase* target,
                                    RenderWidgetHostViewBase* root_view);
diff --git a/content/browser/renderer_host/render_widget_host_unittest.cc b/content/browser/renderer_host/render_widget_host_unittest.cc
index 430d49e..95d265d 100644
--- a/content/browser/renderer_host/render_widget_host_unittest.cc
+++ b/content/browser/renderer_host/render_widget_host_unittest.cc
@@ -131,6 +131,7 @@
                 bool frame_handler) override {}
   void ProgressFling(base::TimeTicks time) override {}
   void StopFling() override {}
+  bool FlingCancellationIsDeferred() override { return false; }
 
   // IPC::Listener
   bool OnMessageReceived(const IPC::Message& message) override {
diff --git a/content/browser/renderer_host/render_widget_host_view_android.cc b/content/browser/renderer_host/render_widget_host_view_android.cc
index b616b83..d3b5b6d 100644
--- a/content/browser/renderer_host/render_widget_host_view_android.cc
+++ b/content/browser/renderer_host/render_widget_host_view_android.cc
@@ -56,6 +56,7 @@
 #include "content/browser/renderer_host/render_widget_host_impl.h"
 #include "content/browser/renderer_host/render_widget_host_input_event_router.h"
 #include "content/browser/renderer_host/ui_events_helper.h"
+#include "content/common/content_switches_internal.h"
 #include "content/common/input_messages.h"
 #include "content/common/view_messages.h"
 #include "content/public/browser/android/compositor.h"
@@ -1500,10 +1501,23 @@
 InputEventAckState RenderWidgetHostViewAndroid::FilterInputEvent(
     const blink::WebInputEvent& input_event) {
   if (overscroll_controller_ &&
-      blink::WebInputEvent::IsGestureEventType(input_event.GetType()) &&
-      overscroll_controller_->WillHandleGestureEvent(
-          static_cast<const blink::WebGestureEvent&>(input_event))) {
-    return INPUT_EVENT_ACK_STATE_CONSUMED;
+      blink::WebInputEvent::IsGestureEventType(input_event.GetType())) {
+    blink::WebGestureEvent gesture_event =
+        static_cast<const blink::WebGestureEvent&>(input_event);
+    if (overscroll_controller_->WillHandleGestureEvent(gesture_event)) {
+      // Terminate an active fling when a GSU generated from the fling progress
+      // (GSU with inertial state) is consumed by the overscroll_controller_ and
+      // overscrolling mode is not |OVERSCROLL_NONE|. The early fling
+      // termination generates a GSE which completes the overscroll action.
+      if (gesture_event.GetType() ==
+              blink::WebInputEvent::kGestureScrollUpdate &&
+          gesture_event.data.scroll_update.inertial_phase ==
+              blink::WebGestureEvent::kMomentumPhase) {
+        host_->StopFling();
+      }
+
+      return INPUT_EVENT_ACK_STATE_CONSUMED;
+    }
   }
 
   if (gesture_listener_manager_ &&
@@ -1913,6 +1927,13 @@
 
 void RenderWidgetHostViewAndroid::OnGestureEvent(
     const ui::GestureEventData& gesture) {
+  if ((gesture.type() == ui::ET_GESTURE_PINCH_BEGIN ||
+       gesture.type() == ui::ET_GESTURE_PINCH_UPDATE ||
+       gesture.type() == ui::ET_GESTURE_PINCH_END) &&
+      !IsPinchToZoomEnabled()) {
+    return;
+  }
+
   blink::WebGestureEvent web_gesture =
       ui::CreateWebGestureEventFromGestureEventData(gesture);
   // TODO(jdduke): Remove this workaround after Android fixes UiAutomator to
@@ -2006,6 +2027,16 @@
     return;
   }
 
+  bool webview_fling = sync_compositor_ && is_currently_scrolling_viewport_;
+  if (!webview_fling) {
+    host_->ProgressFling(args.frame_time);
+  } else if (sync_compositor_->on_compute_scroll_called()) {
+    // On Android webview progress the fling only when |OnComputeScroll| is
+    // called since in some cases Apps override |OnComputeScroll| to cancel
+    // fling animation.
+    host_->ProgressFling(args.frame_time);
+  }
+
   // Update |last_begin_frame_args_| before handling
   // |outstanding_begin_frame_requests_| to prevent the BeginFrameSource from
   // sending the same MISSED args in infinite recursion.
@@ -2019,7 +2050,6 @@
     OnDidNotProduceFrame(
         viz::BeginFrameAck(args.source_id, args.sequence_number, false));
   }
-  host()->ProgressFling(args.frame_time);
 }
 
 const viz::BeginFrameArgs& RenderWidgetHostViewAndroid::LastUsedBeginFrameArgs()
diff --git a/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc b/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc
index 39163b9..d3ef80ea 100644
--- a/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc
+++ b/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc
@@ -4499,8 +4499,8 @@
   {
     // Start over, except instead of ending the gesture with ScrollEnd, end it
     // with a FlingStart, with velocity in the reverse direction. This should
-    // initiate an overscroll, but it should be cancelled because of the fling
-    // in the opposite direction.
+    // initiate an overscroll, the overscroll mode should get reset after the
+    // first GSU event generated by the fling controller.
     overscroll_delegate()->Reset();
     SimulateGestureEvent(WebInputEvent::kGestureScrollBegin,
                          blink::kWebGestureDeviceTouchscreen);
@@ -4517,8 +4517,17 @@
 
     SimulateGestureFlingStartEvent(100, 0, blink::kWebGestureDeviceTouchscreen);
     events = GetAndResetDispatchedMessages();
-    EXPECT_EQ("GestureFlingStart", GetMessageNames(events));
-    EXPECT_EQ(OVERSCROLL_NONE, overscroll_delegate()->completed_mode());
+    // The fling start event is not sent to the renderer.
+    EXPECT_EQ(0U, events.size());
+    EXPECT_EQ(OVERSCROLL_WEST, overscroll_mode());
+    EXPECT_EQ(OverscrollSource::TOUCHSCREEN, overscroll_source());
+    EXPECT_EQ(OVERSCROLL_WEST, overscroll_delegate()->current_mode());
+
+    // The overscrolling mode will reset after the first GSU from fling
+    // progress.
+    base::TimeTicks progress_time =
+        base::TimeTicks::Now() + base::TimeDelta::FromMilliseconds(17);
+    widget_host_->ProgressFling(progress_time);
     EXPECT_EQ(OVERSCROLL_NONE, overscroll_delegate()->current_mode());
   }
 }
diff --git a/content/browser/renderer_host/render_widget_host_view_base.cc b/content/browser/renderer_host/render_widget_host_view_base.cc
index 122a22ae..dd77d08 100644
--- a/content/browser/renderer_host/render_widget_host_view_base.cc
+++ b/content/browser/renderer_host/render_widget_host_view_base.cc
@@ -50,6 +50,7 @@
       wheel_scroll_latching_enabled_(base::FeatureList::IsEnabled(
           features::kTouchpadAndWheelScrollLatching)),
       web_contents_accessibility_(nullptr),
+      is_currently_scrolling_viewport_(false),
       renderer_frame_number_(0),
       weak_factory_(this) {
   host_->render_frame_metadata_provider()->AddObserver(this);
diff --git a/content/browser/renderer_host/render_widget_host_view_base.h b/content/browser/renderer_host/render_widget_host_view_base.h
index 5937ae30..6b98a54aa 100644
--- a/content/browser/renderer_host/render_widget_host_view_base.h
+++ b/content/browser/renderer_host/render_widget_host_view_base.h
@@ -497,6 +497,14 @@
     web_contents_accessibility_ = wcax;
   }
 
+  void set_is_currently_scrolling_viewport(
+      bool is_currently_scrolling_viewport) {
+    is_currently_scrolling_viewport_ = is_currently_scrolling_viewport;
+  }
+
+  bool is_currently_scrolling_viewport() {
+    return is_currently_scrolling_viewport_;
+  }
 #if defined(USE_AURA)
   void EmbedChildFrameRendererWindowTreeClient(
       RenderWidgetHostViewBase* root_view,
@@ -566,6 +574,8 @@
 
   WebContentsAccessibility* web_contents_accessibility_;
 
+  bool is_currently_scrolling_viewport_;
+
  private:
 #if defined(USE_AURA)
   void OnDidScheduleEmbed(int routing_id,
diff --git a/content/browser/renderer_host/render_widget_host_view_child_frame.cc b/content/browser/renderer_host/render_widget_host_view_child_frame.cc
index 1ce4764..4836245 100644
--- a/content/browser/renderer_host/render_widget_host_view_child_frame.cc
+++ b/content/browser/renderer_host/render_widget_host_view_child_frame.cc
@@ -875,6 +875,7 @@
 
 void RenderWidgetHostViewChildFrame::OnBeginFrame(
     const viz::BeginFrameArgs& args) {
+  host_->ProgressFling(args.frame_time);
   if (renderer_compositor_frame_sink_)
     renderer_compositor_frame_sink_->OnBeginFrame(args);
 }
diff --git a/content/browser/site_per_process_browsertest.cc b/content/browser/site_per_process_browsertest.cc
index e5bb06a..edca553b 100644
--- a/content/browser/site_per_process_browsertest.cc
+++ b/content/browser/site_per_process_browsertest.cc
@@ -1382,6 +1382,52 @@
   DCHECK_EQ(filter->last_rect().y(), 0);
 }
 
+// Test that fling on an out-of-process iframe progresses properly.
+IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, GestureFlingStart) {
+  GURL main_url(embedded_test_server()->GetURL(
+      "a.com", "/cross_site_iframe_factory.html?a(b)"));
+  EXPECT_TRUE(NavigateToURL(shell(), main_url));
+
+  FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
+                            ->GetFrameTree()
+                            ->root();
+  ASSERT_EQ(1U, root->child_count());
+
+  FrameTreeNode* child_iframe_node = root->child_at(0);
+
+  RenderWidgetHost* child_rwh =
+      child_iframe_node->current_frame_host()->GetRenderWidgetHost();
+
+  WaitForChildFrameSurfaceReady(child_iframe_node->current_frame_host());
+
+  // Send a GSB to start scrolling sequence.
+  blink::WebGestureEvent gesture_scroll_begin(
+      blink::WebGestureEvent::kGestureScrollBegin,
+      blink::WebInputEvent::kNoModifiers,
+      blink::WebInputEvent::GetStaticTimeStampForTests());
+  gesture_scroll_begin.SetSourceDevice(blink::kWebGestureDeviceTouchscreen);
+  gesture_scroll_begin.data.scroll_begin.delta_hint_units =
+      blink::WebGestureEvent::ScrollUnits::kPrecisePixels;
+  gesture_scroll_begin.data.scroll_begin.delta_x_hint = 0.f;
+  gesture_scroll_begin.data.scroll_begin.delta_y_hint = 5.f;
+  child_rwh->ForwardGestureEvent(gesture_scroll_begin);
+
+  // Send a GFS and wait for the ack of the first GSU generated from progressing
+  // the fling on the browser.
+  InputEventAckWaiter gesture_scroll_update_ack_observer(
+      child_rwh, blink::WebInputEvent::kGestureScrollUpdate);
+  gesture_scroll_update_ack_observer.Reset();
+  blink::WebGestureEvent gesture_fling_start(
+      blink::WebGestureEvent::kGestureFlingStart,
+      blink::WebInputEvent::kNoModifiers,
+      blink::WebInputEvent::GetStaticTimeStampForTests());
+  gesture_fling_start.SetSourceDevice(blink::kWebGestureDeviceTouchscreen);
+  gesture_fling_start.data.fling_start.velocity_x = 0.f;
+  gesture_fling_start.data.fling_start.velocity_y = 50.f;
+  child_rwh->ForwardGestureEvent(gesture_fling_start);
+  gesture_scroll_update_ack_observer.Wait();
+}
+
 class ScrollObserver : public RenderWidgetHost::InputEventObserver {
  public:
   ScrollObserver(double delta_x, double delta_y) { Reset(delta_x, delta_y); }
diff --git a/content/browser/site_per_process_hit_test_browsertest.cc b/content/browser/site_per_process_hit_test_browsertest.cc
index b7ae920..2dbb8470 100644
--- a/content/browser/site_per_process_hit_test_browsertest.cc
+++ b/content/browser/site_per_process_hit_test_browsertest.cc
@@ -1693,18 +1693,22 @@
   DISALLOW_COPY_AND_ASSIGN(CursorMessageFilter);
 };
 
+namespace {
+
 // Verify that we receive a mouse cursor update message when we mouse over
 // a text field contained in an out-of-process iframe.
-IN_PROC_BROWSER_TEST_P(SitePerProcessHitTestBrowserTest,
-                       CursorUpdateReceivedFromCrossSiteIframe) {
-  GURL main_url(embedded_test_server()->GetURL(
+void CursorUpdateReceivedFromCrossSiteIframeHelper(
+    Shell* shell,
+    net::test_server::EmbeddedTestServer* embedded_test_server) {
+  GURL main_url(embedded_test_server->GetURL(
       "/frame_tree/page_with_positioned_frame.html"));
-  EXPECT_TRUE(NavigateToURL(shell(), main_url));
+  EXPECT_TRUE(NavigateToURL(shell, main_url));
 
-  FrameTreeNode* root = web_contents()->GetFrameTree()->root();
+  auto* web_contents = static_cast<WebContentsImpl*>(shell->web_contents());
+  FrameTreeNode* root = web_contents->GetFrameTree()->root();
 
   FrameTreeNode* child_node = root->child_at(0);
-  EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
+  EXPECT_NE(shell->web_contents()->GetSiteInstance(),
             child_node->current_frame_host()->GetSiteInstance());
 
   WaitForChildFrameSurfaceReady(child_node->current_frame_host());
@@ -1734,9 +1738,24 @@
       blink::WebInputEvent::kMouseMove, blink::WebInputEvent::kNoModifiers,
       blink::WebInputEvent::GetStaticTimeStampForTests());
   SetWebEventPositions(&mouse_event, gfx::Point(60, 60), root_view);
-  auto* router = web_contents()->GetInputEventRouter();
+  auto* router = web_contents->GetInputEventRouter();
+  RenderWidgetHostMouseEventMonitor child_monitor(
+      child_view->GetRenderWidgetHost());
+  RenderWidgetHostMouseEventMonitor root_monitor(
+      root_view->GetRenderWidgetHost());
   RouteMouseEventAndWaitUntilDispatch(router, root_view, child_view,
                                       &mouse_event);
+  // The child_view should receive a mouse-move event.
+  EXPECT_TRUE(child_monitor.EventWasReceived());
+  EXPECT_EQ(blink::WebInputEvent::kMouseMove, child_monitor.event().GetType());
+  EXPECT_NEAR(10, child_monitor.event().PositionInWidget().x, 2);
+  EXPECT_NEAR(10, child_monitor.event().PositionInWidget().y, 2);
+
+  // The root_view should also receive a mouse-move event.
+  EXPECT_TRUE(root_monitor.EventWasReceived());
+  EXPECT_EQ(blink::WebInputEvent::kMouseMove, root_monitor.event().GetType());
+  EXPECT_EQ(60, root_monitor.event().PositionInWidget().x);
+  EXPECT_EQ(60, root_monitor.event().PositionInWidget().y);
 
   // CursorMessageFilter::Wait() implicitly tests whether we receive a
   // ViewHostMsg_SetCursor message from the renderer process, because it does
@@ -1753,9 +1772,9 @@
     loop.Run();
   }
 
-  // The |root_view| ends up getting a mouse-leave event, causing it to send an
-  // updated cursor for the view.
-  EXPECT_TRUE(
+  // The root_view receives a mouse-move event on top of the iframe, which does
+  // not send a cursor update.
+  EXPECT_FALSE(
       root_view->GetCursorManager()->GetCursorForTesting(root_view, cursor));
   EXPECT_TRUE(
       root_view->GetCursorManager()->GetCursorForTesting(child_view, cursor));
@@ -1764,6 +1783,20 @@
   cursor.GetCursorInfo(&cursor_info);
   EXPECT_EQ(cursor_info.type, blink::WebCursorInfo::kTypeIBeam);
 }
+
+}  // namespace
+
+IN_PROC_BROWSER_TEST_P(SitePerProcessHitTestBrowserTest,
+                       CursorUpdateReceivedFromCrossSiteIframe) {
+  CursorUpdateReceivedFromCrossSiteIframeHelper(shell(),
+                                                embedded_test_server());
+}
+
+IN_PROC_BROWSER_TEST_P(SitePerProcessHighDPIHitTestBrowserTest,
+                       CursorUpdateReceivedFromCrossSiteIframe) {
+  CursorUpdateReceivedFromCrossSiteIframeHelper(shell(),
+                                                embedded_test_server());
+}
 #endif  // !defined(OS_ANDROID)
 
 #if defined(USE_AURA)
@@ -2452,8 +2485,9 @@
 
 }  // anonymous namespace
 
+// Flaky, see https://crbug.com/823578
 IN_PROC_BROWSER_TEST_P(SitePerProcessHitTestBrowserTest,
-                       InputEventRouterGestureTargetMapTest) {
+                       DISABLED_InputEventRouterGestureTargetMapTest) {
   GURL main_url(embedded_test_server()->GetURL(
       "/frame_tree/page_with_positioned_nested_frames.html"));
   EXPECT_TRUE(NavigateToURL(shell(), main_url));
diff --git a/content/common/input/gesture_event_stream_validator.cc b/content/common/input/gesture_event_stream_validator.cc
index 373b0be..12618d7ad 100644
--- a/content/common/input/gesture_event_stream_validator.cc
+++ b/content/common/input/gesture_event_stream_validator.cc
@@ -21,8 +21,10 @@
 GestureEventStreamValidator::~GestureEventStreamValidator() {
 }
 
-bool GestureEventStreamValidator::Validate(const blink::WebGestureEvent& event,
-                                           std::string* error_msg) {
+bool GestureEventStreamValidator::Validate(
+    const blink::WebGestureEvent& event,
+    const bool fling_cancellation_is_deferred,
+    std::string* error_msg) {
   DCHECK(error_msg);
   error_msg->clear();
   if (!WebInputEvent::IsGestureEventType(event.GetType())) {
@@ -31,7 +33,7 @@
   }
   switch (event.GetType()) {
     case WebInputEvent::kGestureScrollBegin:
-      if (scrolling_)
+      if (scrolling_ && !fling_cancellation_is_deferred)
         error_msg->append("Scroll begin during scroll\n");
       if (pinching_)
         error_msg->append("Scroll begin during pinch\n");
@@ -51,7 +53,8 @@
         error_msg->append("Fling start outside of scroll\n");
       if (pinching_)
         error_msg->append("Flinging while pinching\n");
-      scrolling_ = false;
+      // Don't reset scrolling_ since the GSE sent by the fling_controller_ at
+      // the end of the fling resets it.
       break;
     case WebInputEvent::kGestureScrollEnd:
       if (!scrolling_)
@@ -111,4 +114,10 @@
   return error_msg->empty();
 }
 
+bool GestureEventStreamValidator::Validate(const blink::WebGestureEvent& event,
+                                           std::string* error_msg) {
+  return Validate(event, /* fling_cancellation_is_deferred = */ false,
+                  error_msg);
+}
+
 }  // namespace content
diff --git a/content/common/input/gesture_event_stream_validator.h b/content/common/input/gesture_event_stream_validator.h
index 5d8ae8f3..49303e1 100644
--- a/content/common/input/gesture_event_stream_validator.h
+++ b/content/common/input/gesture_event_stream_validator.h
@@ -24,6 +24,9 @@
 
   // If |event| is valid for the current stream, returns true.
   // Otherwise, returns false with a corresponding error message.
+  bool Validate(const blink::WebGestureEvent& event,
+                const bool fling_cancellation_is_deferred,
+                std::string* error_msg);
   bool Validate(const blink::WebGestureEvent& event, std::string* error_msg);
 
  private:
diff --git a/content/common/input/input_event_stream_validator.cc b/content/common/input/input_event_stream_validator.cc
index 354ad73..26dbd198 100644
--- a/content/common/input/input_event_stream_validator.cc
+++ b/content/common/input/input_event_stream_validator.cc
@@ -25,23 +25,28 @@
 InputEventStreamValidator::~InputEventStreamValidator() {
 }
 
-void InputEventStreamValidator::Validate(const WebInputEvent& event) {
+void InputEventStreamValidator::Validate(
+    const WebInputEvent& event,
+    const bool fling_cancellation_is_deferred /* = false */) {
   if (!enabled_)
     return;
 
-  DCHECK(ValidateImpl(event, &error_msg_))
+  DCHECK(ValidateImpl(event, fling_cancellation_is_deferred, &error_msg_))
       << error_msg_
       << "\nInvalid Event: " << ui::WebInputEventTraits::ToString(event);
 }
 
-bool InputEventStreamValidator::ValidateImpl(const blink::WebInputEvent& event,
-                                             std::string* error_msg) {
+bool InputEventStreamValidator::ValidateImpl(
+    const blink::WebInputEvent& event,
+    const bool fling_cancellation_is_deferred,
+    std::string* error_msg) {
   DCHECK(error_msg);
   if (WebInputEvent::IsGestureEventType(event.GetType())) {
     const WebGestureEvent& gesture = static_cast<const WebGestureEvent&>(event);
     // TODO(jdduke): Validate touchpad gesture streams.
     if (gesture.SourceDevice() == blink::kWebGestureDeviceTouchscreen)
-      return gesture_validator_.Validate(gesture, error_msg);
+      return gesture_validator_.Validate(
+          gesture, fling_cancellation_is_deferred, error_msg);
   } else if (WebInputEvent::IsTouchEventType(event.GetType())) {
     const WebTouchEvent& touch = static_cast<const WebTouchEvent&>(event);
     return touch_validator_.Validate(touch, error_msg);
diff --git a/content/common/input/input_event_stream_validator.h b/content/common/input/input_event_stream_validator.h
index e2d726e..7bf2238e 100644
--- a/content/common/input/input_event_stream_validator.h
+++ b/content/common/input/input_event_stream_validator.h
@@ -24,10 +24,13 @@
   InputEventStreamValidator();
   ~InputEventStreamValidator();
 
-  void Validate(const blink::WebInputEvent&);
+  void Validate(const blink::WebInputEvent&,
+                const bool fling_cancellation_is_deferred = false);
 
  private:
-  bool ValidateImpl(const blink::WebInputEvent&, std::string* error_msg);
+  bool ValidateImpl(const blink::WebInputEvent&,
+                    const bool fling_cancellation_is_deferred,
+                    std::string* error_msg);
 
   GestureEventStreamValidator gesture_validator_;
   TouchEventStreamValidator touch_validator_;
diff --git a/content/common/input/input_handler.mojom b/content/common/input/input_handler.mojom
index 200dac4..07529ba 100644
--- a/content/common/input/input_handler.mojom
+++ b/content/common/input/input_handler.mojom
@@ -177,6 +177,9 @@
   // Sent by the compositor when a fling animation is stopped.
   DidStopFlinging();
 
+  // Sent by the compositor when a GSB has started scrolling the viewport.
+  DidStartScrollingViewport();
+
   // Required for cancelling an ongoing input method composition.
   ImeCancelComposition();
 
diff --git a/content/common/input_messages.h b/content/common/input_messages.h
index 79aad9f..a17d07c3 100644
--- a/content/common/input_messages.h
+++ b/content/common/input_messages.h
@@ -353,6 +353,9 @@
 // Sent by the compositor when a fling animation is stopped.
 IPC_MESSAGE_ROUTED0(InputHostMsg_DidStopFlinging)
 
+// Sent by the compositor when a GSB has started scrolling the viewport.
+IPC_MESSAGE_ROUTED0(InputHostMsg_DidStartScrollingViewport)
+
 // Acknowledges receipt of a InputMsg_MoveCaret message.
 IPC_MESSAGE_ROUTED0(InputHostMsg_MoveCaret_ACK)
 
diff --git a/content/public/browser/webrtc_event_logger.cc b/content/public/browser/webrtc_event_logger.cc
index 219874cd0..e61c7b2 100644
--- a/content/public/browser/webrtc_event_logger.cc
+++ b/content/public/browser/webrtc_event_logger.cc
@@ -10,18 +10,19 @@
 
 WebRtcEventLogger* g_webrtc_event_logger = nullptr;
 
-void WebRtcEventLogger::Set(WebRtcEventLogger* webrtc_event_logger) {
-  DCHECK(webrtc_event_logger);
-  DCHECK(!g_webrtc_event_logger);
-  g_webrtc_event_logger = webrtc_event_logger;
-}
-
 WebRtcEventLogger* WebRtcEventLogger::Get() {
   return g_webrtc_event_logger;
 }
 
-void WebRtcEventLogger::ClearForTesting() {
-  DCHECK(g_webrtc_event_logger);
+WebRtcEventLogger::WebRtcEventLogger() {
+  DCHECK(!g_webrtc_event_logger);
+  g_webrtc_event_logger = this;
+  // Checking that g_webrtc_event_logger was never set before, in a way that
+  // would not interfere with unit tests, is overkill.
+}
+
+WebRtcEventLogger::~WebRtcEventLogger() {
+  DCHECK_EQ(g_webrtc_event_logger, this);
   g_webrtc_event_logger = nullptr;
 }
 
diff --git a/content/public/browser/webrtc_event_logger.h b/content/public/browser/webrtc_event_logger.h
index fa74e0b..926e61d5b 100644
--- a/content/public/browser/webrtc_event_logger.h
+++ b/content/public/browser/webrtc_event_logger.h
@@ -15,19 +15,21 @@
 
 class BrowserContext;
 
-// Interface for a logger of WebRTC events.
+// Interface for a logger of WebRTC events, which the embedding application may
+// subclass and instantiate. Only one instance may ever be created, and it must
+// live until the embedding application terminates.
 class CONTENT_EXPORT WebRtcEventLogger {
  public:
-  // Once set, the logger must remain valid (though not necessarily active)
-  // until the application shuts down, at which point it should be leaked.
-  // For unit tests only, we allow clearing, because we want to make sure that
-  // other units destructors would not satisfy expectations that might otherwise
-  // have not been fulfilled.
-  static void Set(WebRtcEventLogger* webrtc_event_logger);
+  // Get the only instance of WebRtcEventLogger, if one was instantiated, or
+  // nullptr otherwise.
   static WebRtcEventLogger* Get();
-  static void ClearForTesting();
 
-  virtual ~WebRtcEventLogger() = default;
+  // The embedding application may leak or destroy on shutdown. Either way,
+  // it may only be done on shutdown. It's up to the embedding application to
+  // only destroy at a time during shutdown when it is guaranteed that tasks
+  // posted earlier with a reference to the WebRtcEventLogger object, will
+  // not execute.
+  virtual ~WebRtcEventLogger();
 
   // TODO(eladalon): Change from using BrowserContext to using Profile.
   // https://crbug.com/775415
@@ -129,6 +131,9 @@
       const std::string& message,
       base::OnceCallback<void(std::pair<bool, bool>)> reply =
           base::OnceCallback<void(std::pair<bool, bool>)>()) = 0;
+
+ protected:
+  WebRtcEventLogger();
 };
 
 }  // namespace content
diff --git a/content/public/renderer/content_renderer_client.cc b/content/public/renderer/content_renderer_client.cc
index 4566c564..b79384d 100644
--- a/content/public/renderer/content_renderer_client.cc
+++ b/content/public/renderer/content_renderer_client.cc
@@ -216,10 +216,6 @@
   return false;
 }
 
-bool ContentRendererClient::ShouldGatherSiteIsolationStats() const {
-  return true;
-}
-
 std::unique_ptr<blink::WebContentSettingsClient>
 ContentRendererClient::CreateWorkerContentSettingsClient(
     RenderFrame* render_frame) {
diff --git a/content/public/renderer/content_renderer_client.h b/content/public/renderer/content_renderer_client.h
index f663393a..4c8cc50 100644
--- a/content/public/renderer/content_renderer_client.h
+++ b/content/public/renderer/content_renderer_client.h
@@ -301,11 +301,6 @@
   virtual bool ShouldReportDetailedMessageForSource(
       const base::string16& source) const;
 
-  // Returns true if we should gather stats during resource loads as if the
-  // cross-site document blocking policy were enabled. Does not actually block
-  // any pages.
-  virtual bool ShouldGatherSiteIsolationStats() const;
-
   // Creates a permission client for in-renderer worker.
   virtual std::unique_ptr<blink::WebContentSettingsClient>
   CreateWorkerContentSettingsClient(RenderFrame* render_frame);
diff --git a/content/renderer/BUILD.gn b/content/renderer/BUILD.gn
index d23e33b..791702eb 100644
--- a/content/renderer/BUILD.gn
+++ b/content/renderer/BUILD.gn
@@ -243,8 +243,6 @@
     "loader/resource_dispatcher.h",
     "loader/shared_memory_data_consumer_handle.cc",
     "loader/shared_memory_data_consumer_handle.h",
-    "loader/site_isolation_stats_gatherer.cc",
-    "loader/site_isolation_stats_gatherer.h",
     "loader/sync_load_context.cc",
     "loader/sync_load_context.h",
     "loader/sync_load_response.cc",
diff --git a/content/renderer/input/input_event_filter.cc b/content/renderer/input/input_event_filter.cc
index 13fe23e..3f210e5 100644
--- a/content/renderer/input/input_event_filter.cc
+++ b/content/renderer/input/input_event_filter.cc
@@ -87,6 +87,11 @@
   SendMessage(std::make_unique<InputHostMsg_DidStopFlinging>(routing_id));
 }
 
+void InputEventFilter::DidStartScrollingViewport(int routing_id) {
+  SendMessage(
+      std::make_unique<InputHostMsg_DidStartScrollingViewport>(routing_id));
+}
+
 void InputEventFilter::QueueClosureForMainThreadEventQueue(
     int routing_id,
     const base::Closure& closure) {
diff --git a/content/renderer/input/input_event_filter.h b/content/renderer/input/input_event_filter.h
index ae0ab45..b377c35e 100644
--- a/content/renderer/input/input_event_filter.h
+++ b/content/renderer/input/input_event_filter.h
@@ -73,6 +73,7 @@
   void DidOverscroll(int routing_id,
                      const ui::DidOverscrollParams& params) override;
   void DidStopFlinging(int routing_id) override;
+  void DidStartScrollingViewport(int routing_id) override;
   void DispatchNonBlockingEventToMainThread(
       int routing_id,
       ui::WebScopedInputEvent event,
diff --git a/content/renderer/input/input_handler_manager.cc b/content/renderer/input/input_handler_manager.cc
index f21b297e..b9b0e0d 100644
--- a/content/renderer/input/input_handler_manager.cc
+++ b/content/renderer/input/input_handler_manager.cc
@@ -274,6 +274,10 @@
   renderer_scheduler_->DidAnimateForInputOnCompositorThread();
 }
 
+void InputHandlerManager::DidStartScrollingViewport(int routing_id) {
+  client_->DidStartScrollingViewport(routing_id);
+}
+
 void InputHandlerManager::DispatchNonBlockingEventToMainThread(
     int routing_id,
     ui::WebScopedInputEvent event,
diff --git a/content/renderer/input/input_handler_manager.h b/content/renderer/input/input_handler_manager.h
index 40e32e6..85359d7 100644
--- a/content/renderer/input/input_handler_manager.h
+++ b/content/renderer/input/input_handler_manager.h
@@ -110,6 +110,9 @@
   void DidAnimateForInput();
 
   // Called from the compositor's thread.
+  void DidStartScrollingViewport(int routing_id);
+
+  // Called from the compositor's thread.
   void DispatchNonBlockingEventToMainThread(
       int routing_id,
       ui::WebScopedInputEvent event,
diff --git a/content/renderer/input/input_handler_manager_client.h b/content/renderer/input/input_handler_manager_client.h
index c155b0a3..5081002d 100644
--- a/content/renderer/input/input_handler_manager_client.h
+++ b/content/renderer/input/input_handler_manager_client.h
@@ -50,6 +50,7 @@
   virtual void DidOverscroll(int routing_id,
                              const ui::DidOverscrollParams& params) = 0;
   virtual void DidStopFlinging(int routing_id) = 0;
+  virtual void DidStartScrollingViewport(int routing_id) = 0;
   virtual void DispatchNonBlockingEventToMainThread(
       int routing_id,
       ui::WebScopedInputEvent event,
diff --git a/content/renderer/input/input_handler_wrapper.cc b/content/renderer/input/input_handler_wrapper.cc
index 4e5ed8bf..1ad69e0 100644
--- a/content/renderer/input/input_handler_wrapper.cc
+++ b/content/renderer/input/input_handler_wrapper.cc
@@ -88,6 +88,10 @@
   input_handler_manager_->DidAnimateForInput();
 }
 
+void InputHandlerWrapper::DidStartScrollingViewport() {
+  input_handler_manager_->DidStartScrollingViewport(routing_id_);
+}
+
 void InputHandlerWrapper::GenerateScrollBeginAndSendToMainThread(
     const blink::WebGestureEvent& update_event) {
   DCHECK_EQ(update_event.GetType(), blink::WebInputEvent::kGestureScrollUpdate);
diff --git a/content/renderer/input/input_handler_wrapper.h b/content/renderer/input/input_handler_wrapper.h
index e5ddaad..3f6484f 100644
--- a/content/renderer/input/input_handler_wrapper.h
+++ b/content/renderer/input/input_handler_wrapper.h
@@ -55,6 +55,7 @@
       const cc::OverscrollBehavior& overscroll_behavior) override;
   void DidStopFlinging() override;
   void DidAnimateForInput() override;
+  void DidStartScrollingViewport() override;
   void GenerateScrollBeginAndSendToMainThread(
       const blink::WebGestureEvent& update_event) override;
   void SetWhiteListedTouchAction(
diff --git a/content/renderer/input/widget_input_handler_manager.cc b/content/renderer/input/widget_input_handler_manager.cc
index 901295d..0c002d17 100644
--- a/content/renderer/input/widget_input_handler_manager.cc
+++ b/content/renderer/input/widget_input_handler_manager.cc
@@ -244,6 +244,13 @@
   renderer_scheduler_->DidAnimateForInputOnCompositorThread();
 }
 
+void WidgetInputHandlerManager::DidStartScrollingViewport() {
+  mojom::WidgetInputHandlerHost* host = GetWidgetInputHandlerHost();
+  if (!host)
+    return;
+  host->DidStartScrollingViewport();
+}
+
 void WidgetInputHandlerManager::GenerateScrollBeginAndSendToMainThread(
     const blink::WebGestureEvent& update_event) {
   DCHECK_EQ(update_event.GetType(), blink::WebInputEvent::kGestureScrollUpdate);
diff --git a/content/renderer/input/widget_input_handler_manager.h b/content/renderer/input/widget_input_handler_manager.h
index 0335ed75..553f862 100644
--- a/content/renderer/input/widget_input_handler_manager.h
+++ b/content/renderer/input/widget_input_handler_manager.h
@@ -61,6 +61,7 @@
       const cc::OverscrollBehavior& overscroll_behavior) override;
   void DidStopFlinging() override;
   void DidAnimateForInput() override;
+  void DidStartScrollingViewport() override;
   void GenerateScrollBeginAndSendToMainThread(
       const blink::WebGestureEvent& update_event) override;
   void SetWhiteListedTouchAction(
diff --git a/content/renderer/loader/request_extra_data.h b/content/renderer/loader/request_extra_data.h
index d32c610e..410d448 100644
--- a/content/renderer/loader/request_extra_data.h
+++ b/content/renderer/loader/request_extra_data.h
@@ -17,7 +17,6 @@
 #include "third_party/WebKit/public/platform/WebString.h"
 #include "third_party/WebKit/public/platform/WebURLRequest.h"
 #include "ui/base/page_transition_types.h"
-#include "url/origin.h"
 
 namespace network {
 struct ResourceRequest;
@@ -43,10 +42,6 @@
   void set_is_main_frame(bool is_main_frame) {
     is_main_frame_ = is_main_frame;
   }
-  url::Origin frame_origin() const { return frame_origin_; }
-  void set_frame_origin(const url::Origin& frame_origin) {
-    frame_origin_ = frame_origin;
-  }
   void set_allow_download(bool allow_download) {
     allow_download_ = allow_download;
   }
@@ -159,7 +154,6 @@
   blink::mojom::PageVisibilityState visibility_state_;
   int render_frame_id_;
   bool is_main_frame_;
-  url::Origin frame_origin_;
   bool allow_download_;
   ui::PageTransition transition_type_;
   bool should_replace_current_entry_;
diff --git a/content/renderer/loader/resource_dispatcher.cc b/content/renderer/loader/resource_dispatcher.cc
index 1cf9992..bf22236 100644
--- a/content/renderer/loader/resource_dispatcher.cc
+++ b/content/renderer/loader/resource_dispatcher.cc
@@ -30,7 +30,6 @@
 #include "content/public/renderer/request_peer.h"
 #include "content/public/renderer/resource_dispatcher_delegate.h"
 #include "content/renderer/loader/request_extra_data.h"
-#include "content/renderer/loader/site_isolation_stats_gatherer.h"
 #include "content/renderer/loader/sync_load_context.h"
 #include "content/renderer/loader/sync_load_response.h"
 #include "content/renderer/loader/url_loader_client_impl.h"
@@ -169,10 +168,6 @@
 
   network::ResourceResponseInfo renderer_response_info;
   ToResourceResponseInfo(*request_info, response_head, &renderer_response_info);
-  request_info->site_isolation_metadata =
-      SiteIsolationStatsGatherer::OnReceivedResponse(
-          request_info->frame_origin, request_info->response_url,
-          request_info->resource_type, renderer_response_info);
   request_info->peer->OnReceivedResponse(renderer_response_info);
 }
 
@@ -219,8 +214,7 @@
     request_info = GetPendingRequestInfo(request_id);
     if (!request_info)
       return;
-    // We update the response_url here so that we can send it to
-    // SiteIsolationStatsGatherer later when OnReceivedResponse is called.
+    // We update the response_url here for tracking/stats use later.
     request_info->response_url = redirect_info.new_url;
     request_info->response_method = redirect_info.new_method;
     request_info->response_referrer = GURL(redirect_info.new_referrer);
@@ -352,7 +346,6 @@
     std::unique_ptr<RequestPeer> peer,
     ResourceType resource_type,
     int render_frame_id,
-    const url::Origin& frame_origin,
     const GURL& request_url,
     const std::string& method,
     const GURL& referrer,
@@ -361,7 +354,6 @@
       resource_type(resource_type),
       render_frame_id(render_frame_id),
       url(request_url),
-      frame_origin(frame_origin),
       response_url(request_url),
       response_method(method),
       response_referrer(referrer),
@@ -374,7 +366,6 @@
 void ResourceDispatcher::StartSync(
     std::unique_ptr<network::ResourceRequest> request,
     int routing_id,
-    const url::Origin& frame_origin,
     const net::NetworkTrafficAnnotationTag& traffic_annotation,
     SyncLoadResponse* response,
     scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
@@ -399,7 +390,7 @@
   task_runner->PostTask(
       FROM_HERE,
       base::BindOnce(&SyncLoadContext::StartAsyncWithWaitableEvent,
-                     std::move(request), routing_id, task_runner, frame_origin,
+                     std::move(request), routing_id, task_runner,
                      traffic_annotation, std::move(factory_info),
                      std::move(throttles), base::Unretained(response),
                      base::Unretained(&event)));
@@ -411,7 +402,6 @@
     std::unique_ptr<network::ResourceRequest> request,
     int routing_id,
     scoped_refptr<base::SingleThreadTaskRunner> loading_task_runner,
-    const url::Origin& frame_origin,
     const net::NetworkTrafficAnnotationTag& traffic_annotation,
     bool is_sync,
     std::unique_ptr<RequestPeer> peer,
@@ -425,7 +415,7 @@
   int request_id = MakeRequestID();
   pending_requests_[request_id] = std::make_unique<PendingRequestInfo>(
       std::move(peer), static_cast<ResourceType>(request->resource_type),
-      request->render_frame_id, frame_origin, request->url, request->method,
+      request->render_frame_id, request->url, request->method,
       request->referrer, request->download_to_file);
 
   if (url_loader_client_endpoints) {
diff --git a/content/renderer/loader/resource_dispatcher.h b/content/renderer/loader/resource_dispatcher.h
index f7bec45..6f41e2af 100644
--- a/content/renderer/loader/resource_dispatcher.h
+++ b/content/renderer/loader/resource_dispatcher.h
@@ -31,7 +31,6 @@
 #include "services/network/public/mojom/url_loader.mojom.h"
 #include "third_party/WebKit/public/platform/WebURLRequest.h"
 #include "url/gurl.h"
-#include "url/origin.h"
 
 namespace net {
 struct RedirectInfo;
@@ -50,7 +49,6 @@
 namespace content {
 class RequestPeer;
 class ResourceDispatcherDelegate;
-struct SiteIsolationResponseMetaData;
 struct SyncLoadResponse;
 class ThrottlingURLLoader;
 class URLLoaderClientImpl;
@@ -85,7 +83,6 @@
   virtual void StartSync(
       std::unique_ptr<network::ResourceRequest> request,
       int routing_id,
-      const url::Origin& frame_origin,
       const net::NetworkTrafficAnnotationTag& traffic_annotation,
       SyncLoadResponse* response,
       scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
@@ -104,7 +101,6 @@
       std::unique_ptr<network::ResourceRequest> request,
       int routing_id,
       scoped_refptr<base::SingleThreadTaskRunner> loading_task_runner,
-      const url::Origin& frame_origin,
       const net::NetworkTrafficAnnotationTag& traffic_annotation,
       bool is_sync,
       std::unique_ptr<RequestPeer> peer,
@@ -153,7 +149,6 @@
     PendingRequestInfo(std::unique_ptr<RequestPeer> peer,
                        ResourceType resource_type,
                        int render_frame_id,
-                       const url::Origin& frame_origin,
                        const GURL& request_url,
                        const std::string& method,
                        const GURL& referrer,
@@ -167,8 +162,6 @@
     bool is_deferred = false;
     // Original requested url.
     GURL url;
-    // The security origin of the frame that initiates this request.
-    url::Origin frame_origin;
     // The url, method and referrer of the latest response even in case of
     // redirection.
     GURL response_url;
@@ -180,7 +173,6 @@
     base::TimeTicks response_start;
     base::TimeTicks completion_time;
     linked_ptr<base::SharedMemory> buffer;
-    std::unique_ptr<SiteIsolationResponseMetaData> site_isolation_metadata;
     int buffer_size;
 
     // For mojo loading.
diff --git a/content/renderer/loader/resource_dispatcher_unittest.cc b/content/renderer/loader/resource_dispatcher_unittest.cc
index 5f1a87e6..c3da60c9 100644
--- a/content/renderer/loader/resource_dispatcher_unittest.cc
+++ b/content/renderer/loader/resource_dispatcher_unittest.cc
@@ -116,7 +116,7 @@
         new TestRequestPeer(dispatcher(), peer_context));
     int request_id = dispatcher()->StartAsync(
         std::move(request), 0,
-        blink::scheduler::GetSingleThreadTaskRunnerForTesting(), url::Origin(),
+        blink::scheduler::GetSingleThreadTaskRunnerForTesting(),
         TRAFFIC_ANNOTATION_FOR_TESTS, false, std::move(peer),
         base::MakeRefCounted<WeakWrapperSharedURLLoaderFactory>(this),
         std::vector<std::unique_ptr<URLLoaderThrottle>>(),
diff --git a/content/renderer/loader/site_isolation_stats_gatherer.cc b/content/renderer/loader/site_isolation_stats_gatherer.cc
deleted file mode 100644
index 5a88b1d..0000000
--- a/content/renderer/loader/site_isolation_stats_gatherer.cc
+++ /dev/null
@@ -1,259 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/renderer/loader/site_isolation_stats_gatherer.h"
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include "base/macros.h"
-#include "base/metrics/histogram_macros.h"
-#include "base/strings/string_piece.h"
-#include "base/strings/string_util.h"
-#include "net/http/http_response_headers.h"
-#include "services/network/public/cpp/resource_response_info.h"
-
-namespace content {
-
-namespace {
-
-// The gathering of UMA stats for site isolation is deactivated by default, and
-// only activated in renderer processes.
-static bool g_stats_gathering_enabled = false;
-
-bool IsYes(network::CrossOriginReadBlocking::Result result) {
-  return result == network::CrossOriginReadBlocking::Result::kYes;
-}
-
-bool IsRenderableStatusCode(int status_code) {
-  // Chrome only uses the content of a response with one of these status codes
-  // for CSS/JavaScript. For images, Chrome just ignores status code.
-  const int renderable_status_code[] = {
-      200, 201, 202, 203, 206, 300, 301, 302, 303, 305, 306, 307};
-  for (size_t i = 0; i < arraysize(renderable_status_code); ++i) {
-    if (renderable_status_code[i] == status_code)
-      return true;
-  }
-  return false;
-}
-
-void IncrementHistogramCount(const std::string& name) {
-  // The default value of min, max, bucket_count are copied from histogram.h.
-  base::HistogramBase* histogram_pointer = base::Histogram::FactoryGet(
-      name, 1, 100000, 50, base::HistogramBase::kUmaTargetedHistogramFlag);
-  histogram_pointer->Add(1);
-}
-
-void IncrementHistogramEnum(const std::string& name,
-                            uint32_t sample,
-                            uint32_t boundary_value) {
-  // The default value of min, max, bucket_count are copied from histogram.h.
-  base::HistogramBase* histogram_pointer = base::LinearHistogram::FactoryGet(
-      name, 1, boundary_value, boundary_value + 1,
-      base::HistogramBase::kUmaTargetedHistogramFlag);
-  histogram_pointer->Add(sample);
-}
-
-void HistogramCountBlockedResponse(
-    const std::string& bucket_prefix,
-    const std::unique_ptr<SiteIsolationResponseMetaData>& resp_data,
-    bool nosniff_block) {
-  std::string block_label(nosniff_block ? ".NoSniffBlocked" : ".Blocked");
-  IncrementHistogramCount(bucket_prefix + block_label);
-
-  // The content is blocked if it is sniffed as HTML/JSON/XML. When
-  // the blocked response is with an error status code, it is not
-  // disruptive for the following reasons : 1) the blocked content is
-  // not a binary object (such as an image) since it is sniffed as
-  // text; 2) then, this blocking only breaks the renderer behavior
-  // only if it is either JavaScript or CSS. However, the renderer
-  // doesn't use the contents of JS/CSS with unaffected status code
-  // (e.g, 404). 3) the renderer is expected not to use the cross-site
-  // document content for purposes other than JS/CSS (e.g, XHR).
-  bool renderable_status_code =
-      IsRenderableStatusCode(resp_data->http_status_code);
-
-  if (renderable_status_code) {
-    IncrementHistogramEnum(
-        bucket_prefix + block_label + ".RenderableStatusCode2",
-        resp_data->resource_type, RESOURCE_TYPE_LAST_TYPE);
-  } else {
-    IncrementHistogramCount(bucket_prefix + block_label +
-                            ".NonRenderableStatusCode");
-  }
-}
-
-void HistogramCountNotBlockedResponse(const std::string& bucket_prefix,
-                                      bool sniffed_as_js) {
-  IncrementHistogramCount(bucket_prefix + ".NotBlocked");
-  if (sniffed_as_js)
-    IncrementHistogramCount(bucket_prefix + ".NotBlocked.MaybeJS");
-}
-
-}  // namespace
-
-SiteIsolationResponseMetaData::SiteIsolationResponseMetaData() {
-}
-
-void SiteIsolationStatsGatherer::SetEnabled(bool enabled) {
-  g_stats_gathering_enabled = enabled;
-}
-
-std::unique_ptr<SiteIsolationResponseMetaData>
-SiteIsolationStatsGatherer::OnReceivedResponse(
-    const url::Origin& frame_origin,
-    const GURL& response_url,
-    ResourceType resource_type,
-    const network::ResourceResponseInfo& info) {
-  if (!g_stats_gathering_enabled)
-    return nullptr;
-
-  UMA_HISTOGRAM_COUNTS("SiteIsolation.AllResponses", 1);
-
-  // See if this is for navigation. If it is, don't block it, under the
-  // assumption that we will put it in an appropriate process.
-  if (IsResourceTypeFrame(resource_type))
-    return nullptr;
-
-  if (!network::CrossOriginReadBlocking::IsBlockableScheme(response_url))
-    return nullptr;
-
-  if (frame_origin.IsSameOriginWith(url::Origin::Create(response_url)))
-    return nullptr;
-
-  network::CrossOriginReadBlocking::MimeType canonical_mime_type =
-      network::CrossOriginReadBlocking::GetCanonicalMimeType(info.mime_type);
-
-  if (canonical_mime_type ==
-      network::CrossOriginReadBlocking::MimeType::kOthers)
-    return nullptr;
-
-  // Every CORS request should have the Access-Control-Allow-Origin header even
-  // if it is preceded by a pre-flight request. Therefore, if this is a CORS
-  // request, it has this header.  response.httpHeaderField() internally uses
-  // case-insensitive matching for the header name.
-  std::string access_control_origin;
-
-  // We can use a case-insensitive header name for EnumerateHeader().
-  info.headers->EnumerateHeader(nullptr, "access-control-allow-origin",
-                                &access_control_origin);
-  if (network::CrossOriginReadBlocking::IsValidCorsHeaderSet(
-          frame_origin, access_control_origin)) {
-    return nullptr;
-  }
-
-  // Real XSD data collection starts from here.
-  std::string no_sniff;
-  info.headers->EnumerateHeader(nullptr, "x-content-type-options", &no_sniff);
-
-  std::unique_ptr<SiteIsolationResponseMetaData> resp_data(
-      new SiteIsolationResponseMetaData);
-  resp_data->response_url = response_url;
-  resp_data->resource_type = resource_type;
-  resp_data->canonical_mime_type = canonical_mime_type;
-  resp_data->http_status_code = info.headers->response_code();
-  resp_data->no_sniff = base::LowerCaseEqualsASCII(no_sniff, "nosniff");
-
-  return resp_data;
-}
-
-bool SiteIsolationStatsGatherer::OnReceivedFirstChunk(
-    const std::unique_ptr<SiteIsolationResponseMetaData>& resp_data,
-    const char* raw_data,
-    int raw_length) {
-  if (!g_stats_gathering_enabled)
-    return false;
-
-  DCHECK(resp_data.get());
-
-  base::StringPiece data(raw_data, raw_length);
-
-  // Record the length of the first received chunk of data to see if it's enough
-  // for sniffing.
-  UMA_HISTOGRAM_COUNTS("SiteIsolation.XSD.DataLength", raw_length);
-
-  // Record the number of cross-site document responses with a specific mime
-  // type (text/html, text/xml, etc).
-  UMA_HISTOGRAM_ENUMERATION("SiteIsolation.XSD.MimeType",
-                            resp_data->canonical_mime_type,
-                            network::CrossOriginReadBlocking::MimeType::kMax);
-
-  // Store the result of cross-site document blocking analysis.
-  bool would_block = false;
-  bool sniffed_as_js = SniffForJS(data);
-
-  // Record the number of responses whose content is sniffed for what its mime
-  // type claims it to be. For example, we apply a HTML sniffer for a document
-  // tagged with text/html here. Whenever this check becomes true, we'll block
-  // the response.
-  if (resp_data->canonical_mime_type !=
-      network::CrossOriginReadBlocking::MimeType::kPlain) {
-    std::string bucket_prefix;
-    bool sniffed_as_target_document = false;
-    if (resp_data->canonical_mime_type ==
-        network::CrossOriginReadBlocking::MimeType::kHtml) {
-      bucket_prefix = "SiteIsolation.XSD.HTML";
-      sniffed_as_target_document =
-          IsYes(network::CrossOriginReadBlocking::SniffForHTML(data));
-    } else if (resp_data->canonical_mime_type ==
-               network::CrossOriginReadBlocking::MimeType::kXml) {
-      bucket_prefix = "SiteIsolation.XSD.XML";
-      sniffed_as_target_document =
-          IsYes(network::CrossOriginReadBlocking::SniffForXML(data));
-    } else if (resp_data->canonical_mime_type ==
-               network::CrossOriginReadBlocking::MimeType::kJson) {
-      bucket_prefix = "SiteIsolation.XSD.JSON";
-      sniffed_as_target_document =
-          IsYes(network::CrossOriginReadBlocking::SniffForJSON(data));
-    } else {
-      NOTREACHED() << "Not a blockable mime type: "
-                   << resp_data->canonical_mime_type;
-    }
-
-    if (sniffed_as_target_document) {
-      would_block = true;
-      HistogramCountBlockedResponse(bucket_prefix, resp_data, false);
-    } else {
-      if (resp_data->no_sniff) {
-        would_block = true;
-        HistogramCountBlockedResponse(bucket_prefix, resp_data, true);
-      } else {
-        HistogramCountNotBlockedResponse(bucket_prefix, sniffed_as_js);
-      }
-    }
-  } else {
-    // This block is for plain text documents. We apply our HTML, XML,
-    // and JSON sniffer to a text document in the order, and block it
-    // if any of them succeeds in sniffing.
-    std::string bucket_prefix;
-    if (IsYes(network::CrossOriginReadBlocking::SniffForHTML(data)))
-      bucket_prefix = "SiteIsolation.XSD.Plain.HTML";
-    else if (IsYes(network::CrossOriginReadBlocking::SniffForXML(data)))
-      bucket_prefix = "SiteIsolation.XSD.Plain.XML";
-    else if (IsYes(network::CrossOriginReadBlocking::SniffForJSON(data)))
-      bucket_prefix = "SiteIsolation.XSD.Plain.JSON";
-
-    if (bucket_prefix.size() > 0) {
-      would_block = true;
-      HistogramCountBlockedResponse(bucket_prefix, resp_data, false);
-    } else if (resp_data->no_sniff) {
-      would_block = true;
-      HistogramCountBlockedResponse("SiteIsolation.XSD.Plain", resp_data, true);
-    } else {
-      HistogramCountNotBlockedResponse("SiteIsolation.XSD.Plain",
-                                       sniffed_as_js);
-    }
-  }
-
-  return would_block;
-}
-
-bool SiteIsolationStatsGatherer::SniffForJS(base::StringPiece data) {
-  // The purpose of this function is to try to see if there's any possibility
-  // that this data can be JavaScript (superset of JS). Search for "var " for JS
-  // detection. This is a real hack and should only be used for stats gathering.
-  return data.find("var ") != base::StringPiece::npos;
-}
-
-}  // namespace content
diff --git a/content/renderer/loader/site_isolation_stats_gatherer.h b/content/renderer/loader/site_isolation_stats_gatherer.h
deleted file mode 100644
index 736a269..0000000
--- a/content/renderer/loader/site_isolation_stats_gatherer.h
+++ /dev/null
@@ -1,102 +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 CONTENT_RENDERER_LOADER_SITE_ISOLATION_STATS_GATHERER_H_
-#define CONTENT_RENDERER_LOADER_SITE_ISOLATION_STATS_GATHERER_H_
-
-#include <memory>
-#include <string>
-
-#include "base/gtest_prod_util.h"
-#include "base/macros.h"
-#include "base/strings/string_piece.h"
-#include "content/common/content_export.h"
-#include "content/public/common/resource_type.h"
-#include "services/network/cross_origin_read_blocking.h"
-#include "url/gurl.h"
-#include "url/origin.h"
-
-namespace network {
-struct ResourceResponseInfo;
-}
-
-namespace content {
-
-// SiteIsolationStatsGatherer monitors responses to gather various UMA stats to
-// see the compatibility impact of actual deployment of the policy. The UMA stat
-// categories SiteIsolationStatsGatherer gathers are as follows:
-//
-// SiteIsolation.AllResponses : # of all network responses.
-// SiteIsolation.XSD.DataLength : the length of the first packet of a response.
-// SiteIsolation.XSD.MimeType (enum):
-//   # of responses from other sites, tagged with a document mime type.
-//   0:HTML, 1:XML, 2:JSON, 3:Plain, 4:Others
-// SiteIsolation.XSD.[%MIMETYPE].Blocked :
-//   blocked # of cross-site document responses grouped by sniffed MIME type.
-// SiteIsolation.XSD.[%MIMETYPE].Blocked.RenderableStatusCode2 :
-//   # of responses with renderable status code,
-//   out of SiteIsolation.XSD.[%MIMETYPE].Blocked.
-// SiteIsolation.XSD.[%MIMETYPE].Blocked.NonRenderableStatusCode :
-//   # of responses with non-renderable status code,
-//   out of SiteIsolation.XSD.[%MIMETYPE].Blocked.
-// SiteIsolation.XSD.[%MIMETYPE].NoSniffBlocked.RenderableStatusCode2 :
-//   # of responses failed to be sniffed for its MIME type, but blocked by
-//   "X-Content-Type-Options: nosniff" header, and with renderable status code
-//   out of SiteIsolation.XSD.[%MIMETYPE].Blocked.
-// SiteIsolation.XSD.[%MIMETYPE].NoSniffBlocked.NonRenderableStatusCode :
-//   # of responses failed to be sniffed for its MIME type, but blocked by
-//   "X-Content-Type-Options: nosniff" header, and with non-renderable status
-//   code out of SiteIsolation.XSD.[%MIMETYPE].Blocked.
-// SiteIsolation.XSD.[%MIMETYPE].NotBlocked :
-//   # of responses, but not blocked due to failure of mime sniffing.
-// SiteIsolation.XSD.[%MIMETYPE].NotBlocked.MaybeJS :
-//   # of responses that are plausibly sniffed to be JavaScript.
-
-struct SiteIsolationResponseMetaData {
-  SiteIsolationResponseMetaData();
-
-  GURL response_url;
-  ResourceType resource_type;
-  network::CrossOriginReadBlocking::MimeType canonical_mime_type;
-  int http_status_code;
-  bool no_sniff;
-};
-
-class CONTENT_EXPORT SiteIsolationStatsGatherer {
- public:
-  // Set activation flag for the UMA data collection for this renderer process.
-  static void SetEnabled(bool enabled);
-
-  // Returns any bookkeeping data about the HTTP header information for the
-  // request identified by |request_id|. Any data returned should then be
-  // passed to OnReceivedFirstChunk() with the first data chunk.
-  static std::unique_ptr<SiteIsolationResponseMetaData> OnReceivedResponse(
-      const url::Origin& frame_origin,
-      const GURL& response_url,
-      ResourceType resource_type,
-      const network::ResourceResponseInfo& info);
-
-  // Examines the first chunk of network data in case response_url is registered
-  // as a cross-site document by OnReceivedResponse(). This records various
-  // kinds of UMA data stats. This function is called only if the length of
-  // received data is non-zero.
-  static bool OnReceivedFirstChunk(
-      const std::unique_ptr<SiteIsolationResponseMetaData>& resp_data,
-      const char* payload,
-      int length);
-
- private:
-  FRIEND_TEST_ALL_PREFIXES(SiteIsolationStatsGathererTest, SniffForJS);
-
-  SiteIsolationStatsGatherer();  // Not instantiable.
-
-  // Imprecise JS sniffing; only appropriate for collecting UMA stat.
-  static bool SniffForJS(base::StringPiece data);
-
-  DISALLOW_COPY_AND_ASSIGN(SiteIsolationStatsGatherer);
-};
-
-}  // namespace content
-
-#endif  // CONTENT_RENDERER_LOADER_SITE_ISOLATION_STATS_GATHERER_H_
diff --git a/content/renderer/loader/site_isolation_stats_gatherer_browsertest.cc b/content/renderer/loader/site_isolation_stats_gatherer_browsertest.cc
deleted file mode 100644
index 124eea57..0000000
--- a/content/renderer/loader/site_isolation_stats_gatherer_browsertest.cc
+++ /dev/null
@@ -1,207 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/command_line.h"
-#include "base/macros.h"
-#include "base/strings/pattern.h"
-#include "base/strings/string_util.h"
-#include "base/strings/stringprintf.h"
-#include "base/test/histogram_tester.h"
-#include "content/public/common/content_switches.h"
-#include "content/public/common/resource_type.h"
-#include "content/public/test/browser_test_utils.h"
-#include "content/public/test/content_browser_test.h"
-#include "content/public/test/content_browser_test_utils.h"
-#include "content/public/test/test_utils.h"
-#include "content/shell/browser/shell.h"
-#include "net/test/embedded_test_server/embedded_test_server.h"
-#include "services/network/public/cpp/network_switches.h"
-#include "testing/gmock/include/gmock/gmock.h"
-
-namespace content {
-
-// These tests simulate exploited renderer processes, which can fetch arbitrary
-// resources from other websites, not constrained by the Same Origin Policy.  We
-// are trying to verify that the renderer cannot fetch any cross-site document
-// responses even when the Same Origin Policy is turned off inside the renderer.
-class SiteIsolationStatsGathererBrowserTest : public ContentBrowserTest {
- public:
-  SiteIsolationStatsGathererBrowserTest() {}
-  ~SiteIsolationStatsGathererBrowserTest() override {}
-
-  void SetUpCommandLine(base::CommandLine* command_line) override {
-    // EmbeddedTestServer::InitializeAndListen() initializes its |base_url_|
-    // which is required below. This cannot invoke Start() however as that kicks
-    // off the "EmbeddedTestServer IO Thread" which then races with
-    // initialization in ContentBrowserTest::SetUp(), http://crbug.com/674545.
-    ASSERT_TRUE(embedded_test_server()->InitializeAndListen());
-
-    // Add a host resolver rule to map all outgoing requests to the test server.
-    // This allows us to use "real" hostnames in URLs, which we can use to
-    // create arbitrary SiteInstances.
-    command_line->AppendSwitchASCII(
-        network::switches::kHostResolverRules,
-        "MAP * " + embedded_test_server()->host_port_pair().ToString() +
-            ",EXCLUDE localhost");
-
-    // Since we assume exploited renderer process, it can bypass the same origin
-    // policy at will. Simulate that by passing the disable-web-security flag.
-    command_line->AppendSwitch(switches::kDisableWebSecurity);
-  }
-
-  void SetUpOnMainThread() override {
-    // Complete the manual Start() after ContentBrowserTest's own
-    // initialization, ref. comment on InitializeAndListen() above.
-    embedded_test_server()->StartAcceptingConnections();
-  }
-
-  void InspectHistograms(const base::HistogramTester& histograms,
-                         bool should_be_blocked,
-                         const std::string& resource_name) {
-    std::string bucket;
-    int mime_type = 0;  // Hardcoded because histogram enums mustn't change.
-    if (base::MatchPattern(resource_name, "*.html")) {
-      bucket = "HTML";
-      mime_type = 0;
-    } else if (base::MatchPattern(resource_name, "*.xml")) {
-      bucket = "XML";
-      mime_type = 1;
-    } else if (base::MatchPattern(resource_name, "*.json")) {
-      bucket = "JSON";
-      mime_type = 2;
-    } else if (base::MatchPattern(resource_name, "*.txt")) {
-      bucket = "Plain";
-      mime_type = 3;
-      if (base::MatchPattern(resource_name, "json*")) {
-        bucket += ".JSON";
-      } else if (base::MatchPattern(resource_name, "html*")) {
-        bucket += ".HTML";
-      } else if (base::MatchPattern(resource_name, "xml*")) {
-        bucket += ".XML";
-      }
-    } else {
-      FAIL();
-    }
-    FetchHistogramsFromChildProcesses();
-
-    // A few histograms are incremented unconditionally.
-    histograms.ExpectUniqueSample("SiteIsolation.AllResponses", 1, 1);
-    base::HistogramTester::CountsMap expected_metrics;
-    expected_metrics["SiteIsolation.XSD.DataLength"] = 1;
-    expected_metrics["SiteIsolation.XSD.MimeType"] = 1;
-
-    // Determine the appropriate conditionally-incremented histograms.
-    std::string base = "SiteIsolation.XSD." + bucket;
-    if (should_be_blocked) {
-      expected_metrics[base + ".Blocked"] = 1;
-      expected_metrics[base + ".Blocked.RenderableStatusCode2"] = 1;
-    } else {
-      expected_metrics[base + ".NotBlocked"] = 1;
-      if (base::MatchPattern(resource_name, "*js.*")) {
-        expected_metrics[base + ".NotBlocked.MaybeJS"] = 1;
-      }
-    }
-    // This metric from the browser process also records start and stop actions
-    // for the blocking logic, even though blocking is disabled in the browser
-    // process when this test runs.
-    expected_metrics["SiteIsolation.XSD.Browser.Action"] = 2;
-
-    // Make sure that the expected metrics, and only those metrics, were
-    // incremented.
-    EXPECT_THAT(histograms.GetTotalCountsForPrefix("SiteIsolation.XSD."),
-                testing::ContainerEq(expected_metrics))
-        << "For resource_name=" << resource_name
-        << ", should_be_blocked=" << should_be_blocked;
-
-    EXPECT_THAT(histograms.GetAllSamples("SiteIsolation.XSD.MimeType"),
-                testing::ElementsAre(base::Bucket(mime_type, 1)))
-        << "The wrong mime type bucket was incremented.";
-    if (should_be_blocked) {
-      static_assert(13 == RESOURCE_TYPE_XHR, "Histogram enums mustn't change.");
-      EXPECT_THAT(
-          histograms.GetAllSamples(base + ".Blocked.RenderableStatusCode2"),
-          testing::ElementsAre(base::Bucket(RESOURCE_TYPE_XHR, 1)))
-          << "The wrong RenderableStatusCode2 bucket was incremented.";
-    }
-  }
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(SiteIsolationStatsGathererBrowserTest);
-};
-
-IN_PROC_BROWSER_TEST_F(SiteIsolationStatsGathererBrowserTest,
-                       CrossSiteDocumentBlockingForMimeType) {
-  // This test is disabled in --site-per-process, since the documents are
-  // blocked before arriving in the renderer process and thus the existing
-  // histograms do not work.
-  if (AreAllSitesIsolatedForTesting())
-    return;
-
-  // Load a page that issues illegal cross-site document requests to bar.com.
-  // The page uses XHR to request HTML/XML/JSON documents from bar.com, and
-  // inspects if any of them were successfully received. Currently, on illegal
-  // access, the XHR requests should succeed, but the UMA histograms should
-  // record that they would have been blocked. This test is only possible since
-  // we run the browser without the same origin policy.
-  GURL foo("http://foo.com/cross_site_document_blocking/request.html");
-
-  EXPECT_TRUE(NavigateToURL(shell(), foo));
-
-  // Flush out existing histogram activity.
-  FetchHistogramsFromChildProcesses();
-
-  // The following are files under content/test/data/site_isolation. All
-  // should be disallowed for cross site XHR under the document blocking policy.
-  const char* blocked_resources[] = {
-      "comment_valid.html", "html.txt",      "html4_dtd.html", "html4_dtd.txt",
-      "html5_dtd.html",     "html5_dtd.txt", "json.txt",       "valid.html",
-      "valid.json",         "valid.xml",     "xml.txt"};
-
-  for (const char* resource : blocked_resources) {
-    SCOPED_TRACE(base::StringPrintf("... while testing page: %s", resource));
-    base::HistogramTester histograms;
-
-    bool was_blocked;
-    ASSERT_TRUE(ExecuteScriptAndExtractBool(
-        shell(), base::StringPrintf("sendRequest('%s');", resource),
-        &was_blocked));
-    ASSERT_FALSE(was_blocked);
-
-    InspectHistograms(histograms, true, resource);
-  }
-
-  // These files should be allowed for XHR under the document blocking policy.
-  const char* allowed_resources[] = {"js.html", "comment_js.html", "js.xml",
-                                     "js.json", "js.txt",          "img.html",
-                                     "img.xml", "img.json",        "img.txt"};
-  for (const char* resource : allowed_resources) {
-    SCOPED_TRACE(base::StringPrintf("... while testing page: %s", resource));
-    base::HistogramTester histograms;
-
-    bool was_blocked;
-    ASSERT_TRUE(ExecuteScriptAndExtractBool(
-        shell(), base::StringPrintf("sendRequest('%s');", resource),
-        &was_blocked));
-    ASSERT_FALSE(was_blocked);
-
-    InspectHistograms(histograms, false, resource);
-  }
-}
-
-IN_PROC_BROWSER_TEST_F(SiteIsolationStatsGathererBrowserTest,
-                       CrossSiteDocumentBlockingForDifferentTargets) {
-  // This webpage loads a cross-site HTML page in different targets such as
-  // <img>,<link>,<embed>, etc. Since the requested document is blocked, and one
-  // character string (' ') is returned instead, this tests that the renderer
-  // does not crash even when it receives a response body which is " ", whose
-  // length is different from what's described in "content-length" for such
-  // different targets.
-
-  // TODO(nick): Split up these cases, and add positive assertions here about
-  // what actually happens in these various resource-block cases.
-  GURL foo("http://foo.com/cross_site_document_blocking/request_target.html");
-  EXPECT_TRUE(NavigateToURL(shell(), foo));
-}
-
-}  // namespace content
diff --git a/content/renderer/loader/site_isolation_stats_gatherer_unittest.cc b/content/renderer/loader/site_isolation_stats_gatherer_unittest.cc
deleted file mode 100644
index f34659c..0000000
--- a/content/renderer/loader/site_isolation_stats_gatherer_unittest.cc
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/strings/string_piece.h"
-#include "content/renderer/loader/site_isolation_stats_gatherer.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using base::StringPiece;
-
-namespace content {
-
-TEST(SiteIsolationStatsGathererTest, SniffForJS) {
-  StringPiece basic_js_data("var a = 4");
-  StringPiece js_data("\t\t\r\n var a = 4");
-  StringPiece json_data("\t\t\r\n   { \"name\" : \"chrome\", ");
-  StringPiece empty_data("");
-
-  EXPECT_TRUE(SiteIsolationStatsGatherer::SniffForJS(js_data));
-  EXPECT_FALSE(SiteIsolationStatsGatherer::SniffForJS(json_data));
-
-  // Basic bounds check.
-  EXPECT_FALSE(SiteIsolationStatsGatherer::SniffForJS(empty_data));
-}
-
-}  // namespace content
diff --git a/content/renderer/loader/sync_load_context.cc b/content/renderer/loader/sync_load_context.cc
index 4ad31b2..85db10a 100644
--- a/content/renderer/loader/sync_load_context.cc
+++ b/content/renderer/loader/sync_load_context.cc
@@ -21,7 +21,6 @@
     std::unique_ptr<network::ResourceRequest> request,
     int routing_id,
     scoped_refptr<base::SingleThreadTaskRunner> loading_task_runner,
-    const url::Origin& frame_origin,
     const net::NetworkTrafficAnnotationTag& traffic_annotation,
     std::unique_ptr<network::SharedURLLoaderFactoryInfo>
         url_loader_factory_info,
@@ -34,9 +33,9 @@
 
   context->request_id_ = context->resource_dispatcher_->StartAsync(
       std::move(request), routing_id, std::move(loading_task_runner),
-      frame_origin, traffic_annotation, true /* is_sync */,
-      base::WrapUnique(context), context->url_loader_factory_,
-      std::move(throttles), network::mojom::URLLoaderClientEndpointsPtr(),
+      traffic_annotation, true /* is_sync */, base::WrapUnique(context),
+      context->url_loader_factory_, std::move(throttles),
+      network::mojom::URLLoaderClientEndpointsPtr(),
       nullptr /* continue_for_navigation */);
 }
 
diff --git a/content/renderer/loader/sync_load_context.h b/content/renderer/loader/sync_load_context.h
index 808fed9..d32d25f 100644
--- a/content/renderer/loader/sync_load_context.h
+++ b/content/renderer/loader/sync_load_context.h
@@ -15,10 +15,6 @@
 class WaitableEvent;
 }
 
-namespace url {
-class Origin;
-}
-
 namespace network {
 struct ResourceRequest;
 }
@@ -38,7 +34,6 @@
       std::unique_ptr<network::ResourceRequest> request,
       int routing_id,
       scoped_refptr<base::SingleThreadTaskRunner> loading_task_runner,
-      const url::Origin& frame_origin,
       const net::NetworkTrafficAnnotationTag& traffic_annotation,
       std::unique_ptr<network::SharedURLLoaderFactoryInfo>
           url_loader_factory_info,
diff --git a/content/renderer/loader/url_loader_client_impl_unittest.cc b/content/renderer/loader/url_loader_client_impl_unittest.cc
index b71a08ed..eca5f99 100644
--- a/content/renderer/loader/url_loader_client_impl_unittest.cc
+++ b/content/renderer/loader/url_loader_client_impl_unittest.cc
@@ -27,7 +27,7 @@
   URLLoaderClientImplTest() : dispatcher_(new ResourceDispatcher()) {
     request_id_ = dispatcher_->StartAsync(
         std::make_unique<network::ResourceRequest>(), 0,
-        blink::scheduler::GetSingleThreadTaskRunnerForTesting(), url::Origin(),
+        blink::scheduler::GetSingleThreadTaskRunnerForTesting(),
         TRAFFIC_ANNOTATION_FOR_TESTS, false,
         std::make_unique<TestRequestPeer>(dispatcher_.get(),
                                           &request_peer_context_),
diff --git a/content/renderer/loader/url_response_body_consumer.cc b/content/renderer/loader/url_response_body_consumer.cc
index 0379b99..713319a 100644
--- a/content/renderer/loader/url_response_body_consumer.cc
+++ b/content/renderer/loader/url_response_body_consumer.cc
@@ -10,7 +10,6 @@
 #include "base/memory/ptr_util.h"
 #include "content/public/renderer/request_peer.h"
 #include "content/renderer/loader/resource_dispatcher.h"
-#include "content/renderer/loader/site_isolation_stats_gatherer.h"
 #include "services/network/public/cpp/url_loader_completion_status.h"
 
 namespace content {
@@ -148,15 +147,6 @@
         resource_dispatcher_->GetPendingRequestInfo(request_id_);
     DCHECK(request_info);
 
-    // Check whether this response data is compliant with our cross-site
-    // document blocking policy. We only do this for the first chunk of data.
-    if (request_info->site_isolation_metadata.get()) {
-      SiteIsolationStatsGatherer::OnReceivedFirstChunk(
-          request_info->site_isolation_metadata,
-          static_cast<const char*>(buffer), available);
-      request_info->site_isolation_metadata.reset();
-    }
-
     request_info->peer->OnReceivedData(std::make_unique<ReceivedData>(
         static_cast<const char*>(buffer), available, this));
   }
diff --git a/content/renderer/loader/url_response_body_consumer_unittest.cc b/content/renderer/loader/url_response_body_consumer_unittest.cc
index c7a6630f1..79144db 100644
--- a/content/renderer/loader/url_response_body_consumer_unittest.cc
+++ b/content/renderer/loader/url_response_body_consumer_unittest.cc
@@ -150,7 +150,7 @@
                        TestRequestPeer::Context* context) {
     return dispatcher_->StartAsync(
         std::move(request), 0,
-        blink::scheduler::GetSingleThreadTaskRunnerForTesting(), url::Origin(),
+        blink::scheduler::GetSingleThreadTaskRunnerForTesting(),
         TRAFFIC_ANNOTATION_FOR_TESTS, false,
         std::make_unique<TestRequestPeer>(context, message_loop_.task_runner()),
         base::MakeRefCounted<WeakWrapperSharedURLLoaderFactory>(&factory_),
diff --git a/content/renderer/loader/web_url_loader_impl.cc b/content/renderer/loader/web_url_loader_impl.cc
index 3f91217..adebe3e1 100644
--- a/content/renderer/loader/web_url_loader_impl.cc
+++ b/content/renderer/loader/web_url_loader_impl.cc
@@ -739,9 +739,8 @@
 
     resource_dispatcher_->StartSync(
         std::move(resource_request), request.RequestorID(),
-        extra_data->frame_origin(), GetTrafficAnnotationTag(request),
-        sync_load_response, url_loader_factory_,
-        extra_data->TakeURLLoaderThrottles());
+        GetTrafficAnnotationTag(request), sync_load_response,
+        url_loader_factory_, extra_data->TakeURLLoaderThrottles());
     return;
   }
 
@@ -760,9 +759,8 @@
   base::OnceClosure continue_navigation_function;
   request_id_ = resource_dispatcher_->StartAsync(
       std::move(resource_request), request.RequestorID(), task_runner_,
-      extra_data->frame_origin(), GetTrafficAnnotationTag(request),
-      false /* is_sync */, std::move(peer), url_loader_factory_,
-      extra_data->TakeURLLoaderThrottles(),
+      GetTrafficAnnotationTag(request), false /* is_sync */, std::move(peer),
+      url_loader_factory_, extra_data->TakeURLLoaderThrottles(),
       std::move(url_loader_client_endpoints), &continue_navigation_function);
   extra_data->set_continue_navigation_function(
       std::move(continue_navigation_function));
diff --git a/content/renderer/loader/web_url_loader_impl_unittest.cc b/content/renderer/loader/web_url_loader_impl_unittest.cc
index ee71ffa..142e2cd 100644
--- a/content/renderer/loader/web_url_loader_impl_unittest.cc
+++ b/content/renderer/loader/web_url_loader_impl_unittest.cc
@@ -73,7 +73,6 @@
   void StartSync(
       std::unique_ptr<network::ResourceRequest> request,
       int routing_id,
-      const url::Origin& frame_origin,
       const net::NetworkTrafficAnnotationTag& traffic_annotation,
       SyncLoadResponse* response,
       scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
@@ -85,7 +84,6 @@
       std::unique_ptr<network::ResourceRequest> request,
       int routing_id,
       scoped_refptr<base::SingleThreadTaskRunner> loading_task_runner,
-      const url::Origin& frame_origin,
       const net::NetworkTrafficAnnotationTag& traffic_annotation,
       bool is_sync,
       std::unique_ptr<RequestPeer> peer,
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index c293c90..e2f3492 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -4882,7 +4882,6 @@
   extra_data->set_requested_with(requested_with);
   extra_data->set_render_frame_id(routing_id_);
   extra_data->set_is_main_frame(!parent);
-  extra_data->set_frame_origin(url::Origin(frame_document.GetSecurityOrigin()));
   extra_data->set_allow_download(
       navigation_state->common_params().allow_download);
   extra_data->set_transition_type(transition_type);
diff --git a/content/renderer/render_process_impl.cc b/content/renderer/render_process_impl.cc
index 77d5234..7f5e64c 100644
--- a/content/renderer/render_process_impl.cc
+++ b/content/renderer/render_process_impl.cc
@@ -34,7 +34,6 @@
 #include "content/public/common/content_features.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/renderer/content_renderer_client.h"
-#include "content/renderer/loader/site_isolation_stats_gatherer.h"
 #include "services/service_manager/embedder/switches.h"
 #include "third_party/WebKit/public/web/WebFrame.h"
 #include "v8/include/v8.h"
@@ -184,9 +183,6 @@
     v8::V8::SetFlagsFromString(flags.c_str(), static_cast<int>(flags.size()));
   }
 
-  SiteIsolationStatsGatherer::SetEnabled(
-      GetContentClient()->renderer()->ShouldGatherSiteIsolationStats());
-
   if (command_line.HasSwitch(switches::kDomAutomationController))
     enabled_bindings_ |= BINDINGS_POLICY_DOM_AUTOMATION;
   if (command_line.HasSwitch(switches::kStatsCollectionController))
diff --git a/content/renderer/render_widget_unittest.cc b/content/renderer/render_widget_unittest.cc
index ec511998..c9c9089 100644
--- a/content/renderer/render_widget_unittest.cc
+++ b/content/renderer/render_widget_unittest.cc
@@ -82,6 +82,8 @@
 
   MOCK_METHOD0(DidStopFlinging, void());
 
+  MOCK_METHOD0(DidStartScrollingViewport, void());
+
   MOCK_METHOD0(ImeCancelComposition, void());
 
   MOCK_METHOD2(ImeCompositionRangeChanged,
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index 0aece684..d0d17863 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -833,7 +833,6 @@
     "../renderer/accessibility/render_accessibility_impl_browsertest.cc",
     "../renderer/blink_platform_audio_hardware_browsertest.cc",
     "../renderer/gin_browsertest.cc",
-    "../renderer/loader/site_isolation_stats_gatherer_browsertest.cc",
     "../renderer/media/renderer_webmediaplayer_delegate_browsertest.cc",
     "../renderer/mouse_lock_dispatcher_browsertest.cc",
     "../renderer/render_frame_impl_browsertest.cc",
@@ -1586,7 +1585,6 @@
     "../renderer/input/main_thread_event_queue_unittest.cc",
     "../renderer/loader/resource_dispatcher_unittest.cc",
     "../renderer/loader/shared_memory_data_consumer_handle_unittest.cc",
-    "../renderer/loader/site_isolation_stats_gatherer_unittest.cc",
     "../renderer/loader/test_request_peer.cc",
     "../renderer/loader/test_request_peer.h",
     "../renderer/loader/url_loader_client_impl_unittest.cc",
diff --git a/device/fido/fido_ble_transaction.cc b/device/fido/fido_ble_transaction.cc
index 8974ba5..64a7ffd 100644
--- a/device/fido/fido_ble_transaction.cc
+++ b/device/fido/fido_ble_transaction.cc
@@ -130,7 +130,7 @@
 
 void FidoBleTransaction::OnError() {
   request_frame_.reset();
-  request_cont_fragments_ = {};
+  request_cont_fragments_ = base::queue<FidoBleFrameContinuationFragment>();
   response_frame_assembler_.reset();
   std::move(callback_).Run(base::nullopt);
 }
diff --git a/docs/google_play_services.md b/docs/google_play_services.md
index b526cb9..4d285b55 100644
--- a/docs/google_play_services.md
+++ b/docs/google_play_services.md
@@ -48,4 +48,4 @@
 reverted, so please make sure the APIs are available to the bots before
 submitting.
 
-[bug_link]:https://bugs.chromium.org/p/chromium/issues/entry?labels=Restrict-View-Google,pri-1,Hotlist-GooglePlayServices&owner=dgn@chromium.org&os=Android
+[bug_link]:https://bugs.chromium.org/p/chromium/issues/entry?labels=Restrict-View-Google,pri-1,Hotlist-GooglePlayServices&owner=agrieve@chromium.org&os=Android
diff --git a/extensions/renderer/bindings/api_binding_bridge.cc b/extensions/renderer/bindings/api_binding_bridge.cc
index 1d8d169..09967760 100644
--- a/extensions/renderer/bindings/api_binding_bridge.cc
+++ b/extensions/renderer/bindings/api_binding_bridge.cc
@@ -101,6 +101,12 @@
   v8::Local<v8::String> context_type =
       gin::StringToSymbol(isolate, context_type_);
   v8::Local<v8::Value> args[] = {hook_object, extension_id, context_type};
+
+  // TODO(devlin): The context should still be valid at this point - nothing
+  // above should be able to invalidate it. But let's make extra sure.
+  // This CHECK is helping to track down https://crbug.com/819968, and should be
+  // removed when that's fixed.
+  CHECK(binding::IsContextValid(context));
   JSRunner::Get(context)->RunJSFunction(function, context, arraysize(args),
                                         args);
 }
diff --git a/extensions/renderer/bindings/api_binding_util.cc b/extensions/renderer/bindings/api_binding_util.cc
index a575c2d..d8cd664 100644
--- a/extensions/renderer/bindings/api_binding_util.cc
+++ b/extensions/renderer/bindings/api_binding_util.cc
@@ -9,6 +9,7 @@
 #include "base/supports_user_data.h"
 #include "build/build_config.h"
 #include "extensions/renderer/bindings/get_per_context_data.h"
+#include "extensions/renderer/bindings/js_runner.h"
 #include "gin/converter.h"
 #include "gin/per_context_data.h"
 
@@ -75,7 +76,18 @@
           ContextInvalidationData::kPerContextDataKey));
   // The context is valid if we've never created invalidation data for it, or if
   // we have and it hasn't been marked as invalid.
-  return !invalidation_data || invalidation_data->is_context_valid();
+  bool is_context_valid =
+      !invalidation_data || invalidation_data->is_context_valid();
+
+  if (is_context_valid) {
+    // As long as the context is valid, there should be an associated
+    // JSRunner.
+    // TODO(devlin): (Likely) Remove this once https://crbug.com/819968, since
+    // this shouldn't necessarily be a hard dependency. At least downgrade it
+    // to a DCHECK.
+    CHECK(JSRunner::Get(context));
+  }
+  return is_context_valid;
 }
 
 bool IsContextValidOrThrowError(v8::Local<v8::Context> context) {
diff --git a/extensions/renderer/native_extension_bindings_system.cc b/extensions/renderer/native_extension_bindings_system.cc
index 3727b42a..10f329d6 100644
--- a/extensions/renderer/native_extension_bindings_system.cc
+++ b/extensions/renderer/native_extension_bindings_system.cc
@@ -405,8 +405,10 @@
     ScriptContext* context) {
   v8::HandleScope handle_scope(context->isolate());
   v8::Local<v8::Context> v8_context = context->v8_context();
-  JSRunner::ClearInstanceForContext(v8_context);
   api_system_.WillReleaseContext(v8_context);
+  // Clear the JSRunner only after everything else has been notified that the
+  // context is being released.
+  JSRunner::ClearInstanceForContext(v8_context);
 }
 
 void NativeExtensionBindingsSystem::UpdateBindingsForContext(
diff --git a/extensions/shell/renderer/shell_content_renderer_client.cc b/extensions/shell/renderer/shell_content_renderer_client.cc
index a09efe4..0263724 100644
--- a/extensions/shell/renderer/shell_content_renderer_client.cc
+++ b/extensions/shell/renderer/shell_content_renderer_client.cc
@@ -105,10 +105,6 @@
 #endif
 }
 
-bool ShellContentRendererClient::ShouldGatherSiteIsolationStats() const {
-  return false;
-}
-
 content::BrowserPluginDelegate*
 ShellContentRendererClient::CreateBrowserPluginDelegate(
     content::RenderFrame* render_frame,
diff --git a/extensions/shell/renderer/shell_content_renderer_client.h b/extensions/shell/renderer/shell_content_renderer_client.h
index f0f64b46..21549a9 100644
--- a/extensions/shell/renderer/shell_content_renderer_client.h
+++ b/extensions/shell/renderer/shell_content_renderer_client.h
@@ -42,7 +42,6 @@
       const blink::WebURL& url,
       GURL* new_url) override;
   bool IsExternalPepperPlugin(const std::string& module_name) override;
-  bool ShouldGatherSiteIsolationStats() const override;
   content::BrowserPluginDelegate* CreateBrowserPluginDelegate(
       content::RenderFrame* render_frame,
       const content::WebPluginInfo& info,
diff --git a/gpu/command_buffer/build_cmd_buffer_lib.py b/gpu/command_buffer/build_cmd_buffer_lib.py
index 7b507ab..acfc834 100644
--- a/gpu/command_buffer/build_cmd_buffer_lib.py
+++ b/gpu/command_buffer/build_cmd_buffer_lib.py
@@ -2833,7 +2833,7 @@
     f.write("    SetHeader();\n")
     args = func.GetCmdArgs()
     for arg in args:
-      f.write("    %s = _%s;\n" % (arg.name, arg.name))
+      arg.WriteSetCode(f, 4, "_%s" % arg.name)
     f.write("    memcpy(ImmediateDataAddress(this),\n")
     if self.__NeedsToCalcDataCount(func):
       f.write("           _%s, ComputeEffectiveDataSize(%s));" %
@@ -2908,8 +2908,8 @@
     f.write("            RoundSizeToMultipleOfEntries(sizeof(data)),\n")
     f.write("            cmd.header.size * 4u);\n")
     for value, arg in enumerate(args):
-      f.write("  EXPECT_EQ(static_cast<%s>(%d), cmd.%s);\n" %
-                 (arg.type, value + 11, arg.name))
+      f.write("  EXPECT_EQ(static_cast<%s>(%d), %s);\n" %
+                 (arg.type, value + 11, arg.GetArgAccessor('cmd')))
     f.write("  CheckBytesWrittenMatchesExpectedSize(\n")
     f.write("      next_cmd, sizeof(cmd) +\n")
     f.write("      RoundSizeToMultipleOfEntries(sizeof(data)));\n")
@@ -3181,7 +3181,7 @@
     f.write("    SetHeader(_count);\n")
     args = func.GetCmdArgs()
     for arg in args:
-      f.write("    %s = _%s;\n" % (arg.name, arg.name))
+      arg.WriteSetCode(f, 4, "_%s" % arg.name)
     f.write("    memcpy(ImmediateDataAddress(this),\n")
     pointer_arg = func.GetLastOriginalPointerArg()
     f.write("           _%s, ComputeDataSize(_count));\n" % pointer_arg.name)
@@ -3256,8 +3256,8 @@
     for value, arg in enumerate(args):
       if arg.IsPointer() or arg.IsConstant():
         continue
-      f.write("  EXPECT_EQ(static_cast<%s>(%d), cmd.%s);\n" %
-                 (arg.type, value + 1, arg.name))
+      f.write("  EXPECT_EQ(static_cast<%s>(%d), %s);\n" %
+                 (arg.type, value + 1, arg.GetArgAccessor('cmd')))
     f.write("  CheckBytesWrittenMatchesExpectedSize(\n")
     f.write("      next_cmd, sizeof(cmd) +\n")
     f.write("      RoundSizeToMultipleOfEntries(sizeof(data)));\n")
@@ -3663,22 +3663,19 @@
     """Overrriden from TypeHandler."""
     last_arg = func.GetLastOriginalArg()
     args = func.GetCmdArgs()
-    set_code = []
-    for arg in args:
-      set_code.append("    %s = _%s;" % (arg.name, arg.name))
     code = """
-  void Init(%(typed_args)s, uint32_t _data_size) {
+  void Init(%s, uint32_t _data_size) {
     SetHeader(_data_size);
-%(set_code)s
-    memcpy(ImmediateDataAddress(this), _%(last_arg)s, _data_size);
+"""
+    f.write(code % func.MakeTypedArgString("_"))
+    for arg in args:
+      arg.WriteSetCode(f, 4, "_%s" % arg.name)
+    code = """
+    memcpy(ImmediateDataAddress(this), _%s, _data_size);
   }
 
 """
-    f.write(code % {
-          "typed_args": func.MakeTypedArgString("_"),
-          "set_code": "\n".join(set_code),
-          "last_arg": last_arg.name
-        })
+    f.write(code % last_arg.name)
 
   def WriteImmediateCmdSet(self, func, f):
     """Overrriden from TypeHandler."""
@@ -3719,8 +3716,8 @@
     for value, arg in enumerate(all_but_last_arg):
       init_code.append("      static_cast<%s>(%d)," % (arg.type, value + 11))
     for value, arg in enumerate(all_but_last_arg):
-      check_code.append("  EXPECT_EQ(static_cast<%s>(%d), cmd.%s);" %
-                        (arg.type, value + 11, arg.name))
+      check_code.append("  EXPECT_EQ(static_cast<%s>(%d), %s);" %
+                        (arg.type, value + 11, arg.GetArgAccessor('cmd')))
     code = """
 TEST_F(%(prefix)sFormatTest, %(func_name)s) {
   cmds::%(func_name)s& cmd = *GetBufferAs<cmds::%(func_name)s>();
@@ -6209,7 +6206,7 @@
     self.generated_cpp_filenames.append(filename)
 
   def WriteServiceImplementation(self, filename):
-    """Writes the service decorder implementation."""
+    """Writes the service decoder implementation."""
     comment = "// It is included by %s_cmd_decoder.cc\n" % _lower_prefix
     with CHeaderWriter(filename, self.year, comment) as f:
       for func in self.functions:
@@ -6250,7 +6247,7 @@
     self.generated_cpp_filenames.append(filename)
 
   def WritePassthroughServiceImplementation(self, filename):
-    """Writes the passthrough service decorder implementation."""
+    """Writes the passthrough service decoder implementation."""
     with CWriter(filename, self.year) as f:
       header = """
 #include \"gpu/command_buffer/service/gles2_cmd_decoder_passthrough.h\"
@@ -6273,7 +6270,7 @@
     self.generated_cpp_filenames.append(filename)
 
   def WriteServiceUnitTests(self, filename_pattern):
-    """Writes the service decorder unit tests."""
+    """Writes the service decoder unit tests."""
     num_tests = len(self.functions)
     FUNCTIONS_PER_FILE = 98  # hard code this so it doesn't change.
     count = 0
@@ -6410,7 +6407,7 @@
     self.generated_cpp_filenames.append(filename)
 
   def WriteServiceUnitTestsForExtensions(self, filename):
-    """Writes the service decorder unit tests for functions with extension_flag.
+    """Writes the service decoder unit tests for functions with extension_flag.
 
        The functions are special in that they need a specific unit test
        baseclass to turn on the extension.
diff --git a/gpu/command_buffer/build_raster_cmd_buffer.py b/gpu/command_buffer/build_raster_cmd_buffer.py
index 9f0b9cd..1ac120a 100755
--- a/gpu/command_buffer/build_raster_cmd_buffer.py
+++ b/gpu/command_buffer/build_raster_cmd_buffer.py
@@ -21,11 +21,8 @@
 # named types are used in 'raster_cmd_buffer_functions.txt'.
 # type: The actual GL type of the named type.
 # valid: The list of values that are valid for both the client and the service.
-# valid_es3: The list of values that are valid in OpenGL ES 3, but not ES 2.
 # invalid: Examples of invalid values for the type. At least these values
 #          should be tested to be invalid.
-# deprecated_es3: The list of values that are valid in OpenGL ES 2, but
-#                 deprecated in ES 3.
 # is_complete: The list of valid values of type are final and will not be
 #              modified during runtime.
 # validator: If set to False will prevent creation of a ValueValidator. Values
@@ -180,6 +177,14 @@
     'type': 'NoCommand',
     'trace_level': 2,
   },
+  'CreateAndConsumeTextureINTERNAL': {
+    'decoder_func': 'DoCreateAndConsumeTextureINTERNAL',
+    'internal': True,
+    'type': 'PUT',
+    'count': 16,  # GL_MAILBOX_SIZE_CHROMIUM
+    'unit_test': False,
+    'trace_level': 2,
+  },
   'CreateImageCHROMIUM': {
     'type': 'NoCommand',
     'cmd_args':
@@ -259,7 +264,6 @@
                 'GLuint64 timeout',
     'impl_func': False,
     'client_test': False,
-    'es3': True,
     'trace_level': 1,
   },
   'CompressedCopyTextureCHROMIUM': {
@@ -272,7 +276,6 @@
     'resource_type': 'Query',
     'resource_types': 'Queries',
     'unit_test': False,
-    'pepper_interface': 'Query',
     'not_shared': 'True',
   },
   'DeleteQueriesEXT': {
@@ -281,7 +284,6 @@
     'resource_type': 'Query',
     'resource_types': 'Queries',
     'unit_test': False,
-    'pepper_interface': 'Query',
   },
   'BeginQueryEXT': {
     'type': 'Custom',
@@ -289,7 +291,6 @@
     'cmd_args': 'GLenumQueryTarget target, GLidQuery id, void* sync_data',
     'data_transfer_methods': ['shm'],
     'gl_test_func': 'glBeginQuery',
-    'pepper_interface': 'Query',
   },
   'EndQueryEXT': {
     'type': 'Custom',
@@ -297,12 +298,10 @@
     'cmd_args': 'GLenumQueryTarget target, GLuint submit_count',
     'gl_test_func': 'glEndnQuery',
     'client_test': False,
-    'pepper_interface': 'Query',
   },
   'GetQueryObjectuivEXT': {
     'type': 'NoCommand',
     'gl_test_func': 'glGetQueryObjectuiv',
-    'pepper_interface': 'Query',
   },
   'BindTexImage2DCHROMIUM': {
     'decoder_func': 'DoBindTexImage2DCHROMIUM',
diff --git a/gpu/command_buffer/client/raster_cmd_helper_autogen.h b/gpu/command_buffer/client/raster_cmd_helper_autogen.h
index b2156981..1780e6c6 100644
--- a/gpu/command_buffer/client/raster_cmd_helper_autogen.h
+++ b/gpu/command_buffer/client/raster_cmd_helper_autogen.h
@@ -254,6 +254,21 @@
   }
 }
 
+void CreateAndConsumeTextureINTERNALImmediate(GLuint texture_id,
+                                              bool use_buffer,
+                                              gfx::BufferUsage buffer_usage,
+                                              viz::ResourceFormat format,
+                                              const GLbyte* mailbox) {
+  const uint32_t size =
+      raster::cmds::CreateAndConsumeTextureINTERNALImmediate::ComputeSize();
+  raster::cmds::CreateAndConsumeTextureINTERNALImmediate* c =
+      GetImmediateCmdSpaceTotalSize<
+          raster::cmds::CreateAndConsumeTextureINTERNALImmediate>(size);
+  if (c) {
+    c->Init(texture_id, use_buffer, buffer_usage, format, mailbox);
+  }
+}
+
 void TexParameteri(GLuint texture_id, GLenum pname, GLint param) {
   raster::cmds::TexParameteri* c = GetCmdSpace<raster::cmds::TexParameteri>();
   if (c) {
diff --git a/gpu/command_buffer/client/raster_implementation.cc b/gpu/command_buffer/client/raster_implementation.cc
index ffe46a98..71b0000 100644
--- a/gpu/command_buffer/client/raster_implementation.cc
+++ b/gpu/command_buffer/client/raster_implementation.cc
@@ -922,14 +922,26 @@
                                                 const GLbyte* mailbox) {
   NOTIMPLEMENTED();
 }
+
 GLuint RasterImplementation::CreateAndConsumeTexture(
     bool use_buffer,
     gfx::BufferUsage buffer_usage,
     viz::ResourceFormat format,
     const GLbyte* mailbox) {
-  NOTIMPLEMENTED();
-  return texture_id_allocator_.AllocateID();
+  GPU_CLIENT_SINGLE_THREAD_CHECK();
+  GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCreateAndConsumeTexture("
+                     << use_buffer << ", "
+                     << static_cast<uint32_t>(buffer_usage) << ", "
+                     << static_cast<uint32_t>(format) << ", "
+                     << static_cast<const void*>(mailbox) << ")");
+  GLuint client_id = texture_id_allocator_.AllocateID();
+  helper_->CreateAndConsumeTextureINTERNALImmediate(
+      client_id, use_buffer, buffer_usage, format, mailbox);
+  GPU_CLIENT_LOG("returned " << client_id);
+  CheckGLError();
+  return client_id;
 }
+
 void RasterImplementation::BeginRasterCHROMIUM(
     GLuint texture_id,
     GLuint sk_color,
diff --git a/gpu/command_buffer/common/raster_cmd_format_autogen.h b/gpu/command_buffer/common/raster_cmd_format_autogen.h
index 46bd4a0..77363176 100644
--- a/gpu/command_buffer/common/raster_cmd_format_autogen.h
+++ b/gpu/command_buffer/common/raster_cmd_format_autogen.h
@@ -1181,6 +1181,75 @@
 static_assert(offsetof(ProduceTextureDirectImmediate, texture) == 4,
               "offset of ProduceTextureDirectImmediate texture should be 4");
 
+struct CreateAndConsumeTextureINTERNALImmediate {
+  typedef CreateAndConsumeTextureINTERNALImmediate ValueType;
+  static const CommandId kCmdId = kCreateAndConsumeTextureINTERNALImmediate;
+  static const cmd::ArgFlags kArgFlags = cmd::kAtLeastN;
+  static const uint8_t cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(2);
+
+  static uint32_t ComputeDataSize() {
+    return static_cast<uint32_t>(sizeof(GLbyte) * 16);
+  }
+
+  static uint32_t ComputeSize() {
+    return static_cast<uint32_t>(sizeof(ValueType) + ComputeDataSize());
+  }
+
+  void SetHeader() { header.SetCmdByTotalSize<ValueType>(ComputeSize()); }
+
+  void Init(GLuint _texture_id,
+            bool _use_buffer,
+            gfx::BufferUsage _buffer_usage,
+            viz::ResourceFormat _format,
+            const GLbyte* _mailbox) {
+    SetHeader();
+    texture_id = _texture_id;
+    use_buffer = _use_buffer;
+    buffer_usage = static_cast<uint32_t>(_buffer_usage);
+    format = static_cast<uint32_t>(_format);
+    memcpy(ImmediateDataAddress(this), _mailbox, ComputeDataSize());
+  }
+
+  void* Set(void* cmd,
+            GLuint _texture_id,
+            bool _use_buffer,
+            gfx::BufferUsage _buffer_usage,
+            viz::ResourceFormat _format,
+            const GLbyte* _mailbox) {
+    static_cast<ValueType*>(cmd)->Init(_texture_id, _use_buffer, _buffer_usage,
+                                       _format, _mailbox);
+    const uint32_t size = ComputeSize();
+    return NextImmediateCmdAddressTotalSize<ValueType>(cmd, size);
+  }
+
+  gpu::CommandHeader header;
+  uint32_t texture_id;
+  uint32_t use_buffer;
+  uint32_t buffer_usage;
+  uint32_t format;
+};
+
+static_assert(sizeof(CreateAndConsumeTextureINTERNALImmediate) == 20,
+              "size of CreateAndConsumeTextureINTERNALImmediate should be 20");
+static_assert(
+    offsetof(CreateAndConsumeTextureINTERNALImmediate, header) == 0,
+    "offset of CreateAndConsumeTextureINTERNALImmediate header should be 0");
+static_assert(offsetof(CreateAndConsumeTextureINTERNALImmediate, texture_id) ==
+                  4,
+              "offset of CreateAndConsumeTextureINTERNALImmediate texture_id "
+              "should be 4");
+static_assert(offsetof(CreateAndConsumeTextureINTERNALImmediate, use_buffer) ==
+                  8,
+              "offset of CreateAndConsumeTextureINTERNALImmediate use_buffer "
+              "should be 8");
+static_assert(offsetof(CreateAndConsumeTextureINTERNALImmediate,
+                       buffer_usage) == 12,
+              "offset of CreateAndConsumeTextureINTERNALImmediate buffer_usage "
+              "should be 12");
+static_assert(
+    offsetof(CreateAndConsumeTextureINTERNALImmediate, format) == 16,
+    "offset of CreateAndConsumeTextureINTERNALImmediate format should be 16");
+
 struct TexParameteri {
   typedef TexParameteri ValueType;
   static const CommandId kCmdId = kTexParameteri;
diff --git a/gpu/command_buffer/common/raster_cmd_format_test_autogen.h b/gpu/command_buffer/common/raster_cmd_format_test_autogen.h
index 12445a2..dee15e96 100644
--- a/gpu/command_buffer/common/raster_cmd_format_test_autogen.h
+++ b/gpu/command_buffer/common/raster_cmd_format_test_autogen.h
@@ -401,6 +401,46 @@
       next_cmd, sizeof(cmd) + RoundSizeToMultipleOfEntries(sizeof(data)));
 }
 
+TEST_F(RasterFormatTest, CreateAndConsumeTextureINTERNALImmediate) {
+  const int kSomeBaseValueToTestWith = 51;
+  static GLbyte data[] = {
+      static_cast<GLbyte>(kSomeBaseValueToTestWith + 0),
+      static_cast<GLbyte>(kSomeBaseValueToTestWith + 1),
+      static_cast<GLbyte>(kSomeBaseValueToTestWith + 2),
+      static_cast<GLbyte>(kSomeBaseValueToTestWith + 3),
+      static_cast<GLbyte>(kSomeBaseValueToTestWith + 4),
+      static_cast<GLbyte>(kSomeBaseValueToTestWith + 5),
+      static_cast<GLbyte>(kSomeBaseValueToTestWith + 6),
+      static_cast<GLbyte>(kSomeBaseValueToTestWith + 7),
+      static_cast<GLbyte>(kSomeBaseValueToTestWith + 8),
+      static_cast<GLbyte>(kSomeBaseValueToTestWith + 9),
+      static_cast<GLbyte>(kSomeBaseValueToTestWith + 10),
+      static_cast<GLbyte>(kSomeBaseValueToTestWith + 11),
+      static_cast<GLbyte>(kSomeBaseValueToTestWith + 12),
+      static_cast<GLbyte>(kSomeBaseValueToTestWith + 13),
+      static_cast<GLbyte>(kSomeBaseValueToTestWith + 14),
+      static_cast<GLbyte>(kSomeBaseValueToTestWith + 15),
+  };
+  cmds::CreateAndConsumeTextureINTERNALImmediate& cmd =
+      *GetBufferAs<cmds::CreateAndConsumeTextureINTERNALImmediate>();
+  void* next_cmd = cmd.Set(&cmd, static_cast<GLuint>(11), static_cast<bool>(12),
+                           static_cast<gfx::BufferUsage>(13),
+                           static_cast<viz::ResourceFormat>(14), data);
+  EXPECT_EQ(static_cast<uint32_t>(
+                cmds::CreateAndConsumeTextureINTERNALImmediate::kCmdId),
+            cmd.header.command);
+  EXPECT_EQ(sizeof(cmd) + RoundSizeToMultipleOfEntries(sizeof(data)),
+            cmd.header.size * 4u);
+  EXPECT_EQ(static_cast<GLuint>(11), cmd.texture_id);
+  EXPECT_EQ(static_cast<bool>(12), static_cast<bool>(cmd.use_buffer));
+  EXPECT_EQ(static_cast<gfx::BufferUsage>(13),
+            static_cast<gfx::BufferUsage>(cmd.buffer_usage));
+  EXPECT_EQ(static_cast<viz::ResourceFormat>(14),
+            static_cast<viz::ResourceFormat>(cmd.format));
+  CheckBytesWrittenMatchesExpectedSize(
+      next_cmd, sizeof(cmd) + RoundSizeToMultipleOfEntries(sizeof(data)));
+}
+
 TEST_F(RasterFormatTest, TexParameteri) {
   cmds::TexParameteri& cmd = *GetBufferAs<cmds::TexParameteri>();
   void* next_cmd = cmd.Set(&cmd, static_cast<GLuint>(11),
diff --git a/gpu/command_buffer/common/raster_cmd_ids_autogen.h b/gpu/command_buffer/common/raster_cmd_ids_autogen.h
index 9dfd8fd..ea5a391 100644
--- a/gpu/command_buffer/common/raster_cmd_ids_autogen.h
+++ b/gpu/command_buffer/common/raster_cmd_ids_autogen.h
@@ -11,38 +11,39 @@
 #ifndef GPU_COMMAND_BUFFER_COMMON_RASTER_CMD_IDS_AUTOGEN_H_
 #define GPU_COMMAND_BUFFER_COMMON_RASTER_CMD_IDS_AUTOGEN_H_
 
-#define RASTER_COMMAND_LIST(OP)                      \
-  OP(DeleteTexturesImmediate)              /* 256 */ \
-  OP(Finish)                               /* 257 */ \
-  OP(Flush)                                /* 258 */ \
-  OP(GetError)                             /* 259 */ \
-  OP(GetIntegerv)                          /* 260 */ \
-  OP(GenQueriesEXTImmediate)               /* 261 */ \
-  OP(DeleteQueriesEXTImmediate)            /* 262 */ \
-  OP(BeginQueryEXT)                        /* 263 */ \
-  OP(EndQueryEXT)                          /* 264 */ \
-  OP(CompressedCopyTextureCHROMIUM)        /* 265 */ \
-  OP(LoseContextCHROMIUM)                  /* 266 */ \
-  OP(InsertFenceSyncCHROMIUM)              /* 267 */ \
-  OP(WaitSyncTokenCHROMIUM)                /* 268 */ \
-  OP(UnpremultiplyAndDitherCopyCHROMIUM)   /* 269 */ \
-  OP(InitializeDiscardableTextureCHROMIUM) /* 270 */ \
-  OP(UnlockDiscardableTextureCHROMIUM)     /* 271 */ \
-  OP(LockDiscardableTextureCHROMIUM)       /* 272 */ \
-  OP(BeginRasterCHROMIUM)                  /* 273 */ \
-  OP(RasterCHROMIUM)                       /* 274 */ \
-  OP(EndRasterCHROMIUM)                    /* 275 */ \
-  OP(CreateTransferCacheEntryINTERNAL)     /* 276 */ \
-  OP(DeleteTransferCacheEntryINTERNAL)     /* 277 */ \
-  OP(UnlockTransferCacheEntryINTERNAL)     /* 278 */ \
-  OP(CreateTexture)                        /* 279 */ \
-  OP(SetColorSpaceMetadata)                /* 280 */ \
-  OP(ProduceTextureDirectImmediate)        /* 281 */ \
-  OP(TexParameteri)                        /* 282 */ \
-  OP(BindTexImage2DCHROMIUM)               /* 283 */ \
-  OP(ReleaseTexImage2DCHROMIUM)            /* 284 */ \
-  OP(TexStorage2D)                         /* 285 */ \
-  OP(CopySubTexture)                       /* 286 */
+#define RASTER_COMMAND_LIST(OP)                          \
+  OP(DeleteTexturesImmediate)                  /* 256 */ \
+  OP(Finish)                                   /* 257 */ \
+  OP(Flush)                                    /* 258 */ \
+  OP(GetError)                                 /* 259 */ \
+  OP(GetIntegerv)                              /* 260 */ \
+  OP(GenQueriesEXTImmediate)                   /* 261 */ \
+  OP(DeleteQueriesEXTImmediate)                /* 262 */ \
+  OP(BeginQueryEXT)                            /* 263 */ \
+  OP(EndQueryEXT)                              /* 264 */ \
+  OP(CompressedCopyTextureCHROMIUM)            /* 265 */ \
+  OP(LoseContextCHROMIUM)                      /* 266 */ \
+  OP(InsertFenceSyncCHROMIUM)                  /* 267 */ \
+  OP(WaitSyncTokenCHROMIUM)                    /* 268 */ \
+  OP(UnpremultiplyAndDitherCopyCHROMIUM)       /* 269 */ \
+  OP(InitializeDiscardableTextureCHROMIUM)     /* 270 */ \
+  OP(UnlockDiscardableTextureCHROMIUM)         /* 271 */ \
+  OP(LockDiscardableTextureCHROMIUM)           /* 272 */ \
+  OP(BeginRasterCHROMIUM)                      /* 273 */ \
+  OP(RasterCHROMIUM)                           /* 274 */ \
+  OP(EndRasterCHROMIUM)                        /* 275 */ \
+  OP(CreateTransferCacheEntryINTERNAL)         /* 276 */ \
+  OP(DeleteTransferCacheEntryINTERNAL)         /* 277 */ \
+  OP(UnlockTransferCacheEntryINTERNAL)         /* 278 */ \
+  OP(CreateTexture)                            /* 279 */ \
+  OP(SetColorSpaceMetadata)                    /* 280 */ \
+  OP(ProduceTextureDirectImmediate)            /* 281 */ \
+  OP(CreateAndConsumeTextureINTERNALImmediate) /* 282 */ \
+  OP(TexParameteri)                            /* 283 */ \
+  OP(BindTexImage2DCHROMIUM)                   /* 284 */ \
+  OP(ReleaseTexImage2DCHROMIUM)                /* 285 */ \
+  OP(TexStorage2D)                             /* 286 */ \
+  OP(CopySubTexture)                           /* 287 */
 
 enum CommandId {
   kOneBeforeStartPoint =
diff --git a/gpu/command_buffer/raster_cmd_buffer_functions.txt b/gpu/command_buffer/raster_cmd_buffer_functions.txt
index 24b9bd1..5bccf7a 100644
--- a/gpu/command_buffer/raster_cmd_buffer_functions.txt
+++ b/gpu/command_buffer/raster_cmd_buffer_functions.txt
@@ -51,6 +51,7 @@
 GL_APICALL void         GL_APIENTRY glGenMailbox (GLbyte* mailbox);
 GL_APICALL void         GL_APIENTRY glProduceTextureDirect (GLuint texture, const GLbyte* mailbox);
 GL_APICALL GLuint       GL_APIENTRY glCreateAndConsumeTexture (bool use_buffer, EnumClassgfx::BufferUsage buffer_usage, EnumClassviz::ResourceFormat format, const GLbyte* mailbox);
+GL_APICALL GLuint       GL_APIENTRY glCreateAndConsumeTextureINTERNAL (GLuint texture_id, bool use_buffer, EnumClassgfx::BufferUsage buffer_usage, EnumClassviz::ResourceFormat format, const GLbyte* mailbox);
 GL_APICALL void         GL_APIENTRY glTexParameteri (GLuint texture_id, GLenumTextureParameter pname, GLint param);
 GL_APICALL void         GL_APIENTRY glBindTexImage2DCHROMIUM (GLuint texture_id, GLint image_id);
 GL_APICALL void         GL_APIENTRY glReleaseTexImage2DCHROMIUM (GLuint texture_id, GLint image_id);
diff --git a/gpu/command_buffer/service/DEPS b/gpu/command_buffer/service/DEPS
index 831a3d24..0e3904d8 100644
--- a/gpu/command_buffer/service/DEPS
+++ b/gpu/command_buffer/service/DEPS
@@ -2,4 +2,6 @@
   "+cc/paint",
   "+media/media_features.h",
   "+third_party/skia",
+  "+components/viz/common/resources/resource_format.h",
+  "+components/viz/common/resources/resource_format_utils.h",
 ]
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc
index 0ae7c08..0f77855 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -1105,7 +1105,6 @@
                          TextureRef* texture_ref,
                          const volatile GLbyte* data);
 
-  void EnsureTextureForClientId(GLenum target, GLuint client_id);
   void DoCreateAndConsumeTextureINTERNAL(GLuint client_id,
                                          const volatile GLbyte* key);
   void DoApplyScreenSpaceAntialiasingCHROMIUM();
@@ -18289,21 +18288,6 @@
   group_->mailbox_manager()->ProduceTexture(mailbox, produced);
 }
 
-void GLES2DecoderImpl::EnsureTextureForClientId(
-    GLenum target,
-    GLuint client_id) {
-  TextureRef* texture_ref = GetTexture(client_id);
-  if (!texture_ref) {
-    GLuint service_id;
-    api()->glGenTexturesFn(1, &service_id);
-    DCHECK_NE(0u, service_id);
-    texture_ref = CreateTexture(client_id, service_id);
-    texture_manager()->SetTarget(texture_ref, target);
-    api()->glBindTextureFn(target, service_id);
-    RestoreCurrentTextureBindings(&state_, target, state_.active_texture_unit);
-  }
-}
-
 void GLES2DecoderImpl::DoCreateAndConsumeTextureINTERNAL(
     GLuint client_id,
     const volatile GLbyte* data) {
@@ -18324,8 +18308,8 @@
 
   TextureRef* texture_ref = GetTexture(client_id);
   if (texture_ref) {
-    // No need to call EnsureTextureForClientId here, the client_id already has
-    // an associated texture.
+    // No need to create texture here, the client_id already has an associated
+    // texture.
     LOCAL_SET_GL_ERROR(
         GL_INVALID_OPERATION,
         "glCreateAndConsumeTextureCHROMIUM", "client id already in use");
@@ -18334,6 +18318,7 @@
   Texture* texture =
       static_cast<Texture*>(group_->mailbox_manager()->ConsumeTexture(mailbox));
   if (!texture) {
+    // Create texture to handle invalid mailbox (see http://crbug.com/472465).
     bool result = GenTexturesHelper(1, &client_id);
     DCHECK(result);
     LOCAL_SET_GL_ERROR(
diff --git a/gpu/command_buffer/service/raster_decoder.cc b/gpu/command_buffer/service/raster_decoder.cc
index e84cc6ac..c4eb47c 100644
--- a/gpu/command_buffer/service/raster_decoder.cc
+++ b/gpu/command_buffer/service/raster_decoder.cc
@@ -12,11 +12,14 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
 #include "base/trace_event/trace_event.h"
+#include "components/viz/common/resources/resource_format_utils.h"
 #include "gpu/command_buffer/common/capabilities.h"
 #include "gpu/command_buffer/common/command_buffer_id.h"
 #include "gpu/command_buffer/common/constants.h"
 #include "gpu/command_buffer/common/context_result.h"
 #include "gpu/command_buffer/common/debug_marker_manager.h"
+#include "gpu/command_buffer/common/gpu_memory_buffer_support.h"
+#include "gpu/command_buffer/common/mailbox.h"
 #include "gpu/command_buffer/common/raster_cmd_format.h"
 #include "gpu/command_buffer/common/raster_cmd_ids.h"
 #include "gpu/command_buffer/common/sync_token.h"
@@ -26,6 +29,7 @@
 #include "gpu/command_buffer/service/error_state.h"
 #include "gpu/command_buffer/service/feature_info.h"
 #include "gpu/command_buffer/service/logger.h"
+#include "gpu/command_buffer/service/mailbox_manager.h"
 #include "gpu/command_buffer/service/query_manager.h"
 #include "gpu/command_buffer/service/raster_cmd_validation.h"
 #include "ui/gl/gl_context.h"
@@ -54,6 +58,46 @@
 namespace gpu {
 namespace raster {
 
+namespace {
+
+class TextureMetadata {
+ public:
+  TextureMetadata(bool use_buffer,
+                  gfx::BufferUsage buffer_usage,
+                  viz::ResourceFormat format,
+                  const Capabilities& caps)
+      : use_buffer_(use_buffer),
+        buffer_usage_(buffer_usage),
+        format_(format),
+        target_(CalcTarget(use_buffer, buffer_usage, format, caps)) {}
+  TextureMetadata(const TextureMetadata& tmd) = default;
+
+  bool use_buffer() const { return use_buffer_; }
+  gfx::BufferUsage buffer_usage() const { return buffer_usage_; }
+  viz::ResourceFormat format() const { return format_; }
+  GLenum target() const { return target_; }
+
+ private:
+  static GLenum CalcTarget(bool use_buffer,
+                           gfx::BufferUsage buffer_usage,
+                           viz::ResourceFormat format,
+                           const gpu::Capabilities& caps) {
+    if (use_buffer) {
+      gfx::BufferFormat buffer_format = viz::BufferFormat(format);
+      return GetBufferTextureTarget(buffer_usage, buffer_format, caps);
+    } else {
+      return GL_TEXTURE_2D;
+    }
+  }
+
+  const bool use_buffer_;
+  const gfx::BufferUsage buffer_usage_;
+  const viz::ResourceFormat format_;
+  const GLenum target_;
+};
+
+}  // namespace
+
 class RasterDecoderImpl : public RasterDecoder, public gles2::ErrorStateClient {
  public:
   RasterDecoderImpl(DecoderClient* client,
@@ -137,6 +181,13 @@
   void SetIgnoreCachedStateForTest(bool ignore) override;
 
  private:
+  std::unordered_map<GLuint, TextureMetadata> texture_metadata_;
+  TextureMetadata* GetTextureMetadata(GLuint client_id) {
+    auto it = texture_metadata_.find(client_id);
+    DCHECK(it != texture_metadata_.end()) << "Undefined texture id";
+    return &it->second;
+  }
+
   gl::GLApi* api() const { return state_.api(); }
 
   const FeatureInfo::FeatureFlags& features() const {
@@ -167,6 +218,11 @@
   // Deletes the texture info for the given texture.
   void RemoveTexture(GLuint client_id) {
     texture_manager()->RemoveTexture(client_id);
+
+    auto texture_iter = texture_metadata_.find(client_id);
+    DCHECK(texture_iter != texture_metadata_.end());
+
+    texture_metadata_.erase(texture_iter);
   }
 
   void UnbindTexture(TextureRef* texture_ref) {
@@ -193,24 +249,18 @@
   bool GetNumValuesReturnedForGLGet(GLenum pname, GLsizei* num_values);
 
   GLuint DoCreateTexture(bool use_buffer,
-                         gfx::BufferUsage buffer_usage,
-                         viz::ResourceFormat resource_format) {
-    // Stubbed out enough for unittests. Need to take params into account.
-    NOTIMPLEMENTED();
-    GLuint service_id;
-    api()->glGenTexturesFn(1, &service_id);
-    return service_id;
-  }
+                         gfx::BufferUsage /* buffer_usage */,
+                         viz::ResourceFormat /* resource_format */);
   void CreateTexture(GLuint client_id,
                      GLuint service_id,
                      bool use_buffer,
                      gfx::BufferUsage buffer_usage,
-                     viz::ResourceFormat resource_format) {
-    // Stubbed out enough for unittests. Need to take params into account.
-    NOTIMPLEMENTED();
-    CreateTexture(client_id, service_id);
-  }
-
+                     viz::ResourceFormat resource_format);
+  void DoCreateAndConsumeTextureINTERNAL(GLuint client_id,
+                                         bool use_buffer,
+                                         gfx::BufferUsage buffer_usage,
+                                         viz::ResourceFormat resource_format,
+                                         const volatile GLbyte* key);
   void DeleteTexturesHelper(GLsizei n, const volatile GLuint* client_ids);
   bool GenQueriesEXTHelper(GLsizei n, const GLuint* client_ids);
   void DeleteQueriesEXTHelper(GLsizei n, const volatile GLuint* client_ids);
@@ -221,9 +271,7 @@
   void DoBindTexImage2DCHROMIUM(GLuint texture_id, GLint image_id) {
     NOTIMPLEMENTED();
   }
-  void DoProduceTextureDirect(GLuint texture, const volatile GLbyte* mailbox) {
-    NOTIMPLEMENTED();
-  }
+  void DoProduceTextureDirect(GLuint texture, const volatile GLbyte* key);
   void DoReleaseTexImage2DCHROMIUM(GLuint texture_id, GLint image_id) {
     NOTIMPLEMENTED();
   }
@@ -563,6 +611,9 @@
   caps.supports_oop_raster = true;
   caps.texture_target_exception_list =
       group_->gpu_preferences().texture_target_exception_list;
+  caps.texture_format_bgra8888 =
+      feature_info_->feature_flags().ext_texture_format_bgra8888;
+
   return caps;
 }
 
@@ -640,22 +691,17 @@
 }
 
 bool RasterDecoderImpl::HasMoreIdleWork() const {
-  NOTIMPLEMENTED();
   return false;
 }
 
 void RasterDecoderImpl::PerformIdleWork() {
-  NOTIMPLEMENTED();
 }
 
 bool RasterDecoderImpl::HasPollingWork() const {
-  NOTIMPLEMENTED();
   return false;
 }
 
-void RasterDecoderImpl::PerformPollingWork() {
-  NOTIMPLEMENTED();
-}
+void RasterDecoderImpl::PerformPollingWork() {}
 
 TextureBase* RasterDecoderImpl::GetTextureBase(uint32_t client_id) {
   NOTIMPLEMENTED();
@@ -701,13 +747,10 @@
 }
 
 void RasterDecoderImpl::BeginDecoding() {
-  // TODO(backer): Add support the tracing commands.
   gpu_debug_commands_ = log_commands() || debug();
 }
 
-void RasterDecoderImpl::EndDecoding() {
-  NOTIMPLEMENTED();
-}
+void RasterDecoderImpl::EndDecoding() {}
 
 const char* RasterDecoderImpl::GetCommandName(unsigned int command_id) const {
   if (command_id >= kFirstRasterCommand && command_id < kNumCommands) {
@@ -1018,7 +1061,15 @@
 error::Error RasterDecoderImpl::HandleInsertFenceSyncCHROMIUM(
     uint32_t immediate_data_size,
     const volatile void* cmd_data) {
-  NOTIMPLEMENTED();
+  const volatile gles2::cmds::InsertFenceSyncCHROMIUM& c =
+      *static_cast<const volatile gles2::cmds::InsertFenceSyncCHROMIUM*>(
+          cmd_data);
+
+  const uint64_t release_count = c.release_count();
+  client_->OnFenceSyncRelease(release_count);
+  // Exit inner command processing loop so that we check the scheduling state
+  // and yield if necessary as we may have unblocked a higher priority context.
+  ExitCommandProcessingEarly();
   return error::kNoError;
 }
 
@@ -1045,6 +1096,83 @@
   NOTREACHED() << "Unhandled enum " << pname;
 }
 
+GLuint RasterDecoderImpl::DoCreateTexture(
+    bool use_buffer,
+    gfx::BufferUsage /* buffer_usage */,
+    viz::ResourceFormat /* resource_format */) {
+  GLuint service_id = 0;
+  api()->glGenTexturesFn(1, &service_id);
+  DCHECK(service_id);
+  return service_id;
+}
+
+void RasterDecoderImpl::CreateTexture(GLuint client_id,
+                                      GLuint service_id,
+                                      bool use_buffer,
+                                      gfx::BufferUsage buffer_usage,
+                                      viz::ResourceFormat resource_format) {
+  texture_metadata_.emplace(std::make_pair(
+      client_id, TextureMetadata(use_buffer, buffer_usage, resource_format,
+                                 GetCapabilities())));
+  texture_manager()->CreateTexture(client_id, service_id);
+}
+
+void RasterDecoderImpl::DoCreateAndConsumeTextureINTERNAL(
+    GLuint client_id,
+    bool use_buffer,
+    gfx::BufferUsage buffer_usage,
+    viz::ResourceFormat resource_format,
+    const volatile GLbyte* key) {
+  TRACE_EVENT2("gpu", "RasterDecoderImpl::DoCreateAndConsumeTextureINTERNAL",
+               "context", logger_.GetLogPrefix(), "key[0]",
+               static_cast<unsigned char>(key[0]));
+  Mailbox mailbox =
+      Mailbox::FromVolatile(*reinterpret_cast<const volatile Mailbox*>(key));
+  DLOG_IF(ERROR, !mailbox.Verify()) << "CreateAndConsumeTexture was "
+                                       "passed a mailbox that was not "
+                                       "generated by GenMailboxCHROMIUM.";
+  if (!client_id) {
+    LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION,
+                       "glCreateAndConsumeTextureCHROMIUM",
+                       "invalid client id");
+    return;
+  }
+
+  TextureRef* texture_ref = GetTexture(client_id);
+  if (texture_ref) {
+    // No need to create texture here, the client_id already has an associated
+    // texture.
+    LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION,
+                       "glCreateAndConsumeTextureCHROMIUM",
+                       "client id already in use");
+    return;
+  }
+
+  texture_metadata_.emplace(std::make_pair(
+      client_id, TextureMetadata(use_buffer, buffer_usage, resource_format,
+                                 GetCapabilities())));
+
+  Texture* texture =
+      static_cast<Texture*>(group_->mailbox_manager()->ConsumeTexture(mailbox));
+  if (!texture) {
+    // Create texture to handle invalid mailbox (see http://crbug.com/472465).
+    GLuint service_id = 0;
+    api()->glGenTexturesFn(1, &service_id);
+    DCHECK(service_id);
+    texture_manager()->CreateTexture(client_id, service_id);
+
+    LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION,
+                       "glCreateAndConsumeTextureCHROMIUM",
+                       "invalid mailbox name");
+    return;
+  }
+
+  texture_ref = texture_manager()->Consume(client_id, texture);
+
+  // TODO(backer): Validate that the consumed texture is consistent with
+  // TextureMetadata.
+}
+
 void RasterDecoderImpl::DeleteTexturesHelper(
     GLsizei n,
     const volatile GLuint* client_ids) {
@@ -1118,6 +1246,44 @@
                                    pname, param);
 }
 
+void RasterDecoderImpl::DoProduceTextureDirect(GLuint client_id,
+                                               const volatile GLbyte* key) {
+  TRACE_EVENT2("gpu", "RasterDecoderImpl::DoProduceTextureDirect", "context",
+               logger_.GetLogPrefix(), "key[0]",
+               static_cast<unsigned char>(key[0]));
+
+  Mailbox mailbox =
+      Mailbox::FromVolatile(*reinterpret_cast<const volatile Mailbox*>(key));
+  DLOG_IF(ERROR, !mailbox.Verify()) << "ProduceTextureDirect was passed a "
+                                       "mailbox that was not generated by "
+                                       "GenMailboxCHROMIUM.";
+
+  TextureRef* texture_ref = GetTexture(client_id);
+
+  bool clear = !client_id;
+  if (clear) {
+    DCHECK(!texture_ref);
+
+    group_->mailbox_manager()->ProduceTexture(mailbox, nullptr);
+    return;
+  }
+
+  if (!texture_ref) {
+    LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, "ProduceTextureDirect",
+                       "unknown texture");
+    return;
+  }
+
+  Texture* produced = texture_manager()->Produce(texture_ref);
+  if (!produced) {
+    LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, "ProduceTextureDirect",
+                       "invalid texture");
+    return;
+  }
+
+  group_->mailbox_manager()->ProduceTexture(mailbox, produced);
+}
+
 // Include the auto-generated part of this file. We split this because it means
 // we can easily edit the non-auto generated parts right here in this file
 // instead of having to edit some template or the code generator.
diff --git a/gpu/command_buffer/service/raster_decoder_autogen.h b/gpu/command_buffer/service/raster_decoder_autogen.h
index 2dbfe30..fccd84b 100644
--- a/gpu/command_buffer/service/raster_decoder_autogen.h
+++ b/gpu/command_buffer/service/raster_decoder_autogen.h
@@ -339,6 +339,43 @@
   return error::kNoError;
 }
 
+error::Error RasterDecoderImpl::HandleCreateAndConsumeTextureINTERNALImmediate(
+    uint32_t immediate_data_size,
+    const volatile void* cmd_data) {
+  const volatile raster::cmds::CreateAndConsumeTextureINTERNALImmediate& c =
+      *static_cast<const volatile raster::cmds::
+                       CreateAndConsumeTextureINTERNALImmediate*>(cmd_data);
+  GLuint texture_id = static_cast<GLuint>(c.texture_id);
+  bool use_buffer = static_cast<bool>(c.use_buffer);
+  gfx::BufferUsage buffer_usage = static_cast<gfx::BufferUsage>(c.buffer_usage);
+  viz::ResourceFormat format = static_cast<viz::ResourceFormat>(c.format);
+  uint32_t data_size;
+  if (!GLES2Util::ComputeDataSize<GLbyte, 16>(1, &data_size)) {
+    return error::kOutOfBounds;
+  }
+  if (data_size > immediate_data_size) {
+    return error::kOutOfBounds;
+  }
+  volatile const GLbyte* mailbox = GetImmediateDataAs<volatile const GLbyte*>(
+      c, data_size, immediate_data_size);
+  if (!validators_->gfx_buffer_usage.IsValid(buffer_usage)) {
+    LOCAL_SET_GL_ERROR_INVALID_ENUM("glCreateAndConsumeTextureINTERNAL",
+                                    buffer_usage, "buffer_usage");
+    return error::kNoError;
+  }
+  if (!validators_->viz_resource_format.IsValid(format)) {
+    LOCAL_SET_GL_ERROR_INVALID_ENUM("glCreateAndConsumeTextureINTERNAL", format,
+                                    "format");
+    return error::kNoError;
+  }
+  if (mailbox == NULL) {
+    return error::kOutOfBounds;
+  }
+  DoCreateAndConsumeTextureINTERNAL(texture_id, use_buffer, buffer_usage,
+                                    format, mailbox);
+  return error::kNoError;
+}
+
 error::Error RasterDecoderImpl::HandleTexParameteri(
     uint32_t immediate_data_size,
     const volatile void* cmd_data) {
diff --git a/gpu/command_buffer/service/raster_decoder_unittest.cc b/gpu/command_buffer/service/raster_decoder_unittest.cc
index eb25ceb..0268b21c 100644
--- a/gpu/command_buffer/service/raster_decoder_unittest.cc
+++ b/gpu/command_buffer/service/raster_decoder_unittest.cc
@@ -6,6 +6,7 @@
 
 #include "base/command_line.h"
 #include "gpu/command_buffer/common/gles2_cmd_utils.h"
+#include "gpu/command_buffer/common/mailbox.h"
 #include "gpu/command_buffer/common/raster_cmd_format.h"
 #include "gpu/command_buffer/service/context_group.h"
 #include "gpu/command_buffer/service/program_manager.h"
@@ -106,9 +107,9 @@
   EXPECT_EQ(GL_NO_ERROR, GetGLError());
 
   QueryManager* query_manager = decoder_->GetQueryManager();
-  ASSERT_TRUE(query_manager != NULL);
+  ASSERT_TRUE(query_manager != nullptr);
   QueryManager::Query* query = query_manager->GetQuery(kNewClientId);
-  ASSERT_TRUE(query != NULL);
+  ASSERT_TRUE(query != nullptr);
   EXPECT_FALSE(query->IsPending());
 
   EXPECT_CALL(*gl_, Flush()).RetiresOnSaturation();
@@ -172,9 +173,9 @@
   EXPECT_EQ(GL_NO_ERROR, GetGLError());
 
   QueryManager* query_manager = decoder_->GetQueryManager();
-  ASSERT_TRUE(query_manager != NULL);
+  ASSERT_TRUE(query_manager != nullptr);
   QueryManager::Query* query = query_manager->GetQuery(kNewClientId);
-  ASSERT_TRUE(query != NULL);
+  ASSERT_TRUE(query != nullptr);
   EXPECT_FALSE(query->IsPending());
 
   // Test end succeeds
@@ -185,5 +186,49 @@
   EXPECT_FALSE(query->IsPending());
 }
 
+TEST_P(RasterDecoderTest, ProduceAndConsumeTexture) {
+  Mailbox mailbox = Mailbox::Generate();
+  GLuint new_texture_id = kNewClientId;
+
+  // TODO(backer): Use TexStorage2D to set some attributes like width and
+  // height.
+
+  gles2::TextureRef* texture_ref =
+      group().texture_manager()->GetTexture(client_texture_id_);
+  ASSERT_TRUE(texture_ref != nullptr);
+  gles2::Texture* texture = texture_ref->texture();
+  EXPECT_EQ(kServiceTextureId, texture->service_id());
+
+  ProduceTextureDirectImmediate& produce_cmd =
+      *GetImmediateAs<ProduceTextureDirectImmediate>();
+  produce_cmd.Init(client_texture_id_, mailbox.name);
+  EXPECT_EQ(error::kNoError,
+            ExecuteImmediateCmd(produce_cmd, sizeof(mailbox.name)));
+  EXPECT_EQ(GL_NO_ERROR, GetGLError());
+
+  // TODO(backer): Check that ProduceTextureDirect did not change attributes
+  // like width and height.
+
+  // Service ID has not changed.
+  EXPECT_EQ(kServiceTextureId, texture->service_id());
+
+  CreateAndConsumeTextureINTERNALImmediate& consume_cmd =
+      *GetImmediateAs<CreateAndConsumeTextureINTERNALImmediate>();
+  consume_cmd.Init(new_texture_id, false /* use_buffer */,
+                   gfx::BufferUsage::GPU_READ, viz::ResourceFormat::RGBA_8888,
+                   mailbox.name);
+  EXPECT_EQ(error::kNoError,
+            ExecuteImmediateCmd(consume_cmd, sizeof(mailbox.name)));
+  EXPECT_EQ(GL_NO_ERROR, GetGLError());
+
+  // TODO(backer): Check that new_texture_id has appropriate attributes like
+  // width and height.
+
+  // Service ID is restored.
+  texture_ref = group().texture_manager()->GetTexture(new_texture_id);
+  ASSERT_NE(texture_ref, nullptr);
+  EXPECT_EQ(kServiceTextureId, texture_ref->service_id());
+}
+
 }  // namespace raster
 }  // namespace gpu
diff --git a/headless/test/headless_render_browsertest.cc b/headless/test/headless_render_browsertest.cc
index b75d25fbb..5b291f8 100644
--- a/headless/test/headless_render_browsertest.cc
+++ b/headless/test/headless_render_browsertest.cc
@@ -3,7 +3,6 @@
 // found in the LICENSE file.
 
 #include <functional>
-#include <strstream>
 
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
diff --git a/infra/config/global/cr-buildbucket.cfg b/infra/config/global/cr-buildbucket.cfg
index 961cded..9c7f8b1 100644
--- a/infra/config/global/cr-buildbucket.cfg
+++ b/infra/config/global/cr-buildbucket.cfg
@@ -121,24 +121,18 @@
 
 builder_mixins {
   name: "android-angle-try"
-  dimensions: "cores:8"
-  dimensions: "cpu:x86-64"
   dimensions: "os:Ubuntu-14.04"
   mixins: "angle-try"
 }
 
 builder_mixins {
   name: "android-gpu-fyi-ci"
-  dimensions: "cores:8"
-  dimensions: "cpu:x86-64"
   dimensions: "os:Ubuntu-14.04"
   mixins: "gpu-fyi-ci"
 }
 
 builder_mixins {
   name: "android-optional-gpu-try"
-  dimensions: "cores:8"
-  dimensions: "cpu:x86-64"
   dimensions: "os:Ubuntu-14.04"
   mixins: "gpu-optional-try"
   mixins: "android-try"
@@ -219,8 +213,6 @@
 
 builder_mixins {
   name: "linux-gpu-fyi-ci"
-  dimensions: "cpu:x86-64"
-  dimensions: "cores:8"
   mixins: "linux"
   mixins: "gpu-fyi-ci"
 }
@@ -234,6 +226,7 @@
   name: "mac-angle-try"
   mixins: "mac"
   mixins: "angle-try"
+  dimensions: "cores:4"
 }
 
 builder_mixins {
@@ -263,9 +256,9 @@
 
 builder_mixins {
   name: "mac-gpu-fyi-ci"
-  dimensions: "cpu:x86-64"
   mixins: "mac"
   mixins: "gpu-fyi-ci"
+  dimensions: "cores:4"
 }
 
 builder_mixins {
@@ -307,7 +300,6 @@
 
 builder_mixins {
   name: "win-gpu-fyi-ci"
-  dimensions: "cpu:x86-64"
   mixins: "win"
   mixins: "gpu-fyi-ci"
   mixins: "gpu-slow-bot"
@@ -330,8 +322,8 @@
   swarming {
     hostname: "chromium-swarm.appspot.com"
     builder_defaults {
+      dimensions: "cores:8"
       dimensions: "cpu:x86-64"
-      dimensions: "pool:luci.chromium.ci"
       service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
       execution_timeout_secs: 10800  # 3h
       swarming_tags: "vpython:native-python-wrapper"
@@ -356,7 +348,6 @@
       name: "Android arm64 Builder (dbg)"
       mixins: "android-ci"
       dimensions: "os:Ubuntu-14.04"
-      dimensions: "cores:8"
       execution_timeout_secs: 14400  # 4h
     }
 
@@ -409,7 +400,6 @@
       name: "Android x64 Builder (dbg)"
       mixins: "android-ci"
       dimensions: "os:Ubuntu-14.04"
-      dimensions: "cores:8"
       execution_timeout_secs: 14400  # 4h
     }
 
@@ -417,14 +407,12 @@
       name: "Android x86 Builder (dbg)"
       mixins: "android-ci"
       dimensions: "os:Ubuntu-14.04"
-      dimensions: "cores:8"
     }
 
     builders {
       name: "Marshmallow 64 bit Tester"
       mixins: "android-ci"
       dimensions: "os:Ubuntu-14.04"
-      dimensions: "cores:8"
     }
 
     # Fuchsia bots.
@@ -472,7 +460,6 @@
     builders {
       name: "GPU Linux Builder"
       mixins: "linux-gpu-ci"
-      dimensions: "cores:8"
     }
 
     builders {
@@ -491,7 +478,6 @@
     builders {
       name: "Linux Release (NVIDIA)"
       mixins: "linux-gpu-ci"
-      dimensions: "cores:8"
     }
 
     builders {
@@ -502,22 +488,18 @@
     builders {
       name: "Linux Builder (dbg)"
       mixins: "linux-ci"
-      dimensions: "cpu:x86-64"
       dimensions: "cores:32"
     }
 
     builders {
       name: "Linux Builder (dbg)(32)"
       mixins: "linux-ci"
-      dimensions: "cpu:x86-64"
       dimensions: "cores:32"
     }
 
     builders {
       name: "Linux Tests (dbg)(1)"
       mixins: "linux-ci"
-      dimensions: "cpu:x86-64"
-      dimensions: "cores:8"
     }
 
     builders {
@@ -580,14 +562,10 @@
     builders {
       name: "Mac Builder (dbg)"
       mixins: "mac-ci"
-      dimensions: "cpu:x86-64"
-      dimensions: "cores:8"
     }
     builders {
       name: "Mac10.13 Tests (dbg)"
       mixins: "mac-ci"
-      dimensions: "cpu:x86-64"
-      dimensions: "cores:8"
     }
 
     # chromium.gpu.fyi
@@ -662,35 +640,27 @@
     builders {
       name: "Win Builder"
       mixins: "win-ci"
-      dimensions: "cpu:x86-64"
       dimensions: "cores:32"
     }
     builders {
       name: "Win Builder (dbg)"
       mixins: "win-ci"
-      dimensions: "cpu:x86-64"
       dimensions: "cores:32"
     }
     builders {
       name: "Win7 (32) Tests"
       mixins: "win-ci"
       dimensions: "os:Windows-7"
-      dimensions: "cpu:x86-64"
-      dimensions: "cores:8"
     }
     builders {
       name: "Win7 Tests (1)"
       mixins: "win-ci"
       dimensions: "os:Windows-7"
-      dimensions: "cpu:x86-64"
-      dimensions: "cores:8"
     }
     builders {
       name: "Win7 Tests (dbg)(1)"
       mixins: "win-ci"
       dimensions: "os:Windows-7"
-      dimensions: "cpu:x86-64"
-      dimensions: "cores:8"
     }
     builders {
       name: "Win10 Tests x64 (dbg)"
@@ -702,37 +672,30 @@
     builders {
       name: "GPU FYI Win Builder"
       mixins: "win-gpu-fyi-ci"
-      dimensions: "cores:8"
     }
     builders {
       name: "GPU FYI Win Builder (dbg)"
       mixins: "win-gpu-fyi-ci"
-      dimensions: "cores:8"
     }
     builders {
       name: "GPU FYI Win Clang Builder (dbg)"
       mixins: "win-gpu-fyi-ci"
-      dimensions: "cores:8"
     }
     builders {
       name: "GPU FYI Win dEQP Builder"
       mixins: "win-gpu-fyi-ci"
-      dimensions: "cores:8"
     }
     builders {
       name: "GPU FYI Win x64 Builder"
       mixins: "win-gpu-fyi-ci"
-      dimensions: "cores:8"
     }
     builders {
       name: "GPU FYI Win x64 Builder (dbg)"
       mixins: "win-gpu-fyi-ci"
-      dimensions: "cores:8"
     }
     builders {
       name: "GPU FYI Win x64 dEQP Builder"
       mixins: "win-gpu-fyi-ci"
-      dimensions: "cores:8"
     }
     builders {
       name: "Win10 FYI Debug (NVIDIA)"
@@ -852,8 +815,8 @@
 
     builder_defaults {
       category: "Chromium CQ"
+      dimensions: "cores:8"
       dimensions: "cpu:x86-64"
-      dimensions: "pool:luci.chromium.try"
       service_account: "chromium-try-builder@chops-service-accounts.iam.gserviceaccount.com"
       execution_timeout_secs: 10800  # 3h
       swarming_tags: "vpython:native-python-wrapper"
@@ -881,13 +844,11 @@
       mixins: "android-try"
       name: "android_arm64_dbg_recipe"
       dimensions: "os:Ubuntu-14.04"
-      dimensions: "cores:8"
     }
     builders {
       mixins: "android-try"
       name: "android_n5x_swarming_dbg"
       dimensions: "os:Ubuntu-14.04"
-      dimensions: "cores:8"
     }
     builders { mixins: "android-optional-gpu-try" name: "android_optional_gpu_tests_rel" }
 
@@ -1022,7 +983,12 @@
     builders { mixins: "mac-try" name: "mac_chromium_variable_layout" }
     builders { mixins: "mac-try" name: "mac_nacl_sdk" }
     builders { mixins: "mac-try" name: "mac_nacl_sdk_build" }
-    builders { mixins: "mac-optional-gpu-try" name: "mac_optional_gpu_tests_rel" }
+    builders {
+      mixins: "mac-optional-gpu-try"
+      name: "mac_optional_gpu_tests_rel"
+      # Clear cores dimension requirement because build{103..105}-m9 are cores:4
+      dimensions: "cores:"
+    }
     builders { mixins: "mac-try" name: "mac_upload_clang" }
     builders { mixins: "mac-try" name: "mac-views-rel" }
 
diff --git a/ios/chrome/app/main_controller.mm b/ios/chrome/app/main_controller.mm
index 5eecccd2..4b9a008 100644
--- a/ios/chrome/app/main_controller.mm
+++ b/ios/chrome/app/main_controller.mm
@@ -888,7 +888,7 @@
   }
   if (!_mainCoordinator) {
     // Lazily create the main coordinator.
-    if (IsTabSwitcherTabGridEnabled()) {
+    if (IsUIRefreshPhase1Enabled()) {
       TabGridCoordinator* tabGridCoordinator =
           [[TabGridCoordinator alloc] initWithWindow:self.window
                           applicationCommandEndpoint:self];
@@ -2483,12 +2483,12 @@
 
 // Creates and returns a tab switcher object according to the current
 // experimental flags and device idioms:
-// - If the tab grid experimental flag is enabled, the TabGridController's
+// - If the UI Refresh phase 1 flag is enabled, the TabGridController's
 //   TabSwitcher is returned.
 // - If the current device is an iPad, a new TabSwitcherController is returned.
 // - Otherwise, a new StackViewController is returned.
 - (id<TabSwitcher>)newTabSwitcher {
-  if (IsTabSwitcherTabGridEnabled()) {
+  if (IsUIRefreshPhase1Enabled()) {
     DCHECK(_mainCoordinator)
         << " Main coordinator not created when tab switcher needed.";
     TabGridCoordinator* tabGridCoordinator =
diff --git a/ios/chrome/app/tests_fake_hook.mm b/ios/chrome/app/tests_fake_hook.mm
index f0e7c98..da4a92e59 100644
--- a/ios/chrome/app/tests_fake_hook.mm
+++ b/ios/chrome/app/tests_fake_hook.mm
@@ -31,10 +31,6 @@
 bool ForceUIRefreshPhase1() {
   return false;
 }
-// TODO(crbug.com/818560) : Remove this hook.
-bool ForceTabSwitcherTabGrid() {
-  return false;
-}
 void SetUpTestsIfPresent() {}
 void RunTestsIfPresent() {}
 
diff --git a/ios/chrome/app/tests_hook.h b/ios/chrome/app/tests_hook.h
index 49e875c..afd241f 100644
--- a/ios/chrome/app/tests_hook.h
+++ b/ios/chrome/app/tests_hook.h
@@ -36,11 +36,6 @@
 // overriding the flag value.
 bool ForceUIRefreshPhase1();
 
-// TODO(crbug.com/818560): Removes this hook.
-// Returns true if the tab grid will be displayed as the tab switcher,
-// overriding the flag value.
-bool ForceTabSwitcherTabGrid();
-
 // Global integration tests setup.  This is not used by EarlGrey-based
 // integration tests.
 void SetUpTestsIfPresent();
diff --git a/ios/chrome/browser/about_flags.mm b/ios/chrome/browser/about_flags.mm
index 1e52b670..00a599a 100644
--- a/ios/chrome/browser/about_flags.mm
+++ b/ios/chrome/browser/about_flags.mm
@@ -237,9 +237,6 @@
      flag_descriptions::kMailtoHandlingWithGoogleUIName,
      flag_descriptions::kMailtoHandlingWithGoogleUIDescription,
      flags_ui::kOsIos, FEATURE_VALUE_TYPE(kMailtoHandledWithGoogleUI)},
-    {"tab-switcher-tab-grid", flag_descriptions::kTabSwitcherTabGridName,
-     flag_descriptions::kTabSwitcherTabGridDescription, flags_ui::kOsIos,
-     FEATURE_VALUE_TYPE(kTabSwitcherTabGrid)},
     {"feedback-kit-v2", flag_descriptions::kFeedbackKitV2Name,
      flag_descriptions::kFeedbackKitV2Description, flags_ui::kOsIos,
      FEATURE_VALUE_TYPE(kFeedbackKitV2)},
diff --git a/ios/chrome/browser/download/download_manager_metric_names.h b/ios/chrome/browser/download/download_manager_metric_names.h
index 71686fe9..6f7d1c1 100644
--- a/ios/chrome/browser/download/download_manager_metric_names.h
+++ b/ios/chrome/browser/download/download_manager_metric_names.h
@@ -9,4 +9,17 @@
 // app is installed after presenting Store Kit dialog from the Download Manager.
 extern const char kDownloadManagerGoogleDriveInstalled[];
 
+// Values of the UMA Download.IOSDownloadedFileAction histogram. This enum is
+// append only.
+enum class DownloadedFileAction {
+  // Downloaded file was uploaded to Google Drive.
+  OpenedInDrive = 0,
+  // Downloaded file was open in the app other than Google Drive.
+  OpenedInOtherApp = 1,
+  // Downloaded file was discarded (the user closed the app, tab, or download
+  // manager UI).
+  NoAction = 2,
+  Count,
+};
+
 #endif  // IOS_CHROME_BROWSER_DOWNLOAD_DOWNLOAD_MANAGER_METRIC_NAMES_H_
diff --git a/ios/chrome/browser/download/google_drive_app_util.h b/ios/chrome/browser/download/google_drive_app_util.h
index 561e660..f3acb81 100644
--- a/ios/chrome/browser/download/google_drive_app_util.h
+++ b/ios/chrome/browser/download/google_drive_app_util.h
@@ -16,6 +16,9 @@
 // app is installed.
 extern NSString* const kGoogleDriveAppURLScheme;
 
+// Bundle ID of Google Drive application.
+extern NSString* const kGoogleDriveAppBundleID;
+
 // Returns URL which can be used to check if Google Drive app is installed via
 // -[UIApplication canOpenURL:] call.
 NSURL* GetGoogleDriveAppUrl();
diff --git a/ios/chrome/browser/download/google_drive_app_util.mm b/ios/chrome/browser/download/google_drive_app_util.mm
index eadc37a..5311676b 100644
--- a/ios/chrome/browser/download/google_drive_app_util.mm
+++ b/ios/chrome/browser/download/google_drive_app_util.mm
@@ -12,6 +12,7 @@
 
 NSString* const kGoogleDriveITunesItemIdentifier = @"507874739";
 NSString* const kGoogleDriveAppURLScheme = @"googledrive";
+NSString* const kGoogleDriveAppBundleID = @"com.google.Drive";
 
 NSURL* GetGoogleDriveAppUrl() {
   NSURLComponents* google_drive_url = [[NSURLComponents alloc] init];
diff --git a/ios/chrome/browser/first_run/first_run.h b/ios/chrome/browser/first_run/first_run.h
index 89034452..9de15087 100644
--- a/ios/chrome/browser/first_run/first_run.h
+++ b/ios/chrome/browser/first_run/first_run.h
@@ -7,6 +7,7 @@
 #ifndef IOS_CHROME_BROWSER_FIRST_RUN_FIRST_RUN_H_
 #define IOS_CHROME_BROWSER_FIRST_RUN_FIRST_RUN_H_
 
+#include "base/files/file.h"
 #include "base/macros.h"
 
 namespace base {
@@ -24,13 +25,28 @@
 // or explicitly skipped.
 class FirstRun {
  public:
+  // Result to create sentinel file. This enum is defined in
+  // src/tools/metrics/histograms/enums.xml
+  enum SentinelResult {
+    // No error.
+    SENTINEL_RESULT_SUCCESS,
+    // GetFirstRunSentinelFilePath() returned no file path.
+    SENTINEL_RESULT_FAILED_TO_GET_PATH,
+    // Sentinel file already exists.
+    SENTINEL_RESULT_FILE_PATH_EXISTS,
+    // File system error.
+    SENTINEL_RESULT_FILE_ERROR,
+    SENTINEL_RESULT_MAX,
+  };
+
   // Returns true if this is the first time chrome is run for this user.
   static bool IsChromeFirstRun();
 
-  // Creates the sentinel file that signals that chrome has been configured iff
-  // the file does not exist yet. Returns true if the file was created and false
-  // if the file already exists or could not be created.
-  static bool CreateSentinel();
+  // Creates the sentinel file that signals that chrome has been configured if
+  // the file does not exist yet. Returns SENTINEL_RESULT_SUCCESS if the file
+  // was created. If SENTINEL_RESULT_FILE_ERROR is returned, |error| is set to
+  // the file system error, if non-nil.
+  static SentinelResult CreateSentinel(base::File::Error* error);
 
   // Removes the sentinel file created in ConfigDone(). Returns false if the
   // sentinel file could not be removed.
diff --git a/ios/chrome/browser/first_run/first_run.mm b/ios/chrome/browser/first_run/first_run.mm
index 4f88454..5081b98 100644
--- a/ios/chrome/browser/first_run/first_run.mm
+++ b/ios/chrome/browser/first_run/first_run.mm
@@ -61,12 +61,16 @@
 }
 
 // static
-bool FirstRun::CreateSentinel() {
+FirstRun::SentinelResult FirstRun::CreateSentinel(base::File::Error* error) {
   base::FilePath first_run_sentinel;
-  if (!GetFirstRunSentinelFilePath(&first_run_sentinel) ||
-      base::PathExists(first_run_sentinel))
-    return false;
-  return base::WriteFile(first_run_sentinel, "", 0) != -1;
+  if (!GetFirstRunSentinelFilePath(&first_run_sentinel))
+    return SENTINEL_RESULT_FAILED_TO_GET_PATH;
+  if (base::PathExists(first_run_sentinel))
+    return SENTINEL_RESULT_FILE_PATH_EXISTS;
+  bool success = base::WriteFile(first_run_sentinel, "", 0) != -1;
+  if (error)
+    *error = base::File::GetLastFileError();
+  return success ? SENTINEL_RESULT_SUCCESS : SENTINEL_RESULT_FILE_ERROR;
 }
 
 // static
diff --git a/ios/chrome/browser/first_run/first_run_metrics.h b/ios/chrome/browser/first_run/first_run_metrics.h
index a272fd6..62054d5 100644
--- a/ios/chrome/browser/first_run/first_run_metrics.h
+++ b/ios/chrome/browser/first_run/first_run_metrics.h
@@ -31,7 +31,7 @@
   HAS_SSO_ACCOUNT_SIGNIN_SKIPPED_GIVEUP,
   // Sentinel file marks the successful completion of First Run. This records
   // the cases where sentinel creation failed. In most likelihood, user will
-  // go through First Run again at the next launch.
+  // go through First Run again at the next launch - deprecated.
   SENTINEL_CREATION_FAILED,
   // Number of First Run states.
   SIGNIN_SIZE
diff --git a/ios/chrome/browser/ios_chrome_flag_descriptions.cc b/ios/chrome/browser/ios_chrome_flag_descriptions.cc
index cfdb4fce..28578683 100644
--- a/ios/chrome/browser/ios_chrome_flag_descriptions.cc
+++ b/ios/chrome/browser/ios_chrome_flag_descriptions.cc
@@ -126,11 +126,6 @@
     "BVC is visible, the tab switcher will remain in the VC hierarchy "
     "underneath it.";
 
-const char kTabSwitcherTabGridName[] = "TabSwitcher Tab Grid";
-const char kTabSwitcherTabGridDescription[] =
-    "When enabled, the tab grid will be used as the tab switcher for both "
-    "phone and tablet.";
-
 const char kUIRefreshPhase1Name[] = "UI Refresh Phase 1";
 const char kUIRefreshPhase1Description[] =
     "When enabled, the first phase of the iOS UI refresh will be displayed.";
diff --git a/ios/chrome/browser/ios_chrome_flag_descriptions.h b/ios/chrome/browser/ios_chrome_flag_descriptions.h
index 3188265..ef9241c 100644
--- a/ios/chrome/browser/ios_chrome_flag_descriptions.h
+++ b/ios/chrome/browser/ios_chrome_flag_descriptions.h
@@ -114,10 +114,6 @@
 extern const char kTabSwitcherPresentsBVCName[];
 extern const char kTabSwitcherPresentsBVCDescription[];
 
-// Title and description for the flag to enable the TabGrid as the tab switcher.
-extern const char kTabSwitcherTabGridName[];
-extern const char kTabSwitcherTabGridDescription[];
-
 // Title and description for the flag to enable the phase 1 UI Refresh.
 extern const char kUIRefreshPhase1Name[];
 extern const char kUIRefreshPhase1Description[];
diff --git a/ios/chrome/browser/metrics/new_tab_page_uma.h b/ios/chrome/browser/metrics/new_tab_page_uma.h
index ef5ae69..7db52e4f 100644
--- a/ios/chrome/browser/metrics/new_tab_page_uma.h
+++ b/ios/chrome/browser/metrics/new_tab_page_uma.h
@@ -29,6 +29,7 @@
   ACTION_OPENED_SUGGESTION,
   ACTION_OPENED_LEARN_MORE,
   ACTION_OPENED_PROMO,
+  ACTION_OPENED_HISTORY_ENTRY,
   NUM_ACTION_TYPES,
 };
 
diff --git a/ios/chrome/browser/passwords/credential_manager_util.mm b/ios/chrome/browser/passwords/credential_manager_util.mm
index aabe1ce..80fe918 100644
--- a/ios/chrome/browser/passwords/credential_manager_util.mm
+++ b/ios/chrome/browser/passwords/credential_manager_util.mm
@@ -138,14 +138,20 @@
 bool ParseCredentialDictionary(const base::DictionaryValue& json,
                                CredentialInfo* credential,
                                std::string* reason) {
-  if (!json.GetString(kCredentialIdKey, &credential->id)) {
+  base::string16 id;
+  if (!json.GetString(kCredentialIdKey, &id)) {
     // |id| is required.
     if (reason) {
       *reason = "no valid 'id' field";
     }
     return false;
   }
-  json.GetString(kCredentialNameKey, &credential->name);
+  credential->id = id;
+
+  base::string16 name;
+  json.GetString(kCredentialNameKey, &name);
+  credential->name = name;
+
   std::string iconUrl;
   if (json.GetString(kCredentialIconKey, &iconUrl) && !iconUrl.empty()) {
     credential->icon = GURL(iconUrl);
@@ -166,15 +172,16 @@
     return false;
   }
   if (credential->type == CredentialType::CREDENTIAL_TYPE_PASSWORD) {
-    if (!json.GetString(kPasswordCredentialPasswordKey,
-                        &credential->password) ||
-        credential->password.empty()) {
+    base::string16 password;
+    if (!json.GetString(kPasswordCredentialPasswordKey, &password) ||
+        password.empty()) {
       // |password| field is required for PasswordCredential.
       if (reason) {
         *reason = "no valid 'password' field";
       }
       return false;
     }
+    credential->password = password;
   }
   if (credential->type == CredentialType::CREDENTIAL_TYPE_FEDERATED) {
     std::string federation;
diff --git a/ios/chrome/browser/passwords/js_credential_manager.mm b/ios/chrome/browser/passwords/js_credential_manager.mm
index 0f33b2a..f555dbb6 100644
--- a/ios/chrome/browser/passwords/js_credential_manager.mm
+++ b/ios/chrome/browser/passwords/js_credential_manager.mm
@@ -25,18 +25,19 @@
     return base::StringPrintf(
         "new FederatedCredential({id: %s, name: %s, iconURL: %s, provider: "
         "%s})",
-        base::GetQuotedJSONString(info.id).c_str(),
-        base::GetQuotedJSONString(info.name).c_str(),
+        base::GetQuotedJSONString(info.id.value_or(base::string16())).c_str(),
+        base::GetQuotedJSONString(info.name.value_or(base::string16())).c_str(),
         base::GetQuotedJSONString(info.icon.spec()).c_str(),
         base::GetQuotedJSONString(info.federation.GetURL().spec()).c_str());
   }
   if (info.type == password_manager::CredentialType::CREDENTIAL_TYPE_PASSWORD) {
     return base::StringPrintf(
         "new PasswordCredential({id: %s, name: %s, iconURL: %s, password: %s})",
-        base::GetQuotedJSONString(info.id).c_str(),
-        base::GetQuotedJSONString(info.name).c_str(),
+        base::GetQuotedJSONString(info.id.value_or(base::string16())).c_str(),
+        base::GetQuotedJSONString(info.name.value_or(base::string16())).c_str(),
         base::GetQuotedJSONString(info.icon.spec()).c_str(),
-        base::GetQuotedJSONString(info.password).c_str());
+        base::GetQuotedJSONString(info.password.value_or(base::string16()))
+            .c_str());
   }
   /* if (info.type == CREDENTIAL_TYPE_EMPTY) */
   return std::string();
diff --git a/ios/chrome/browser/ui/download/download_manager_coordinator.mm b/ios/chrome/browser/ui/download/download_manager_coordinator.mm
index fbb490cb..5e1da9c5 100644
--- a/ios/chrome/browser/ui/download/download_manager_coordinator.mm
+++ b/ios/chrome/browser/ui/download/download_manager_coordinator.mm
@@ -7,6 +7,7 @@
 #include <memory>
 
 #import "base/logging.h"
+#include "base/metrics/histogram_macros.h"
 #include "base/metrics/user_metrics.h"
 #include "base/metrics/user_metrics_action.h"
 #include "base/strings/sys_string_conversions.h"
@@ -30,9 +31,33 @@
 #error "This file requires ARC support."
 #endif
 
+namespace {
+// Tracks download tasks which were not opened by the user yet. Reports various
+// metrics in DownloadTaskObserver callbacks.
+class UnopenedDownloadsTracker : public web::DownloadTaskObserver {
+ public:
+  // Starts tracking this download task.
+  void Add(web::DownloadTask* task) { task->AddObserver(this); }
+  // Stops tracking this download task.
+  void Remove(web::DownloadTask* task) { task->RemoveObserver(this); }
+  // DownloadTaskObserver overrides:
+  void OnDownloadDestroyed(web::DownloadTask* task) override {
+    // This download task was never open by the user.
+    task->RemoveObserver(this);
+
+    if (task->IsDone() && task->GetErrorCode() == net::OK) {
+      UMA_HISTOGRAM_ENUMERATION("Download.IOSDownloadedFileAction",
+                                DownloadedFileAction::NoAction,
+                                DownloadedFileAction::Count);
+    }
+  }
+};
+}  // namespace
+
 @interface DownloadManagerCoordinator ()<
     ContainedPresenterDelegate,
-    DownloadManagerViewControllerDelegate> {
+    DownloadManagerViewControllerDelegate,
+    UIDocumentInteractionControllerDelegate> {
   // View controller for presenting Download Manager UI.
   DownloadManagerViewController* _viewController;
   // A dialog which requests a confirmation from the user.
@@ -41,6 +66,7 @@
   UIDocumentInteractionController* _openInController;
   DownloadManagerMediator _mediator;
   StoreKitCoordinator* _storeKitCoordinator;
+  UnopenedDownloadsTracker _unopenedDownloads;
 }
 @end
 
@@ -61,6 +87,7 @@
   _viewController.delegate = self;
   _mediator.SetDownloadTask(_downloadTask);
   _mediator.SetConsumer(_viewController);
+  _unopenedDownloads.Add(_downloadTask);
 
   self.presenter.baseViewController = self.baseViewController;
   self.presenter.presentedViewController = _viewController;
@@ -144,6 +171,19 @@
   [self start];
 }
 
+#pragma mark - UIDocumentInteractionControllerDelegate
+
+- (void)documentInteractionController:
+            (UIDocumentInteractionController*)controller
+        willBeginSendingToApplication:(NSString*)applicationID {
+  DownloadedFileAction action = [applicationID isEqual:kGoogleDriveAppBundleID]
+                                    ? DownloadedFileAction::OpenedInDrive
+                                    : DownloadedFileAction::OpenedInOtherApp;
+  UMA_HISTOGRAM_ENUMERATION("Download.IOSDownloadedFileAction", action,
+                            DownloadedFileAction::Count);
+  _unopenedDownloads.Remove(_downloadTask);
+}
+
 #pragma mark - ContainedPresenterDelegate
 
 - (void)containedPresenterDidDismiss:(id<ContainedPresenter>)presenter {
@@ -203,6 +243,7 @@
   NSURL* URL = [NSURL fileURLWithPath:base::SysUTF8ToNSString(path.value())];
   _openInController =
       [UIDocumentInteractionController interactionControllerWithURL:URL];
+  _openInController.delegate = self;
 
   BOOL menuShown =
       [_openInController presentOpenInMenuFromRect:layoutGuide.layoutFrame
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 392ff0f..cbebe6f3 100644
--- a/ios/chrome/browser/ui/download/download_manager_coordinator_unittest.mm
+++ b/ios/chrome/browser/ui/download/download_manager_coordinator_unittest.mm
@@ -11,6 +11,7 @@
 #include "base/mac/foundation_util.h"
 #include "base/run_loop.h"
 #include "base/strings/sys_string_conversions.h"
+#include "base/test/histogram_tester.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"
@@ -105,6 +106,7 @@
   id application_;
   DownloadManagerCoordinator* coordinator_;
   base::UserActionTester user_action_tester_;
+  base::HistogramTester histogram_tester_;
 };
 
 // Tests starting the coordinator. Verifies that view controller is presented
@@ -355,11 +357,12 @@
   }));
 }
 
-// Tests presenting Open In... menu.
+// Tests presenting Open In... menu without actually opening the download.
 TEST_F(DownloadManagerCoordinatorTest, OpenIn) {
-  web::FakeDownloadTask task(GURL(kTestUrl), kTestMimeType);
-  task.SetSuggestedFilename(base::SysNSStringToUTF16(kTestSuggestedFileName));
-  coordinator_.downloadTask = &task;
+  auto task =
+      std::make_unique<web::FakeDownloadTask>(GURL(kTestUrl), kTestMimeType);
+  task->SetSuggestedFilename(base::SysNSStringToUTF16(kTestSuggestedFileName));
+  coordinator_.downloadTask = task.get();
   [coordinator_ start];
 
   EXPECT_EQ(1U, base_view_controller_.childViewControllers.count);
@@ -370,9 +373,9 @@
   // Start and complete the download.
   base::FilePath path;
   ASSERT_TRUE(base::GetTempDir(&path));
-  task.Start(std::make_unique<net::URLFetcherFileWriter>(
+  task->Start(std::make_unique<net::URLFetcherFileWriter>(
       base::ThreadTaskRunnerHandle::Get(), path));
-  task.SetDone(true);
+  task->SetDone(true);
 
   // Stub UIDocumentInteractionController.
   FakeDocumentInteractionController* document_interaction_controller =
@@ -397,6 +400,110 @@
       CGRectZero, document_interaction_controller.presentedOpenInMenu.rect));
   ASSERT_EQ(view, document_interaction_controller.presentedOpenInMenu.view);
   ASSERT_TRUE(document_interaction_controller.presentedOpenInMenu.animated);
+
+  // Download task is destroyed without opening the file.
+  task = nullptr;
+  histogram_tester_.ExpectUniqueSample(
+      "Download.IOSDownloadedFileAction",
+      static_cast<base::HistogramBase::Sample>(DownloadedFileAction::NoAction),
+      1);
+}
+
+// Tests opening the download in Google Drive app.
+TEST_F(DownloadManagerCoordinatorTest, OpenInDrive) {
+  web::FakeDownloadTask task(GURL(kTestUrl), kTestMimeType);
+  task.SetSuggestedFilename(base::SysNSStringToUTF16(kTestSuggestedFileName));
+  coordinator_.downloadTask = &task;
+  [coordinator_ start];
+
+  EXPECT_EQ(1U, base_view_controller_.childViewControllers.count);
+  DownloadManagerViewController* viewController =
+      base_view_controller_.childViewControllers.firstObject;
+  ASSERT_EQ([DownloadManagerViewController class], [viewController class]);
+
+  // Start and complete the download.
+  base::FilePath path;
+  ASSERT_TRUE(base::GetTempDir(&path));
+  task.Start(std::make_unique<net::URLFetcherFileWriter>(
+      base::ThreadTaskRunnerHandle::Get(), path));
+
+  // Stub UIDocumentInteractionController.
+  id document_interaction_controller =
+      [[FakeDocumentInteractionController alloc] init];
+  OCMStub([document_interaction_controller_class_
+              interactionControllerWithURL:[OCMArg any]])
+      .andReturn(document_interaction_controller);
+
+  // Present Open In... menu.
+  ASSERT_FALSE([document_interaction_controller presentedOpenInMenu]);
+  @autoreleasepool {
+    // This call will retain coordinator, which should outlive thread bundle.
+    [viewController.delegate downloadManagerViewController:viewController
+                          presentOpenInMenuWithLayoutGuide:nil];
+  }
+  ASSERT_TRUE([document_interaction_controller presentedOpenInMenu]);
+
+  // Open the file in Google Drive app.
+  @autoreleasepool {
+    // This call will retain coordinator, which should outlive thread bundle.
+    [[document_interaction_controller delegate]
+        documentInteractionController:document_interaction_controller
+        willBeginSendingToApplication:kGoogleDriveAppBundleID];
+  }
+
+  histogram_tester_.ExpectUniqueSample("Download.IOSDownloadedFileAction",
+                                       static_cast<base::HistogramBase::Sample>(
+                                           DownloadedFileAction::OpenedInDrive),
+                                       1);
+}
+
+// Tests opening the download in app other than Google Drive app.
+TEST_F(DownloadManagerCoordinatorTest, OpenInOtherApp) {
+  web::FakeDownloadTask task(GURL(kTestUrl), kTestMimeType);
+  task.SetSuggestedFilename(base::SysNSStringToUTF16(kTestSuggestedFileName));
+  coordinator_.downloadTask = &task;
+  [coordinator_ start];
+
+  EXPECT_EQ(1U, base_view_controller_.childViewControllers.count);
+  DownloadManagerViewController* viewController =
+      base_view_controller_.childViewControllers.firstObject;
+  ASSERT_EQ([DownloadManagerViewController class], [viewController class]);
+
+  // Start and complete the download.
+  base::FilePath path;
+  ASSERT_TRUE(base::GetTempDir(&path));
+  task.Start(std::make_unique<net::URLFetcherFileWriter>(
+      base::ThreadTaskRunnerHandle::Get(), path));
+
+  // Stub UIDocumentInteractionController.
+  id document_interaction_controller =
+      [[FakeDocumentInteractionController alloc] init];
+  OCMStub([document_interaction_controller_class_
+              interactionControllerWithURL:[OCMArg any]])
+      .andReturn(document_interaction_controller);
+
+  // Present Open In... menu.
+  ASSERT_FALSE([document_interaction_controller presentedOpenInMenu]);
+  @autoreleasepool {
+    // This call will retain coordinator, which should outlive thread bundle.
+    [viewController.delegate downloadManagerViewController:viewController
+                          presentOpenInMenuWithLayoutGuide:nil];
+  }
+  ASSERT_TRUE([document_interaction_controller presentedOpenInMenu]);
+
+  // Open the file in Google Drive app.
+  @autoreleasepool {
+    // This call will retain coordinator, which should outlive thread bundle.
+    [[document_interaction_controller delegate]
+        documentInteractionController:document_interaction_controller
+        willBeginSendingToApplication:@"foo-app-id"];
+  }
+
+  histogram_tester_.ExpectUniqueSample(
+      "Download.IOSDownloadedFileAction",
+      static_cast<base::HistogramBase::Sample>(
+          DownloadedFileAction::OpenedInOtherApp),
+      1);
 }
 
 // Tests closing view controller while the download is in progress. Coordinator
diff --git a/ios/chrome/browser/ui/first_run/first_run_util.mm b/ios/chrome/browser/ui/first_run/first_run_util.mm
index a8e1a57b..e2ef733 100644
--- a/ios/chrome/browser/ui/first_run/first_run_util.mm
+++ b/ios/chrome/browser/ui/first_run/first_run_util.mm
@@ -6,6 +6,7 @@
 
 #include "base/bind.h"
 #include "base/callback.h"
+#include "base/metrics/histogram_functions.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/strings/sys_string_conversions.h"
 #include "base/task_scheduler/post_task.h"
@@ -77,43 +78,38 @@
 }
 
 // Trampoline method for Bind to create the sentinel file.
-bool CreateSentinel() {
-  return FirstRun::CreateSentinel();
+void CreateSentinel() {
+  base::File::Error file_error;
+  FirstRun::SentinelResult sentinel_created =
+      FirstRun::CreateSentinel(&file_error);
+  UMA_HISTOGRAM_ENUMERATION("FirstRun.Sentinel.Created", sentinel_created,
+                            FirstRun::SentinelResult::SENTINEL_RESULT_MAX);
+  if (sentinel_created == FirstRun::SentinelResult::SENTINEL_RESULT_FILE_ERROR)
+    UMA_HISTOGRAM_ENUMERATION("FirstRun.Sentinel.CreatedFileError", -file_error,
+                              -base::File::FILE_ERROR_MAX);
 }
 
-// Helper function for recording first run metrics. Takes an additional
-// |sentinel_created| argument which is the returned value from
-// CreateSentinel().
+// Helper function for recording first run metrics.
 void RecordFirstRunMetricsInternal(ios::ChromeBrowserState* browserState,
                                    bool sign_in_attempted,
-                                   bool has_sso_accounts,
-                                   bool sentinel_created) {
+                                   bool has_sso_accounts) {
   first_run::SignInStatus sign_in_status;
-  // |sentinel_created| is false if the sentinel file was not created which
-  // indicates that the sentinel already exists and metrics were already
-  // recorded.
-  // Note: If the user signs in and then signs out during first run, it will be
-  // recorded as a successful sign in.
-  if (!sentinel_created) {
-    sign_in_status = first_run::SENTINEL_CREATION_FAILED;
+  bool user_signed_in =
+      ios::SigninManagerFactory::GetForBrowserState(browserState)
+          ->IsAuthenticated();
+  if (user_signed_in) {
+    sign_in_status = has_sso_accounts
+                         ? first_run::HAS_SSO_ACCOUNT_SIGNIN_SUCCESSFUL
+                         : first_run::SIGNIN_SUCCESSFUL;
   } else {
-    bool user_signed_in =
-        ios::SigninManagerFactory::GetForBrowserState(browserState)
-            ->IsAuthenticated();
-    if (user_signed_in) {
+    if (sign_in_attempted) {
       sign_in_status = has_sso_accounts
-                           ? first_run::HAS_SSO_ACCOUNT_SIGNIN_SUCCESSFUL
-                           : first_run::SIGNIN_SUCCESSFUL;
+                           ? first_run::HAS_SSO_ACCOUNT_SIGNIN_SKIPPED_GIVEUP
+                           : first_run::SIGNIN_SKIPPED_GIVEUP;
     } else {
-      if (sign_in_attempted) {
-        sign_in_status = has_sso_accounts
-                             ? first_run::HAS_SSO_ACCOUNT_SIGNIN_SKIPPED_GIVEUP
-                             : first_run::SIGNIN_SKIPPED_GIVEUP;
-      } else {
-        sign_in_status = has_sso_accounts
-                             ? first_run::HAS_SSO_ACCOUNT_SIGNIN_SKIPPED_QUICK
-                             : first_run::SIGNIN_SKIPPED_QUICK;
-      }
+      sign_in_status = has_sso_accounts
+                           ? first_run::HAS_SSO_ACCOUNT_SIGNIN_SKIPPED_QUICK
+                           : first_run::SIGNIN_SKIPPED_QUICK;
     }
   }
   UMA_HISTOGRAM_ENUMERATION("FirstRun.SignIn", sign_in_status,
@@ -150,12 +146,11 @@
     ios::ChromeBrowserState* browserState,
     BOOL sign_in_attempted,
     BOOL has_sso_account) {
-  // Call CreateSentinel() and pass the result into RecordFirstRunMetrics().
-  base::PostTaskWithTraitsAndReplyWithResult(
-      FROM_HERE, {base::MayBlock(), base::TaskPriority::BACKGROUND},
-      base::BindOnce(&CreateSentinel),
-      base::BindOnce(&RecordFirstRunMetricsInternal, browserState,
-                     sign_in_attempted, has_sso_account));
+  base::PostTaskWithTraits(FROM_HERE,
+                           {base::MayBlock(), base::TaskPriority::BACKGROUND},
+                           base::BindOnce(&CreateSentinel));
+  RecordFirstRunMetricsInternal(browserState, sign_in_attempted,
+                                has_sso_account);
 }
 
 void FinishFirstRun(ios::ChromeBrowserState* browserState,
diff --git a/ios/chrome/browser/ui/history/BUILD.gn b/ios/chrome/browser/ui/history/BUILD.gn
index 84e7069..d9c4b85 100644
--- a/ios/chrome/browser/ui/history/BUILD.gn
+++ b/ios/chrome/browser/ui/history/BUILD.gn
@@ -50,6 +50,7 @@
     "//ios/chrome/browser/browser_state",
     "//ios/chrome/browser/favicon",
     "//ios/chrome/browser/history",
+    "//ios/chrome/browser/metrics:metrics_internal",
     "//ios/chrome/browser/signin",
     "//ios/chrome/browser/sync",
     "//ios/chrome/browser/ui",
diff --git a/ios/chrome/browser/ui/history/history_collection_view_controller.mm b/ios/chrome/browser/ui/history/history_collection_view_controller.mm
index 3e7ce6e4..3780191 100644
--- a/ios/chrome/browser/ui/history/history_collection_view_controller.mm
+++ b/ios/chrome/browser/ui/history/history_collection_view_controller.mm
@@ -24,6 +24,7 @@
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
 #include "ios/chrome/browser/chrome_url_constants.h"
 #include "ios/chrome/browser/history/history_service_factory.h"
+#import "ios/chrome/browser/metrics/new_tab_page_uma.h"
 #import "ios/chrome/browser/signin/authentication_service.h"
 #include "ios/chrome/browser/signin/authentication_service_factory.h"
 #include "ios/chrome/browser/sync/ios_chrome_profile_sync_service_factory.h"
@@ -880,6 +881,8 @@
 
 - (void)openURL:(const GURL&)URL {
   GURL copiedURL(URL);
+  new_tab_page_uma::RecordAction(_browserState,
+                                 new_tab_page_uma::ACTION_OPENED_HISTORY_ENTRY);
   [self.delegate historyCollectionViewController:self
                        shouldCloseWithCompletion:^{
                          [self.URLLoader
diff --git a/ios/chrome/browser/ui/tab_grid/tab_grid_egtests_hook.mm b/ios/chrome/browser/ui/tab_grid/tab_grid_egtests_hook.mm
index 681321c..7fa1b5b 100644
--- a/ios/chrome/browser/ui/tab_grid/tab_grid_egtests_hook.mm
+++ b/ios/chrome/browser/ui/tab_grid/tab_grid_egtests_hook.mm
@@ -38,11 +38,6 @@
   return true;
 }
 
-// TODO(crbug.com/818560) : Remove this hook.
-bool ForceTabSwitcherTabGrid() {
-  return true;
-}
-
 void SetUpTestsIfPresent() {
   // No-op for Earl Grey.
 }
diff --git a/ios/chrome/browser/ui/tab_grid/tab_grid_mediator_unittest.mm b/ios/chrome/browser/ui/tab_grid/tab_grid_mediator_unittest.mm
index 63882f1..d99ce55 100644
--- a/ios/chrome/browser/ui/tab_grid/tab_grid_mediator_unittest.mm
+++ b/ios/chrome/browser/ui/tab_grid/tab_grid_mediator_unittest.mm
@@ -31,6 +31,54 @@
 #error "This file requires ARC support."
 #endif
 
+// Test object that conforms to GridConsumer and exposes inner state for test
+// verification.
+@interface FakeConsumer : NSObject<GridConsumer>
+@property(nonatomic, strong) NSMutableArray<GridItem*>* items;
+@property(nonatomic, assign) NSUInteger selectedIndex;
+@end
+@implementation FakeConsumer
+@synthesize items = _items;
+@synthesize selectedIndex = _selectedIndex;
+
+- (void)populateItems:(NSArray<GridItem*>*)items
+        selectedIndex:(NSUInteger)selectedIndex {
+  self.selectedIndex = selectedIndex;
+  self.items = [items mutableCopy];
+}
+
+- (void)insertItem:(GridItem*)item
+           atIndex:(NSUInteger)index
+     selectedIndex:(NSUInteger)selectedIndex {
+  [self.items insertObject:item atIndex:index];
+  self.selectedIndex = selectedIndex;
+}
+
+- (void)removeItemAtIndex:(NSUInteger)index
+            selectedIndex:(NSUInteger)selectedIndex {
+  [self.items removeObjectAtIndex:index];
+  self.selectedIndex = selectedIndex;
+}
+
+- (void)selectItemAtIndex:(NSUInteger)selectedIndex {
+  self.selectedIndex = selectedIndex;
+}
+
+- (void)replaceItemAtIndex:(NSUInteger)index withItem:(GridItem*)item {
+  self.items[index] = item;
+}
+
+- (void)moveItemFromIndex:(NSUInteger)fromIndex
+                  toIndex:(NSUInteger)toIndex
+            selectedIndex:(NSUInteger)selectedIndex {
+  GridItem* item = self.items[fromIndex];
+  [self.items removeObjectAtIndex:fromIndex];
+  [self.items insertObject:item atIndex:toIndex];
+  self.selectedIndex = selectedIndex;
+}
+
+@end
+
 // Fake WebStateList delegate that attaches the tab ID tab helper.
 class TabIdFakeWebStateListDelegate : public FakeWebStateListDelegate {
  public:
@@ -76,7 +124,7 @@
                                       WebStateOpener());
     }
     web_state_list_->ActivateWebStateAt(1);
-    consumer_ = OCMProtocolMock(@protocol(GridConsumer));
+    consumer_ = [[FakeConsumer alloc] init];
     mediator_ = [[TabGridMediator alloc] initWithConsumer:consumer_];
     mediator_.tabModel = tab_model_;
   }
@@ -89,37 +137,22 @@
   std::unique_ptr<TabIdFakeWebStateListDelegate> web_state_list_delegate_;
   std::unique_ptr<WebStateList> web_state_list_;
   id tab_model_;
-  id consumer_;
+  FakeConsumer* consumer_;
   TabGridMediator* mediator_;
   NSMutableSet* original_identifiers_;
 };
 
 // Tests that the consumer is populated after the tab model is set on the
 // mediator.
-// TODO(crbug.com/819658): Test fails on device. Re-enable after fixing.
-#if TARGET_IPHONE_SIMULATOR
-#define MAYBE_ConsumerPopulateItems ConsumerPopulateItems
-#else
-#define MAYBE_ConsumerPopulateItems DISABLED_ConsumerPopulateItems
-#endif
-TEST_F(TabGridMediatorTest, MAYBE_ConsumerPopulateItems) {
-  [[consumer_ verify] populateItems:[OCMArg checkWithBlock:^BOOL(id value) {
-                        NSArray* items =
-                            base::mac::ObjCCastStrict<NSArray>(value);
-                        EXPECT_EQ(3UL, items.count);
-                        return YES;
-                      }]
-                      selectedIndex:1];
+TEST_F(TabGridMediatorTest, ConsumerPopulateItems) {
+  EXPECT_EQ(3UL, consumer_.items.count);
+  EXPECT_EQ(1UL, consumer_.selectedIndex);
 }
 
 // Tests that the consumer is notified when a web state is inserted.
-// TODO(crbug.com/819658): Test fails on device. Re-enable after fixing.
-#if TARGET_IPHONE_SIMULATOR
-#define MAYBE_ConsumerInsertItem ConsumerInsertItem
-#else
-#define MAYBE_ConsumerInsertItem DISABLED_ConsumerInsertItem
-#endif
-TEST_F(TabGridMediatorTest, MAYBE_ConsumerInsertItem) {
+TEST_F(TabGridMediatorTest, ConsumerInsertItem) {
+  ASSERT_EQ(3UL, consumer_.items.count);
+  ASSERT_EQ(1UL, consumer_.selectedIndex);
   auto web_state = std::make_unique<web::TestWebState>();
   TabIdTabHelper::CreateForWebState(web_state.get());
   NSString* item_identifier =
@@ -127,27 +160,24 @@
   web_state_list_->InsertWebState(1, std::move(web_state),
                                   WebStateList::INSERT_FORCE_INDEX,
                                   WebStateOpener());
-  [[consumer_ verify] insertItem:[OCMArg checkWithBlock:^BOOL(id value) {
-                        GridItem* item =
-                            base::mac::ObjCCastStrict<GridItem>(value);
-                        EXPECT_NSEQ(item_identifier, item.identifier);
-                        return YES;
-                      }]
-                         atIndex:1
-                   selectedIndex:2];
+  EXPECT_EQ(4UL, consumer_.items.count);
+  EXPECT_EQ(2UL, consumer_.selectedIndex);
+  EXPECT_NSEQ(item_identifier, consumer_.items[1].identifier);
+  EXPECT_FALSE([original_identifiers_ containsObject:item_identifier]);
 }
 
 // Tests that the consumer is notified when a web state is removed.
 TEST_F(TabGridMediatorTest, ConsumerRemoveItem) {
   web_state_list_->CloseWebStateAt(1, WebStateList::CLOSE_NO_FLAGS);
-  [[consumer_ verify] removeItemAtIndex:1 selectedIndex:1];
+  EXPECT_EQ(2UL, consumer_.items.count);
+  EXPECT_EQ(1UL, consumer_.selectedIndex);
 }
 
 // Tests that the consumer is notified when the active web state is changed.
 TEST_F(TabGridMediatorTest, ConsumerUpdateSelectedItem) {
-  // Selected index is 1 before the update.
+  ASSERT_EQ(1UL, consumer_.selectedIndex);
   web_state_list_->ActivateWebStateAt(2);
-  [[consumer_ verify] selectItemAtIndex:2];
+  EXPECT_EQ(2UL, consumer_.selectedIndex);
 }
 
 // Tests that the consumer is notified when a web state is replaced.
@@ -157,20 +187,21 @@
   NSString* new_item_identifier =
       TabIdTabHelper::FromWebState(new_web_state.get())->tab_id();
   web_state_list_->ReplaceWebStateAt(1, std::move(new_web_state));
-  [[consumer_ verify]
-      replaceItemAtIndex:1
-                withItem:[OCMArg checkWithBlock:^BOOL(id value) {
-                  GridItem* item = base::mac::ObjCCastStrict<GridItem>(value);
-                  EXPECT_NSEQ(new_item_identifier, item.identifier);
-                  return YES;
-                }]];
+  EXPECT_EQ(3UL, consumer_.items.count);
+  EXPECT_EQ(1UL, consumer_.selectedIndex);
+  EXPECT_NSEQ(new_item_identifier, consumer_.items[1].identifier);
+  EXPECT_FALSE([original_identifiers_ containsObject:new_item_identifier]);
 }
 
 // Tests that the consumer is notified when a web state is moved.
 TEST_F(TabGridMediatorTest, ConsumerMoveItem) {
-  // Selected index is 1 before the move.
+  NSString* item1 = consumer_.items[1].identifier;
+  NSString* item2 = consumer_.items[2].identifier;
+  ASSERT_EQ(1UL, consumer_.selectedIndex);
   web_state_list_->MoveWebStateAt(1, 2);
-  [[consumer_ verify] moveItemFromIndex:1 toIndex:2 selectedIndex:2];
+  EXPECT_NSEQ(item1, consumer_.items[2].identifier);
+  EXPECT_NSEQ(item2, consumer_.items[1].identifier);
+  EXPECT_EQ(2UL, consumer_.selectedIndex);
 }
 
 // Tests that the active index is updated when |-selectItemAtIndex:| is called.
diff --git a/ios/chrome/browser/ui/tab_grid/tab_grid_view_controller.mm b/ios/chrome/browser/ui/tab_grid/tab_grid_view_controller.mm
index afbb2471c..f593242f 100644
--- a/ios/chrome/browser/ui/tab_grid/tab_grid_view_controller.mm
+++ b/ios/chrome/browser/ui/tab_grid/tab_grid_view_controller.mm
@@ -131,6 +131,18 @@
   self.regularTabsViewController.gridView.contentInset = contentInset;
 }
 
+- (void)viewWillTransitionToSize:(CGSize)size
+       withTransitionCoordinator:
+           (id<UIViewControllerTransitionCoordinator>)coordinator {
+  auto animate = ^(id<UIViewControllerTransitionCoordinatorContext> context) {
+    // Call the current page setter to sync the scroll view offset to the
+    // current page value.
+    self.currentPage = _currentPage;
+    [self configureViewControllerForCurrentSizeClassesAndPage];
+  };
+  [coordinator animateAlongsideTransition:animate completion:nil];
+}
+
 - (UIStatusBarStyle)preferredStatusBarStyle {
   return UIStatusBarStyleLightContent;
 }
diff --git a/ios/chrome/browser/ui/tab_grid/transitions/grid_transition_layout.mm b/ios/chrome/browser/ui/tab_grid/transitions/grid_transition_layout.mm
index 26d5256..14e4126 100644
--- a/ios/chrome/browser/ui/tab_grid/transitions/grid_transition_layout.mm
+++ b/ios/chrome/browser/ui/tab_grid/transitions/grid_transition_layout.mm
@@ -29,7 +29,7 @@
 }
 
 - (void)setSelectedItem:(GridTransitionLayoutItem*)selectedItem {
-  DCHECK([self.items containsObject:selectedItem]);
+  DCHECK(!selectedItem || [self.items containsObject:selectedItem]);
   _selectedItem = selectedItem;
 }
 
diff --git a/ios/chrome/browser/ui/toolbar/adaptive/adaptive_toolbar_eg_tests_hook.mm b/ios/chrome/browser/ui/toolbar/adaptive/adaptive_toolbar_eg_tests_hook.mm
index 15a705f..7fa1b5b 100644
--- a/ios/chrome/browser/ui/toolbar/adaptive/adaptive_toolbar_eg_tests_hook.mm
+++ b/ios/chrome/browser/ui/toolbar/adaptive/adaptive_toolbar_eg_tests_hook.mm
@@ -38,11 +38,6 @@
   return true;
 }
 
-// TODO(crbug.com/818560) : Remove this hook.
-bool ForceTabSwitcherTabGrid() {
-  return false;
-}
-
 void SetUpTestsIfPresent() {
   // No-op for Earl Grey.
 }
diff --git a/ios/chrome/browser/ui/ui_feature_flags.cc b/ios/chrome/browser/ui/ui_feature_flags.cc
index f8924b93..57f2788 100644
--- a/ios/chrome/browser/ui/ui_feature_flags.cc
+++ b/ios/chrome/browser/ui/ui_feature_flags.cc
@@ -7,8 +7,5 @@
 const base::Feature kUIRefreshPhase1{"UIRefreshPhase1",
                                      base::FEATURE_DISABLED_BY_DEFAULT};
 
-const base::Feature kTabSwitcherTabGrid{"TabSwitcherTabGrid",
-                                        base::FEATURE_DISABLED_BY_DEFAULT};
-
 const base::Feature kCollectionsUIReboot{"CollectionsUIReboot",
                                          base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/ios/chrome/browser/ui/ui_feature_flags.h b/ios/chrome/browser/ui/ui_feature_flags.h
index 6bf5f97..32395450d 100644
--- a/ios/chrome/browser/ui/ui_feature_flags.h
+++ b/ios/chrome/browser/ui/ui_feature_flags.h
@@ -11,10 +11,6 @@
 // used directly. Instead use ui_util::IsUIRefreshPhase1Enabled().
 extern const base::Feature kUIRefreshPhase1;
 
-// Used to enable the tab grid on phone and tablet. This flag should not be
-// used directly. Instead use ui_util::IsTabSwitcherTabGridEnabled().
-extern const base::Feature kTabSwitcherTabGrid;
-
 // Feature to choose whether to use the new UI Reboot Collection stack, or the
 // legacy one. This flag should not be used directly. Instead use
 // experimental_flags::IsCollectionsUIRebootEnabled()
diff --git a/ios/chrome/browser/ui/ui_util.h b/ios/chrome/browser/ui/ui_util.h
index 78f957e..dbeb71a 100644
--- a/ios/chrome/browser/ui/ui_util.h
+++ b/ios/chrome/browser/ui/ui_util.h
@@ -42,9 +42,6 @@
 // Returns whether the first phase of the UI refresh will be displayed.
 bool IsUIRefreshPhase1Enabled();
 
-// Returns whether the tab grid will be displayed as the tab switcher.
-bool IsTabSwitcherTabGridEnabled();
-
 // Returns the height of the status bar, accounting for orientation.
 CGFloat StatusBarHeight();
 
diff --git a/ios/chrome/browser/ui/ui_util.mm b/ios/chrome/browser/ui/ui_util.mm
index 9e68e25..b821199 100644
--- a/ios/chrome/browser/ui/ui_util.mm
+++ b/ios/chrome/browser/ui/ui_util.mm
@@ -63,13 +63,6 @@
   return base::FeatureList::IsEnabled(kUIRefreshPhase1);
 }
 
-// TODO(crbug.com/818560) : Remove this flag.
-bool IsTabSwitcherTabGridEnabled() {
-  if (tests_hook::ForceTabSwitcherTabGrid())
-    return true;
-  return base::FeatureList::IsEnabled(kTabSwitcherTabGrid);
-}
-
 CGFloat StatusBarHeight() {
   // This is a temporary solution until usage of StatusBarHeight has been
   // replaced with topLayoutGuide.
diff --git a/ios/chrome/test/earl_grey/eg_tests_hook.mm b/ios/chrome/test/earl_grey/eg_tests_hook.mm
index 05154c2..f1f1ada 100644
--- a/ios/chrome/test/earl_grey/eg_tests_hook.mm
+++ b/ios/chrome/test/earl_grey/eg_tests_hook.mm
@@ -38,11 +38,6 @@
   return false;
 }
 
-// TODO(crbug.com/818560) : Remove this hook.
-bool ForceTabSwitcherTabGrid() {
-  return false;
-}
-
 void SetUpTestsIfPresent() {
   // No-op for Earl Grey.
 }
diff --git a/ios/chrome/test/fakes/fake_document_interaction_controller.h b/ios/chrome/test/fakes/fake_document_interaction_controller.h
index 10a70ab5..d34ed8f9 100644
--- a/ios/chrome/test/fakes/fake_document_interaction_controller.h
+++ b/ios/chrome/test/fakes/fake_document_interaction_controller.h
@@ -19,13 +19,16 @@
 // present any UI, but simply captures the presentation requests.
 @interface FakeDocumentInteractionController : NSObject
 
+@property(nonatomic, weak) id<UIDocumentInteractionControllerDelegate> delegate;
+
+// Menu that is currently being presented.
+@property(nonatomic, readonly) OpenInMenu* presentedOpenInMenu;
+
 // Fake implementations of UIDocumentInteractionController methods:
 - (BOOL)presentOpenInMenuFromRect:(CGRect)rect
                            inView:(UIView*)view
                          animated:(BOOL)animated;
 
-// Menu that is currently being presented.
-@property(nonatomic, readonly) OpenInMenu* presentedOpenInMenu;
 
 @end
 
diff --git a/ios/chrome/test/fakes/fake_document_interaction_controller.mm b/ios/chrome/test/fakes/fake_document_interaction_controller.mm
index 946e26f..3d1730f 100644
--- a/ios/chrome/test/fakes/fake_document_interaction_controller.mm
+++ b/ios/chrome/test/fakes/fake_document_interaction_controller.mm
@@ -22,6 +22,7 @@
 @end
 
 @implementation FakeDocumentInteractionController
+@synthesize delegate = _delegate;
 @synthesize presentedOpenInMenu = _presentedOpenInMenu;
 - (BOOL)presentOpenInMenuFromRect:(CGRect)rect
                            inView:(UIView*)view
diff --git a/ios/public/provider/chrome/browser/signin/chrome_identity_service.h b/ios/public/provider/chrome/browser/signin/chrome_identity_service.h
index 7d1d0cd..b10b8a3 100644
--- a/ios/public/provider/chrome/browser/signin/chrome_identity_service.h
+++ b/ios/public/provider/chrome/browser/signin/chrome_identity_service.h
@@ -160,12 +160,20 @@
                               AccessTokenCallback callback);
 
   // Asynchronously retrieves access tokens for the given identity and scopes.
+  // TODO(crbug.com/516021): Deprecated API, it will be removed after cleanup
+  // in downstream, see crrev.com/i/480972 and crrev.com/c/973229.
   virtual void GetAccessToken(ChromeIdentity* identity,
                               const std::string& client_id,
                               const std::string& client_secret,
                               const std::set<std::string>& scopes,
                               AccessTokenCallback callback);
 
+  // Asynchronously retrieves access tokens for the given identity and scopes.
+  virtual void GetAccessToken(ChromeIdentity* identity,
+                              const std::string& client_id,
+                              const std::set<std::string>& scopes,
+                              AccessTokenCallback callback);
+
   // Fetches the profile avatar, from the cache or the network.
   // For high resolution iPads, returns large images (200 x 200) to avoid
   // pixelization. Calls back on the main thread.
diff --git a/ios/public/provider/chrome/browser/signin/chrome_identity_service.mm b/ios/public/provider/chrome/browser/signin/chrome_identity_service.mm
index d32e9ea..b1bb3f9 100644
--- a/ios/public/provider/chrome/browser/signin/chrome_identity_service.mm
+++ b/ios/public/provider/chrome/browser/signin/chrome_identity_service.mm
@@ -91,6 +91,13 @@
                                            const std::set<std::string>& scopes,
                                            AccessTokenCallback callback) {}
 
+void ChromeIdentityService::GetAccessToken(ChromeIdentity* identity,
+                                           const std::string& client_id,
+                                           const std::set<std::string>& scopes,
+                                           AccessTokenCallback callback) {
+  GetAccessToken(identity, client_id, "", scopes, callback);
+}
+
 void ChromeIdentityService::GetAvatarForIdentity(ChromeIdentity* identity,
                                                  GetAvatarCallback callback) {}
 
diff --git a/ios/third_party/material_components_ios/BUILD.gn b/ios/third_party/material_components_ios/BUILD.gn
index bd7421e..949d72d 100644
--- a/ios/third_party/material_components_ios/BUILD.gn
+++ b/ios/third_party/material_components_ios/BUILD.gn
@@ -31,6 +31,13 @@
   ]
 }
 
+config("disable_deprecated_errors") {
+  cflags = [
+    "-Wno-deprecated",
+    "-Wno-deprecated-declarations",
+  ]
+}
+
 _icon_names = [
   "ic_check",
   "ic_check_circle",
@@ -130,6 +137,7 @@
     "src/components/Dialogs/src/ColorThemer/MDCAlertColorThemer.m",
     "src/components/Dialogs/src/MDCAlertController.h",
     "src/components/Dialogs/src/MDCAlertController.m",
+    "src/components/Dialogs/src/MDCAlertControllerView.h",
     "src/components/Dialogs/src/MDCDialogPresentationController.h",
     "src/components/Dialogs/src/MDCDialogPresentationController.m",
     "src/components/Dialogs/src/MDCDialogTransitionController.h",
@@ -137,6 +145,8 @@
     "src/components/Dialogs/src/MaterialDialogs.h",
     "src/components/Dialogs/src/UIViewController+MaterialDialogs.h",
     "src/components/Dialogs/src/UIViewController+MaterialDialogs.m",
+    "src/components/Dialogs/src/private/MDCAlertControllerView+Private.h",
+    "src/components/Dialogs/src/private/MDCAlertControllerView+Private.m",
     "src/components/Dialogs/src/private/MDCDialogShadowedView.h",
     "src/components/Dialogs/src/private/MDCDialogShadowedView.m",
     "src/components/Dialogs/src/private/MaterialDialogsStrings.h",
@@ -322,6 +332,10 @@
     ":config",
     "//build/config/compiler:enable_arc",
     "//build/config/compiler:no_chromium_code",
+
+    # material_components_ios internally uses deprecated methods.
+    # Disable the warning about deprecation usage.
+    ":disable_deprecated_errors",
   ]
 }
 
diff --git a/ios/web/download/download_task_impl.mm b/ios/web/download/download_task_impl.mm
index 8e4c675..21ee439 100644
--- a/ios/web/download/download_task_impl.mm
+++ b/ios/web/download/download_task_impl.mm
@@ -219,6 +219,8 @@
   DCHECK_CURRENTLY_ON(web::WebThread::UI);
   DCHECK_NE(state_, State::kInProgress);
   writer_ = std::move(writer);
+  percent_complete_ = 0;
+  received_bytes_ = 0;
   state_ = State::kInProgress;
   GetCookies(base::Bind(&DownloadTaskImpl::StartWithCookies,
                         weak_factory_.GetWeakPtr()));
diff --git a/ios/web/download/download_task_impl_unittest.mm b/ios/web/download/download_task_impl_unittest.mm
index 8baf503..26d935e 100644
--- a/ios/web/download/download_task_impl_unittest.mm
+++ b/ios/web/download/download_task_impl_unittest.mm
@@ -344,10 +344,12 @@
   ASSERT_TRUE(WaitUntilConditionOrTimeout(kWaitForDownloadTimeout, ^{
     return task_->IsDone();
   }));
+  EXPECT_EQ(100, task_->GetPercentComplete());
 
   // Restart the task.
   EXPECT_CALL(task_observer_, OnDownloadUpdated(task_.get()));
   session_task = Start();
+  EXPECT_EQ(0, task_->GetPercentComplete());
   ASSERT_TRUE(session_task);
   testing::Mock::VerifyAndClearExpectations(&task_observer_);
 
diff --git a/ios/web/navigation/legacy_navigation_manager_impl.mm b/ios/web/navigation/legacy_navigation_manager_impl.mm
index 8e61f963..7ce0b9d9 100644
--- a/ios/web/navigation/legacy_navigation_manager_impl.mm
+++ b/ios/web/navigation/legacy_navigation_manager_impl.mm
@@ -90,8 +90,12 @@
   NavigationItem* item = GetPendingItem();
   if (!item)
     item = GetLastCommittedNonAppSpecificItem();
-  DCHECK(item->GetUserAgentType() != UserAgentType::NONE);
-  GetTransientItem()->SetUserAgentType(item->GetUserAgentType());
+  // |item| may still be nullptr if NTP is the only entry in the session.
+  // See https://crbug.com/822908 for details.
+  if (item) {
+    DCHECK(item->GetUserAgentType() != UserAgentType::NONE);
+    GetTransientItem()->SetUserAgentType(item->GetUserAgentType());
+  }
 }
 
 void LegacyNavigationManagerImpl::AddPendingItem(
diff --git a/media/base/cdm_promise.h b/media/base/cdm_promise.h
index 9467973e..13740f5 100644
--- a/media/base/cdm_promise.h
+++ b/media/base/cdm_promise.h
@@ -29,7 +29,7 @@
 // indicates the type of CdmPromiseTemplate. CdmPromiseTemplate<T> adds the
 // resolve(T) method that is dependent on the type of promise. This base class
 // is specified so that the promises can be easily saved before passing across
-// the pepper interface.
+// IPC.
 class MEDIA_EXPORT CdmPromise {
  public:
   enum class Exception {
diff --git a/media/base/media_switches.cc b/media/base/media_switches.cc
index 6efb48a3..ddaf778 100644
--- a/media/base/media_switches.cc
+++ b/media/base/media_switches.cc
@@ -359,9 +359,8 @@
 #endif  // BUILDFLAG(ENABLE_PLUGINS)
 
 // Adds icons to the overflow menu on the native media controls.
-// For experiment: crbug.com/763301
 const base::Feature kOverflowIconsForMediaControls{
-    "OverflowIconsForMediaControls", base::FEATURE_DISABLED_BY_DEFAULT};
+    "OverflowIconsForMediaControls", base::FEATURE_ENABLED_BY_DEFAULT};
 
 // Enables the new redesigned media controls.
 const base::Feature kUseModernMediaControls{"UseModernMediaControls",
diff --git a/media/capture/video/win/video_capture_device_win.cc b/media/capture/video/win/video_capture_device_win.cc
index 2a562b36..92fe61d 100644
--- a/media/capture/video/win/video_capture_device_win.cc
+++ b/media/capture/video/win/video_capture_device_win.cc
@@ -321,6 +321,7 @@
       {kMediaSubTypeI420, PIXEL_FORMAT_I420},
       {MEDIASUBTYPE_IYUV, PIXEL_FORMAT_I420},
       {MEDIASUBTYPE_RGB24, PIXEL_FORMAT_RGB24},
+      {MEDIASUBTYPE_RGB32, PIXEL_FORMAT_RGB32},
       {MEDIASUBTYPE_YUY2, PIXEL_FORMAT_YUY2},
       {MEDIASUBTYPE_MJPG, PIXEL_FORMAT_MJPEG},
       {MEDIASUBTYPE_UYVY, PIXEL_FORMAT_UYVY},
diff --git a/media/cdm/cdm_helpers.cc b/media/cdm/cdm_helpers.cc
index 491bff9e2..de58ea2f 100644
--- a/media/cdm/cdm_helpers.cc
+++ b/media/cdm/cdm_helpers.cc
@@ -4,14 +4,7 @@
 
 #include "media/cdm/cdm_helpers.h"
 
-#if defined(USE_PPAPI_CDM_ADAPTER)
-// When building the ppapi adapter do not include any non-trivial base/ headers.
-#include "ppapi/cpp/logging.h"  // nogncheck
-#define PLATFORM_DCHECK PP_DCHECK
-#else
 #include "base/logging.h"
-#define PLATFORM_DCHECK DCHECK
-#endif
 
 namespace media {
 
@@ -77,22 +70,22 @@
 
 void VideoFrameImpl::SetPlaneOffset(cdm::VideoFrame::VideoPlane plane,
                                     uint32_t offset) {
-  PLATFORM_DCHECK(plane < kMaxPlanes);
+  DCHECK(plane < kMaxPlanes);
   plane_offsets_[plane] = offset;
 }
 
 uint32_t VideoFrameImpl::PlaneOffset(VideoPlane plane) {
-  PLATFORM_DCHECK(plane < kMaxPlanes);
+  DCHECK(plane < kMaxPlanes);
   return plane_offsets_[plane];
 }
 
 void VideoFrameImpl::SetStride(VideoPlane plane, uint32_t stride) {
-  PLATFORM_DCHECK(plane < kMaxPlanes);
+  DCHECK(plane < kMaxPlanes);
   strides_[plane] = stride;
 }
 
 uint32_t VideoFrameImpl::Stride(VideoPlane plane) {
-  PLATFORM_DCHECK(plane < kMaxPlanes);
+  DCHECK(plane < kMaxPlanes);
   return strides_[plane];
 }
 
diff --git a/media/cdm/cdm_helpers.h b/media/cdm/cdm_helpers.h
index 8cbb6dc..11823c4 100644
--- a/media/cdm/cdm_helpers.h
+++ b/media/cdm/cdm_helpers.h
@@ -9,16 +9,10 @@
 
 #include "base/compiler_specific.h"
 #include "base/macros.h"
-#include "media/cdm/api/content_decryption_module.h"
-
-#if !defined(USE_PPAPI_CDM_ADAPTER)
 #include "base/memory/ref_counted.h"
-#include "media/base/media_export.h"  // nogncheck
+#include "media/base/media_export.h"
+#include "media/cdm/api/content_decryption_module.h"
 #include "ui/gfx/geometry/size.h"
-#define MEDIA_CDM_EXPORT MEDIA_EXPORT
-#else
-#define MEDIA_CDM_EXPORT
-#endif
 
 namespace media {
 
@@ -42,7 +36,7 @@
   DISALLOW_COPY_AND_ASSIGN(DecryptedBlockImpl);
 };
 
-class MEDIA_CDM_EXPORT VideoFrameImpl : public cdm::VideoFrame {
+class MEDIA_EXPORT VideoFrameImpl : public cdm::VideoFrame {
  public:
   VideoFrameImpl();
   ~VideoFrameImpl() override;
@@ -61,7 +55,6 @@
   void SetTimestamp(int64_t timestamp) final;
   int64_t Timestamp() const final;
 
-#if !defined(USE_PPAPI_CDM_ADAPTER)
   // Create a media::VideoFrame based on the data contained in this object.
   // |natural_size| is the visible portion of the video frame, and is
   // provided separately as it comes from the configuration, not the CDM.
@@ -73,7 +66,6 @@
   // - |frame_buffer_| will be NULL (now owned by returned media::VideoFrame).
   virtual scoped_refptr<media::VideoFrame> TransformToVideoFrame(
       gfx::Size natural_size) = 0;
-#endif
 
  protected:
   // The video buffer format.
diff --git a/media/cdm/cdm_wrapper.h b/media/cdm/cdm_wrapper.h
index d879fa4..1d35d81 100644
--- a/media/cdm/cdm_wrapper.h
+++ b/media/cdm/cdm_wrapper.h
@@ -10,32 +10,19 @@
 #include <string>
 
 #include "base/compiler_specific.h"
-#include "base/macros.h"
-#include "media/cdm/api/content_decryption_module.h"
-#include "media/cdm/supported_cdm_versions.h"
-
-#if defined(USE_PPAPI_CDM_ADAPTER)
-// When building the ppapi adapter do not include any non-trivial base/ headers.
-#include "ppapi/cpp/logging.h"  // nogncheck
-#define PLATFORM_DCHECK PP_DCHECK
-#else
 #include "base/feature_list.h"
 #include "base/logging.h"
-#include "media/base/media_switches.h"  // nogncheck
-#define PLATFORM_DCHECK DCHECK
-#endif
+#include "base/macros.h"
+#include "media/base/media_switches.h"
+#include "media/cdm/api/content_decryption_module.h"
+#include "media/cdm/supported_cdm_versions.h"
 
 namespace media {
 
 namespace {
 
 bool IsExperimentalCdmInterfaceSupported() {
-#if defined(USE_PPAPI_CDM_ADAPTER)
-  // No new CDM interface will be supported using pepper CDM.
-  return false;
-#else
   return base::FeatureList::IsEnabled(media::kSupportExperimentalCdmInterface);
-#endif
 }
 
 bool IsEncryptionSchemeSupportedByLegacyCdms(
@@ -322,7 +309,7 @@
   }
 
  private:
-  CdmWrapperImpl(CdmInterface* cdm) : cdm_(cdm) { PLATFORM_DCHECK(cdm_); }
+  CdmWrapperImpl(CdmInterface* cdm) : cdm_(cdm) { DCHECK(cdm_); }
 
   CdmInterface* cdm_;
 
@@ -505,14 +492,13 @@
   // TODO(xhwang): Static assert these at compile time.
   const int kMinVersion = cdm::ContentDecryptionModule_8::kVersion;
   const int kMaxVersion = cdm::ContentDecryptionModule_10::kVersion;
-  PLATFORM_DCHECK(!IsSupportedCdmInterfaceVersion(kMinVersion - 1));
+  DCHECK(!IsSupportedCdmInterfaceVersion(kMinVersion - 1));
   for (int version = kMinVersion; version <= kMaxVersion; ++version)
-    PLATFORM_DCHECK(IsSupportedCdmInterfaceVersion(version));
-  PLATFORM_DCHECK(!IsSupportedCdmInterfaceVersion(kMaxVersion + 1));
+    DCHECK(IsSupportedCdmInterfaceVersion(version));
+  DCHECK(!IsSupportedCdmInterfaceVersion(kMaxVersion + 1));
 
   // Try to create the CDM using the latest CDM interface version.
-  // This is only attempted if requested. For pepper plugins, this is done
-  // at compile time. For mojo, it is done using a media feature setting.
+  // This is only attempted if requested.
   CdmWrapper* cdm_wrapper = nullptr;
 
   // TODO(xhwang): Check whether we can use static loops to simplify this code.
@@ -551,6 +537,4 @@
 
 }  // namespace media
 
-#undef PLATFORM_DCHECK
-
 #endif  // MEDIA_CDM_CDM_WRAPPER_H_
diff --git a/media/cdm/library_cdm/DEPS b/media/cdm/library_cdm/DEPS
deleted file mode 100644
index d8abde77..0000000
--- a/media/cdm/library_cdm/DEPS
+++ /dev/null
@@ -1,7 +0,0 @@
-# Since media/ does not depend on anything in media/cdm/library_cdm/, these
-# extra dependencies are okay.
-include_rules = [
-  "+ppapi/c",
-  "+ppapi/cpp",
-  "+ppapi/utility",
-]
diff --git a/media/cdm/library_cdm/cdm_file_io_impl.cc b/media/cdm/library_cdm/cdm_file_io_impl.cc
deleted file mode 100644
index 71a013b..0000000
--- a/media/cdm/library_cdm/cdm_file_io_impl.cc
+++ /dev/null
@@ -1,566 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "media/cdm/library_cdm/cdm_file_io_impl.h"
-
-#include <sstream>
-
-#include "media/cdm/library_cdm/cdm_logging.h"
-#include "ppapi/c/pp_errors.h"
-#include "ppapi/cpp/dev/url_util_dev.h"
-
-namespace media {
-
-// Arbitrary choice based on the following heuristic ideas:
-// - not too big to avoid unnecessarily large memory allocation;
-// - not too small to avoid breaking most reads into multiple read operations.
-const int kReadSize = 8 * 1024;
-
-// Maximum length of a file name.
-const size_t kFileNameMaxLength = 256;
-
-// Call func_call and check the result. If the result is not
-// PP_OK_COMPLETIONPENDING, print out logs, call OnError() and return.
-#define CHECK_PP_OK_COMPLETIONPENDING(func_call, error_type)         \
-  do {                                                               \
-    int32_t result = func_call;                                      \
-    PP_DCHECK(result != PP_OK);                                      \
-    if (result != PP_OK_COMPLETIONPENDING) {                         \
-      CDM_DLOG() << #func_call << " failed with result: " << result; \
-      state_ = STATE_ERROR;                                          \
-      OnError(error_type);                                           \
-      return;                                                        \
-    }                                                                \
-  } while (0)
-
-#if !defined(NDEBUG)
-// PPAPI calls should only be made on the main thread. In this file, main thread
-// checking is only performed in public APIs and the completion callbacks. This
-// ensures all functions are running on the main thread since internal methods
-// are called either by the public APIs or by the completion callbacks.
-static bool IsMainThread() {
-  return pp::Module::Get()->core()->IsMainThread();
-}
-#endif  // !defined(NDEBUG)
-
-// Posts a task to run |cb| on the main thread. The task is posted even if the
-// current thread is the main thread.
-static void PostOnMain(pp::CompletionCallback cb) {
-  pp::Module::Get()->core()->CallOnMainThread(0, cb, PP_OK);
-}
-
-// As this is part of pepper, don't use base::string_utils.
-static bool IsLetter(char c) {
-  return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z');
-}
-
-static bool IsDigit(char c) {
-  return c >= '0' && c <= '9';
-}
-
-// File names must only contain letters (A-Za-z), digits(0-9), or "._-",
-// and not start with "_". It must contain at least 1 character, and not
-// more then |kFileNameMaxLength| characters.
-static bool IsValidFileName(const std::string& name) {
-  if (name.empty() || name.length() > kFileNameMaxLength || name[0] == '_')
-    return false;
-
-  for (auto ch : name) {
-    if (!IsLetter(ch) && !IsDigit(ch) && ch != '.' && ch != '_' && ch != '-') {
-      return false;
-    }
-  }
-
-  return true;
-}
-
-CdmFileIOImpl::FileLockMap* CdmFileIOImpl::file_lock_map_ = NULL;
-
-CdmFileIOImpl::ResourceTracker::ResourceTracker() {
-  // Do nothing here since we lazy-initialize CdmFileIOImpl::file_lock_map_
-  // in CdmFileIOImpl::AcquireFileLock().
-}
-
-CdmFileIOImpl::ResourceTracker::~ResourceTracker() {
-  delete CdmFileIOImpl::file_lock_map_;
-}
-
-CdmFileIOImpl::CdmFileIOImpl(cdm::FileIOClient* client,
-                             PP_Instance pp_instance,
-                             const pp::CompletionCallback& first_file_read_cb)
-    : state_(STATE_UNOPENED),
-      client_(client),
-      pp_instance_handle_(pp_instance),
-      io_offset_(0),
-      first_file_read_reported_(false),
-      first_file_read_cb_(first_file_read_cb),
-      callback_factory_(this) {
-  PP_DCHECK(IsMainThread());
-  PP_DCHECK(pp_instance);  // 0 indicates a "NULL handle".
-}
-
-CdmFileIOImpl::~CdmFileIOImpl() {
-  // The destructor is private. |this| can only be destructed through Close().
-  PP_DCHECK(state_ == STATE_CLOSED);
-}
-
-// Call sequence: Open() -> OpenFileSystem() -> STATE_FILE_SYSTEM_OPENED.
-// Note: This only stores file name and opens the file system. The real file
-// open is deferred to when Read() or Write() is called.
-void CdmFileIOImpl::Open(const char* file_name, uint32_t file_name_size) {
-  CDM_DLOG() << __func__ << " " << std::string(file_name, file_name_size);
-  PP_DCHECK(IsMainThread());
-
-  if (state_ != STATE_UNOPENED) {
-    CDM_DLOG() << "Open() called in an invalid state.";
-    OnError(OPEN_ERROR);
-    return;
-  }
-
-  std::string file_name_str(file_name, file_name_size);
-  if (!IsValidFileName(file_name_str)) {
-    CDM_DLOG() << "Invalid file name.";
-    state_ = STATE_ERROR;
-    OnError(OPEN_ERROR);
-    return;
-  }
-
-  // pp::FileRef only accepts path that begins with a '/' character.
-  file_name_ = '/' + file_name_str;
-
-  if (!AcquireFileLock()) {
-    CDM_DLOG() << "File is in use by other cdm::FileIO objects.";
-    OnError(OPEN_WHILE_IN_USE);
-    return;
-  }
-
-  state_ = STATE_OPENING_FILE_SYSTEM;
-  OpenFileSystem();
-}
-
-// Call sequence:
-// Read() -> OpenFileForRead() -> ReadFile() -> Done.
-void CdmFileIOImpl::Read() {
-  CDM_DLOG() << __func__;
-  PP_DCHECK(IsMainThread());
-
-  if (state_ == STATE_READING || state_ == STATE_WRITING) {
-    CDM_DLOG() << "Read() called during pending read/write.";
-    OnError(READ_WHILE_IN_USE);
-    return;
-  }
-
-  if (state_ != STATE_FILE_SYSTEM_OPENED) {
-    CDM_DLOG() << "Read() called in an invalid state.";
-    OnError(READ_ERROR);
-    return;
-  }
-
-  PP_DCHECK(io_offset_ == 0);
-  PP_DCHECK(io_buffer_.empty());
-  PP_DCHECK(cumulative_read_buffer_.empty());
-  io_buffer_.resize(kReadSize);
-  io_offset_ = 0;
-
-  state_ = STATE_READING;
-  OpenFileForRead();
-}
-
-// Call sequence:
-// Write() -> OpenTempFileForWrite() -> WriteTempFile() -> RenameTempFile().
-// The file name of the temporary file is /_<requested_file_name>.
-void CdmFileIOImpl::Write(const uint8_t* data, uint32_t data_size) {
-  CDM_DLOG() << __func__ << ": size = " << data_size;
-  PP_DCHECK(IsMainThread());
-
-  if (state_ == STATE_READING || state_ == STATE_WRITING) {
-    CDM_DLOG() << "Write() called during pending read/write.";
-    OnError(WRITE_WHILE_IN_USE);
-    return;
-  }
-
-  if (state_ != STATE_FILE_SYSTEM_OPENED) {
-    CDM_DLOG() << "Write() called in an invalid state.";
-    OnError(WRITE_ERROR);
-    return;
-  }
-
-  PP_DCHECK(io_offset_ == 0);
-  PP_DCHECK(io_buffer_.empty());
-  if (data_size > 0)
-    io_buffer_.assign(data, data + data_size);
-  else
-    PP_DCHECK(!data);
-
-  state_ = STATE_WRITING;
-  OpenTempFileForWrite();
-}
-
-void CdmFileIOImpl::Close() {
-  CDM_DLOG() << __func__;
-  PP_DCHECK(IsMainThread());
-  PP_DCHECK(state_ != STATE_CLOSED);
-  Reset();
-  state_ = STATE_CLOSED;
-  ReleaseFileLock();
-  // All pending callbacks are canceled since |callback_factory_| is destroyed.
-  delete this;
-}
-
-bool CdmFileIOImpl::SetFileID() {
-  PP_DCHECK(file_id_.empty());
-  PP_DCHECK(!file_name_.empty() && file_name_[0] == '/');
-
-  // Not taking ownership of |url_util_dev| (which is a singleton).
-  const pp::URLUtil_Dev* url_util_dev = pp::URLUtil_Dev::Get();
-  PP_URLComponents_Dev components;
-  pp::Var url_var =
-      url_util_dev->GetDocumentURL(pp_instance_handle_, &components);
-  if (!url_var.is_string())
-    return false;
-  std::string url = url_var.AsString();
-
-  file_id_.append(url, components.scheme.begin, components.scheme.len);
-  file_id_ += ':';
-  file_id_.append(url, components.host.begin, components.host.len);
-  file_id_ += ':';
-  file_id_.append(url, components.port.begin, components.port.len);
-  file_id_ += file_name_;
-
-  return true;
-}
-
-bool CdmFileIOImpl::AcquireFileLock() {
-  PP_DCHECK(IsMainThread());
-
-  if (file_id_.empty() && !SetFileID())
-    return false;
-
-  if (!file_lock_map_) {
-    file_lock_map_ = new FileLockMap();
-  } else {
-    FileLockMap::iterator found = file_lock_map_->find(file_id_);
-    if (found != file_lock_map_->end() && found->second)
-      return false;
-  }
-
-  (*file_lock_map_)[file_id_] = true;
-  return true;
-}
-
-void CdmFileIOImpl::ReleaseFileLock() {
-  PP_DCHECK(IsMainThread());
-
-  if (!file_lock_map_)
-    return;
-
-  FileLockMap::iterator found = file_lock_map_->find(file_id_);
-  if (found != file_lock_map_->end() && found->second)
-    found->second = false;
-}
-
-void CdmFileIOImpl::OpenFileSystem() {
-  PP_DCHECK(state_ == STATE_OPENING_FILE_SYSTEM);
-
-  pp::CompletionCallbackWithOutput<pp::FileSystem> cb =
-      callback_factory_.NewCallbackWithOutput(
-          &CdmFileIOImpl::OnFileSystemOpened);
-  isolated_file_system_ = pp::IsolatedFileSystemPrivate(
-      pp_instance_handle_, PP_ISOLATEDFILESYSTEMTYPE_PRIVATE_PLUGINPRIVATE);
-
-  CHECK_PP_OK_COMPLETIONPENDING(isolated_file_system_.Open(cb), OPEN_ERROR);
-}
-
-void CdmFileIOImpl::OnFileSystemOpened(int32_t result,
-                                       pp::FileSystem file_system) {
-  PP_DCHECK(IsMainThread());
-  PP_DCHECK(state_ == STATE_OPENING_FILE_SYSTEM);
-
-  if (result != PP_OK) {
-    CDM_DLOG() << "File system open failed asynchronously.";
-    ReleaseFileLock();
-    state_ = STATE_ERROR;
-    OnError(OPEN_ERROR);
-    return;
-  }
-
-  file_system_ = file_system;
-
-  state_ = STATE_FILE_SYSTEM_OPENED;
-  client_->OnOpenComplete(cdm::FileIOClient::kSuccess);
-}
-
-void CdmFileIOImpl::OpenFileForRead() {
-  PP_DCHECK(state_ == STATE_READING);
-
-  PP_DCHECK(file_io_.is_null());
-  PP_DCHECK(file_ref_.is_null());
-  file_io_ = pp::FileIO(pp_instance_handle_);
-  file_ref_ = pp::FileRef(file_system_, file_name_.c_str());
-
-  // Open file for read. If file doesn't exist, PP_ERROR_FILENOTFOUND will be
-  // returned.
-  int32_t file_open_flag = PP_FILEOPENFLAG_READ;
-
-  pp::CompletionCallback cb =
-      callback_factory_.NewCallback(&CdmFileIOImpl::OnFileOpenedForRead);
-  CHECK_PP_OK_COMPLETIONPENDING(file_io_.Open(file_ref_, file_open_flag, cb),
-                                READ_ERROR);
-}
-
-void CdmFileIOImpl::OnFileOpenedForRead(int32_t result) {
-  CDM_DLOG() << __func__ << ": result = " << result;
-  PP_DCHECK(IsMainThread());
-  PP_DCHECK(state_ == STATE_READING);
-
-  if (result != PP_OK && result != PP_ERROR_FILENOTFOUND) {
-    CDM_DLOG() << "File open failed.";
-    state_ = STATE_ERROR;
-    OnError(OPEN_ERROR);
-    return;
-  }
-
-  // File doesn't exist.
-  if (result == PP_ERROR_FILENOTFOUND) {
-    Reset();
-    state_ = STATE_FILE_SYSTEM_OPENED;
-    client_->OnReadComplete(cdm::FileIOClient::kSuccess, NULL, 0);
-    return;
-  }
-
-  ReadFile();
-}
-
-// Call sequence:
-//                               fully read
-// ReadFile() ---> OnFileRead() ------------> Done.
-//     ^                |
-//     | partially read |
-//     |----------------|
-void CdmFileIOImpl::ReadFile() {
-  PP_DCHECK(state_ == STATE_READING);
-  PP_DCHECK(!io_buffer_.empty());
-
-  pp::CompletionCallback cb =
-      callback_factory_.NewCallback(&CdmFileIOImpl::OnFileRead);
-  CHECK_PP_OK_COMPLETIONPENDING(
-      file_io_.Read(io_offset_, &io_buffer_[0], io_buffer_.size(), cb),
-      READ_ERROR);
-}
-
-void CdmFileIOImpl::OnFileRead(int32_t bytes_read) {
-  CDM_DLOG() << __func__ << ": bytes_read = " << bytes_read;
-  PP_DCHECK(IsMainThread());
-  PP_DCHECK(state_ == STATE_READING);
-
-  // 0 |bytes_read| indicates end-of-file reached.
-  if (bytes_read < PP_OK) {
-    CDM_DLOG() << "Read file failed.";
-    state_ = STATE_ERROR;
-    OnError(READ_ERROR);
-    return;
-  }
-
-  PP_DCHECK(static_cast<size_t>(bytes_read) <= io_buffer_.size());
-  // Append |bytes_read| in |io_buffer_| to |cumulative_read_buffer_|.
-  cumulative_read_buffer_.insert(cumulative_read_buffer_.end(),
-                                 io_buffer_.begin(),
-                                 io_buffer_.begin() + bytes_read);
-  io_offset_ += bytes_read;
-
-  // Not received end-of-file yet. Keep reading.
-  if (bytes_read > 0) {
-    ReadFile();
-    return;
-  }
-
-  // We hit end-of-file. Return read data to the client.
-
-  // Clear |cumulative_read_buffer_| in case OnReadComplete() calls Read() or
-  // Write().
-  std::vector<char> local_buffer;
-  std::swap(cumulative_read_buffer_, local_buffer);
-
-  const uint8_t* data =
-      local_buffer.empty() ? NULL
-                           : reinterpret_cast<const uint8_t*>(&local_buffer[0]);
-
-  // Call this before OnReadComplete() so that we always have the latest file
-  // size before CDM fires errors.
-  if (!first_file_read_reported_) {
-    first_file_read_cb_.Run(local_buffer.size());
-    first_file_read_reported_ = true;
-  }
-
-  Reset();
-
-  state_ = STATE_FILE_SYSTEM_OPENED;
-  client_->OnReadComplete(cdm::FileIOClient::kSuccess, data,
-                          local_buffer.size());
-}
-
-void CdmFileIOImpl::OpenTempFileForWrite() {
-  PP_DCHECK(state_ == STATE_WRITING);
-
-  PP_DCHECK(file_name_.size() > 1 && file_name_[0] == '/');
-  // Temporary file name format: /_<requested_file_name>
-  std::string temp_file_name = "/_" + file_name_.substr(1);
-
-  PP_DCHECK(file_io_.is_null());
-  PP_DCHECK(file_ref_.is_null());
-  file_io_ = pp::FileIO(pp_instance_handle_);
-  file_ref_ = pp::FileRef(file_system_, temp_file_name.c_str());
-
-  // Create the file if it doesn't exist. Truncate the file to length 0 if it
-  // exists.
-  // TODO(xhwang): Find a good way to report to UMA cases where the temporary
-  // file already exists (due to previous interruption or failure).
-  int32_t file_open_flag =
-      PP_FILEOPENFLAG_WRITE | PP_FILEOPENFLAG_TRUNCATE | PP_FILEOPENFLAG_CREATE;
-
-  pp::CompletionCallback cb =
-      callback_factory_.NewCallback(&CdmFileIOImpl::OnTempFileOpenedForWrite);
-  CHECK_PP_OK_COMPLETIONPENDING(file_io_.Open(file_ref_, file_open_flag, cb),
-                                WRITE_ERROR);
-}
-
-void CdmFileIOImpl::OnTempFileOpenedForWrite(int32_t result) {
-  CDM_DLOG() << __func__ << ": result = " << result;
-  PP_DCHECK(IsMainThread());
-  PP_DCHECK(state_ == STATE_WRITING);
-
-  if (result != PP_OK) {
-    CDM_DLOG() << "Open temporary file failed.";
-    state_ = STATE_ERROR;
-    OnError(WRITE_ERROR);
-    return;
-  }
-
-  // We were told to write 0 bytes (to clear the file). In this case, there's
-  // no need to write anything.
-  if (io_buffer_.empty()) {
-    RenameTempFile();
-    return;
-  }
-
-  PP_DCHECK(io_offset_ == 0);
-  io_offset_ = 0;
-  WriteTempFile();
-}
-
-// Call sequence:
-//                                         fully written
-// WriteTempFile() -> OnTempFileWritten() ---------------> RenameTempFile().
-//      ^                     |
-//      |  partially written  |
-//      |---------------------|
-void CdmFileIOImpl::WriteTempFile() {
-  PP_DCHECK(state_ == STATE_WRITING);
-  PP_DCHECK(io_offset_ < io_buffer_.size());
-
-  pp::CompletionCallback cb =
-      callback_factory_.NewCallback(&CdmFileIOImpl::OnTempFileWritten);
-  CHECK_PP_OK_COMPLETIONPENDING(
-      file_io_.Write(io_offset_, &io_buffer_[io_offset_],
-                     io_buffer_.size() - io_offset_, cb),
-      WRITE_ERROR);
-}
-
-void CdmFileIOImpl::OnTempFileWritten(int32_t bytes_written) {
-  CDM_DLOG() << __func__ << ": bytes_written = " << bytes_written;
-  PP_DCHECK(IsMainThread());
-  PP_DCHECK(state_ == STATE_WRITING);
-
-  if (bytes_written <= PP_OK) {
-    CDM_DLOG() << "Write temporary file failed.";
-    state_ = STATE_ERROR;
-    OnError(WRITE_ERROR);
-    return;
-  }
-
-  io_offset_ += bytes_written;
-  PP_DCHECK(io_offset_ <= io_buffer_.size());
-
-  if (io_offset_ < io_buffer_.size()) {
-    WriteTempFile();
-    return;
-  }
-
-  // All data written. Now rename the temporary file to the real file.
-  RenameTempFile();
-}
-
-void CdmFileIOImpl::RenameTempFile() {
-  PP_DCHECK(state_ == STATE_WRITING);
-
-  pp::CompletionCallback cb =
-      callback_factory_.NewCallback(&CdmFileIOImpl::OnTempFileRenamed);
-  CHECK_PP_OK_COMPLETIONPENDING(
-      file_ref_.Rename(pp::FileRef(file_system_, file_name_.c_str()), cb),
-      WRITE_ERROR);
-}
-
-void CdmFileIOImpl::OnTempFileRenamed(int32_t result) {
-  CDM_DLOG() << __func__ << ": result = " << result;
-  PP_DCHECK(IsMainThread());
-  PP_DCHECK(state_ == STATE_WRITING);
-
-  if (result != PP_OK) {
-    CDM_DLOG() << "Rename temporary file failed.";
-    state_ = STATE_ERROR;
-    OnError(WRITE_ERROR);
-    return;
-  }
-
-  Reset();
-
-  state_ = STATE_FILE_SYSTEM_OPENED;
-  client_->OnWriteComplete(cdm::FileIOClient::kSuccess);
-}
-
-void CdmFileIOImpl::Reset() {
-  PP_DCHECK(IsMainThread());
-  io_buffer_.clear();
-  io_offset_ = 0;
-  cumulative_read_buffer_.clear();
-  file_io_.Close();
-  file_io_ = pp::FileIO();
-  file_ref_ = pp::FileRef();
-}
-
-void CdmFileIOImpl::OnError(ErrorType error_type) {
-  // For *_WHILE_IN_USE errors, do not reset these values. Otherwise, the
-  // existing read/write operation will fail.
-  if (error_type == READ_ERROR || error_type == WRITE_ERROR)
-    Reset();
-
-  PostOnMain(callback_factory_.NewCallback(&CdmFileIOImpl::NotifyClientOfError,
-                                           error_type));
-}
-
-void CdmFileIOImpl::NotifyClientOfError(int32_t result, ErrorType error_type) {
-  PP_DCHECK(result == PP_OK);
-  switch (error_type) {
-    case OPEN_ERROR:
-      client_->OnOpenComplete(cdm::FileIOClient::kError);
-      break;
-    case READ_ERROR:
-      client_->OnReadComplete(cdm::FileIOClient::kError, NULL, 0);
-      break;
-    case WRITE_ERROR:
-      client_->OnWriteComplete(cdm::FileIOClient::kError);
-      break;
-    case OPEN_WHILE_IN_USE:
-      client_->OnOpenComplete(cdm::FileIOClient::kInUse);
-      break;
-    case READ_WHILE_IN_USE:
-      client_->OnReadComplete(cdm::FileIOClient::kInUse, NULL, 0);
-      break;
-    case WRITE_WHILE_IN_USE:
-      client_->OnWriteComplete(cdm::FileIOClient::kInUse);
-      break;
-  }
-}
-
-}  // namespace media
diff --git a/media/cdm/library_cdm/cdm_file_io_impl.h b/media/cdm/library_cdm/cdm_file_io_impl.h
deleted file mode 100644
index ca7e88c..0000000
--- a/media/cdm/library_cdm/cdm_file_io_impl.h
+++ /dev/null
@@ -1,216 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MEDIA_CDM_LIBRARY_CDM_CDM_FILE_IO_IMPL_H_
-#define MEDIA_CDM_LIBRARY_CDM_CDM_FILE_IO_IMPL_H_
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <algorithm>
-#include <string>
-#include <vector>
-
-#include "base/macros.h"
-#include "media/cdm/api/content_decryption_module.h"
-#include "ppapi/c/ppb_file_io.h"
-#include "ppapi/cpp/file_io.h"
-#include "ppapi/cpp/file_ref.h"
-#include "ppapi/cpp/instance.h"
-#include "ppapi/cpp/module.h"
-#include "ppapi/cpp/private/isolated_file_system_private.h"
-#include "ppapi/utility/completion_callback_factory.h"
-
-namespace media {
-
-// Due to PPAPI limitations, all functions must be called on the main thread.
-//
-// Implementation notes about states:
-// 1, When a method is called in an invalid state (e.g. Read() before Open() is
-//    called, Write() before Open() finishes or Open() after Open()), kError
-//    will be returned. The state of |this| will not change.
-// 2, When the file is opened by another CDM instance, or when we call Read()/
-//    Write() during a pending Read()/Write(), kInUse will be returned. The
-//    state of |this| will not change.
-// 3, When a pepper operation failed (either synchronously or asynchronously),
-//    kError will be returned. The state of |this| will be set to ERROR.
-// 4. Any operation in ERROR state will end up with kError.
-class CdmFileIOImpl : public cdm::FileIO {
- public:
-  // A class that helps release |file_lock_map_|.
-  // There should be only one instance of ResourceTracker in a process. Also,
-  // ResourceTracker should outlive all CdmFileIOImpl instances.
-  class ResourceTracker {
-   public:
-    ResourceTracker();
-    ~ResourceTracker();
-
-   private:
-    DISALLOW_COPY_AND_ASSIGN(ResourceTracker);
-  };
-
-  // After the first successful file read, call |first_file_read_cb| to report
-  // the file size. |first_file_read_cb| takes one parameter: the file size in
-  // bytes.
-  CdmFileIOImpl(cdm::FileIOClient* client,
-                PP_Instance pp_instance,
-                const pp::CompletionCallback& first_file_read_cb);
-
-  // cdm::FileIO implementation.
-  void Open(const char* file_name, uint32_t file_name_size) override;
-  void Read() override;
-  void Write(const uint8_t* data, uint32_t data_size) override;
-  void Close() override;
-
- private:
-  // TODO(xhwang): Introduce more detailed states for UMA logging if needed.
-  enum State {
-    STATE_UNOPENED,
-    STATE_OPENING_FILE_SYSTEM,
-    STATE_FILE_SYSTEM_OPENED,
-    STATE_READING,
-    STATE_WRITING,
-    STATE_CLOSED,
-    STATE_ERROR
-  };
-
-  enum ErrorType {
-    OPEN_WHILE_IN_USE,
-    READ_WHILE_IN_USE,
-    WRITE_WHILE_IN_USE,
-    OPEN_ERROR,
-    READ_ERROR,
-    WRITE_ERROR
-  };
-
-  // Always use Close() to release |this| object.
-  ~CdmFileIOImpl() override;
-
-  // |file_id_| -> |is_file_lock_acquired_| map.
-  // Design detail:
-  // - We never erase an entry from this map.
-  // - Pros: When the same file is read or written repeatedly, we don't need to
-  //   insert/erase the entry repeatedly, which is expensive.
-  // - Cons: If there are a lot of one-off files used, this map will be
-  //   unnecessarily large. But this should be a rare case.
-  // - Ideally we could use unordered_map for this. But unordered_set is only
-  //   available in C++11.
-  typedef std::map<std::string, bool> FileLockMap;
-
-  // File lock map shared by all CdmFileIOImpl objects to prevent read/write
-  // race. A CdmFileIOImpl object tries to acquire a lock before opening a
-  // file. If the file open failed, the lock is released. Otherwise, the
-  // CdmFileIOImpl object holds the lock until Close() is called.
-  // TODO(xhwang): Investigate the following cases and make sure we are good:
-  // - This assumes all CDM instances run in the same process for a given file
-  //   system.
-  // - When multiple CDM instances are running in different profiles (e.g.
-  //   normal/incognito window, multiple profiles), we may be overlocking.
-  static FileLockMap* file_lock_map_;
-
-  // Sets |file_id_|. Returns false if |file_id_| cannot be set (e.g. origin URL
-  // cannot be fetched).
-  bool SetFileID();
-
-  // Acquires the file lock. Returns true if the lock is successfully acquired.
-  // After the lock is acquired, other cdm::FileIO objects in the same process
-  // and in the same origin will get kInUse when trying to open the same file.
-  bool AcquireFileLock();
-
-  // Releases the file lock so that the file can be opened by other cdm::FileIO
-  // objects.
-  void ReleaseFileLock();
-
-  // Helper functions for Open().
-  void OpenFileSystem();
-  void OnFileSystemOpened(int32_t result, pp::FileSystem file_system);
-
-  // Helper functions for Read().
-  void OpenFileForRead();
-  void OnFileOpenedForRead(int32_t result);
-  void ReadFile();
-  void OnFileRead(int32_t bytes_read);
-
-  // Helper functions for Write(). We always write data to a temporary file,
-  // then rename the temporary file to the target file. This can prevent data
-  // corruption if |this| is Close()'ed while waiting for writing to complete.
-  // However, if Close() is called after OpenTempFileForWrite() but before
-  // RenameTempFile(), we may still end up with an empty, partially written or
-  // fully written temporary file in the file system. This temporary file will
-  // be truncated next time OpenTempFileForWrite() is called.
-
-  void OpenTempFileForWrite();
-  void OnTempFileOpenedForWrite(int32_t result);
-  void WriteTempFile();
-  void OnTempFileWritten(int32_t bytes_written);
-  // Note: pp::FileRef::Rename() actually does a "move": if the target file
-  // exists, Rename() will succeed and the target file will be overwritten.
-  // See PepperInternalFileRefBackend::Rename() for implementation detail.
-  void RenameTempFile();
-  void OnTempFileRenamed(int32_t result);
-
-  // Reset |this| to a clean state.
-  void Reset();
-
-  // For real open/read/write errors, Reset() and set the |state_| to ERROR.
-  // Calls client_->OnXxxxComplete with kError or kInUse asynchronously. In some
-  // cases we could actually call them synchronously, but since these errors
-  // shouldn't happen in normal cases, we are not optimizing such cases.
-  void OnError(ErrorType error_type);
-
-  // Callback to notify client of error asynchronously.
-  void NotifyClientOfError(int32_t result, ErrorType error_type);
-
-  State state_;
-
-  // Non-owning pointer.
-  cdm::FileIOClient* const client_;
-
-  const pp::InstanceHandle pp_instance_handle_;
-
-  // Format: /<requested_file_name>
-  std::string file_name_;
-
-  // A string ID that uniquely identifies a file in the user's profile.
-  // It consists of the origin of the document URL (including scheme, host and
-  // port, delimited by colons) and the |file_name_|.
-  // For example: http:example.com:8080/foo_file.txt
-  std::string file_id_;
-
-  pp::IsolatedFileSystemPrivate isolated_file_system_;
-  pp::FileSystem file_system_;
-
-  // Shared between read and write. During read, |file_ref_| refers to the real
-  // file to read data from. During write, it refers to the temporary file to
-  // write data into.
-  pp::FileIO file_io_;
-  pp::FileRef file_ref_;
-
-  // A temporary buffer to hold (partial) data to write or the data that has
-  // been read. The size of |io_buffer_| is always "bytes to write" or "bytes to
-  // read". Use "char" instead of "unit8_t" because PPB_FileIO uses char* for
-  // binary data read and write.
-  std::vector<char> io_buffer_;
-
-  // Offset into the file for reading/writing data. When writing data to the
-  // file, this is also the offset to the |io_buffer_|.
-  size_t io_offset_;
-
-  // Buffer to hold all read data requested. This buffer is passed to |client_|
-  // when read completes.
-  std::vector<char> cumulative_read_buffer_;
-
-  bool first_file_read_reported_;
-
-  // Callback to report the file size in bytes after the first successful read.
-  pp::CompletionCallback first_file_read_cb_;
-
-  pp::CompletionCallbackFactory<CdmFileIOImpl> callback_factory_;
-
-  DISALLOW_COPY_AND_ASSIGN(CdmFileIOImpl);
-};
-
-}  // namespace media
-
-#endif  // MEDIA_CDM_LIBRARY_CDM_CDM_FILE_IO_IMPL_H_
diff --git a/media/cdm/library_cdm/cdm_logging.cc b/media/cdm/library_cdm/cdm_logging.cc
deleted file mode 100644
index 7c5ccdc3..0000000
--- a/media/cdm/library_cdm/cdm_logging.cc
+++ /dev/null
@@ -1,140 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// Only compile this file in debug build. This gives us one more level of
-// protection that if the linker tries to link in strings/symbols appended to
-// "DLOG() <<" in release build (which it shouldn't), we'll get "undefined
-// reference" errors.
-
-#include "media/cdm/library_cdm/cdm_logging.h"
-
-#include "build/build_config.h"
-
-#if defined(OS_WIN)
-#include <io.h>
-#include <windows.h>
-#elif defined(OS_MACOSX)
-#include <mach-o/dyld.h>
-#include <mach/mach.h>
-#include <mach/mach_time.h>
-#elif defined(OS_POSIX)
-#include <sys/syscall.h>
-#include <time.h>
-#endif
-
-#if defined(OS_POSIX)
-#include <errno.h>
-#include <pthread.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#endif
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <iomanip>
-#include <iostream>
-
-namespace media {
-
-#if !defined(NDEBUG)
-
-namespace {
-
-// Helper functions to wrap platform differences.
-
-int32_t CurrentProcessId() {
-#if defined(OS_WIN)
-  return GetCurrentProcessId();
-#elif defined(OS_POSIX)
-  return getpid();
-#endif
-}
-
-int32_t CurrentThreadId() {
-// Pthreads doesn't have the concept of a thread ID, so we have to reach down
-// into the kernel.
-#if defined(OS_LINUX)
-  return syscall(__NR_gettid);
-#elif defined(OS_ANDROID)
-  return gettid();
-#elif defined(OS_SOLARIS)
-  return pthread_self();
-#elif defined(OS_POSIX)
-  return reinterpret_cast<int64_t>(pthread_self());
-#elif defined(OS_WIN)
-  return static_cast<int32_t>(::GetCurrentThreadId());
-#endif
-}
-
-uint64_t TickCount() {
-#if defined(OS_WIN)
-  return GetTickCount();
-#elif defined(OS_MACOSX)
-  return mach_absolute_time();
-#elif defined(OS_POSIX)
-  struct timespec ts;
-  clock_gettime(CLOCK_MONOTONIC, &ts);
-
-  uint64_t absolute_micro = static_cast<int64_t>(ts.tv_sec) * 1000000 +
-                            static_cast<int64_t>(ts.tv_nsec) / 1000;
-
-  return absolute_micro;
-#endif
-}
-
-}  // namespace
-
-CdmLogMessage::CdmLogMessage(const char* file, int line) {
-  std::string filename(file);
-  size_t last_slash_pos = filename.find_last_of("\\/");
-  if (last_slash_pos != std::string::npos)
-    filename = filename.substr(last_slash_pos + 1);
-
-  stream_ << '[';
-
-  // Process and thread ID.
-  stream_ << CurrentProcessId() << ':';
-  stream_ << CurrentThreadId() << ':';
-
-  // Time and tick count.
-  time_t t = time(NULL);
-  struct tm local_time = {0};
-#ifdef _MSC_VER
-  localtime_s(&local_time, &t);
-#else
-  localtime_r(&t, &local_time);
-#endif
-  struct tm* tm_time = &local_time;
-  stream_ << std::setfill('0') << std::setw(2) << 1 + tm_time->tm_mon
-          << std::setw(2) << tm_time->tm_mday << '/' << std::setw(2)
-          << tm_time->tm_hour << std::setw(2) << tm_time->tm_min << std::setw(2)
-          << tm_time->tm_sec << ':';
-  stream_ << TickCount() << ':';
-
-  // File name.
-  stream_ << filename << "(" << line << ")] ";
-}
-
-CdmLogMessage::~CdmLogMessage() {
-  // Use std::cout explicitly for the line break. This limits the use of this
-  // class only to the definition of DLOG() (which also uses std::cout).
-  //
-  // This appends "std::endl" after all other messages appended to DLOG(),
-  // which relies on the C++ standard ISO/IEC 14882:1998(E) $12.2.3:
-  // "Temporary objects are destroyed as the last step in evaluating the
-  // full-expression (1.9) that (lexically) contains the point where they were
-  // created."
-  std::cout << std::endl;
-}
-
-#endif  // !defined(NDEBUG)
-
-std::ostream& CdmLogStream::stream() {
-  return std::cout;
-}
-
-}  // namespace media
diff --git a/media/cdm/library_cdm/cdm_logging.h b/media/cdm/library_cdm/cdm_logging.h
deleted file mode 100644
index f89042f..0000000
--- a/media/cdm/library_cdm/cdm_logging.h
+++ /dev/null
@@ -1,83 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// This file defines useful logging macros/methods for CDM adapter.
-
-#ifndef MEDIA_CDM_LIBRARY_CDM_CDM_LOGGING_H_
-#define MEDIA_CDM_LIBRARY_CDM_CDM_LOGGING_H_
-
-#include <ostream>
-#include <sstream>
-#include <string>
-
-namespace media {
-
-namespace {
-
-// The following classes/macros are adapted from base/logging.h.
-
-// This class is used to explicitly ignore values in the conditional
-// logging macros.  This avoids compiler warnings like "value computed
-// is not used" and "statement has no effect".
-class LogMessageVoidify {
- public:
-  LogMessageVoidify() {}
-  // This has to be an operator with a precedence lower than << but
-  // higher than ?:
-  void operator&(std::ostream&) {}
-};
-
-}  // namespace
-
-// This class is used to avoid having to include <iostream> in this file.
-class CdmLogStream {
- public:
-  CdmLogStream() {}
-
-  // Retrieves the stream that we write to. This header cannot depend on
-  // <iostream> because that will add static initializers to all files that
-  // include this header. See https://crbug.com/94794.
-  std::ostream& stream();
-};
-
-// This class serves two purposes:
-// (1) It adds common headers to the log message, e.g. timestamp, process ID.
-// (2) It adds a line break at the end of the log message.
-// This class is copied and modified from base/logging.* but is quite different
-// in terms of how things work. This class is designed to work only with the
-// CDM_DLOG() defined below and should not be used for other purposes.
-class CdmLogMessage {
- public:
-  CdmLogMessage(const char* file, int line);
-  ~CdmLogMessage();
-
-  std::string message() { return stream_.str(); }
-
- private:
-  std::ostringstream stream_;
-};
-
-// Helper macro which avoids evaluating the arguments to a stream if
-// the condition doesn't hold.
-#define CDM_LAZY_STREAM(stream, condition) \
-  !(condition) ? (void)0 : LogMessageVoidify() & (stream)
-
-#if defined(NDEBUG)
-// Logging is disabled for the release builds, theoretically the compiler should
-// take care of removing the references to CdmLogMessage but it's not always the
-// case when some specific optimizations are turned on (like PGO). Update the
-// macro to make sure that we don't try to do any logging or to refer to
-// CdmLogMessage in release.
-#define CDM_DLOG_IS_ON() false
-#define CDM_DLOG() CDM_LAZY_STREAM(CdmLogStream().stream(), CDM_DLOG_IS_ON())
-#else
-#define CDM_DLOG_IS_ON() true
-#define CDM_DLOG()                                           \
-  CDM_LAZY_STREAM(CdmLogStream().stream(), CDM_DLOG_IS_ON()) \
-      << CdmLogMessage(__FILE__, __LINE__).message()
-#endif
-
-}  // namespace media
-
-#endif  // MEDIA_CDM_LIBRARY_CDM_CDM_LOGGING_H_
diff --git a/media/cdm/library_cdm/linked_ptr.h b/media/cdm/library_cdm/linked_ptr.h
deleted file mode 100644
index 7bd5fdb..0000000
--- a/media/cdm/library_cdm/linked_ptr.h
+++ /dev/null
@@ -1,192 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-//
-// This is a copy of base/linked_ptr.h with CHECKS/DCHECKS replaced with
-// PP_DCHECKs.
-//
-// A "smart" pointer type with reference tracking.  Every pointer to a
-// particular object is kept on a circular linked list.  When the last pointer
-// to an object is destroyed or reassigned, the object is deleted.
-//
-// Used properly, this deletes the object when the last reference goes away.
-// There are several caveats:
-// - Like all reference counting schemes, cycles lead to leaks.
-// - Each smart pointer is actually two pointers (8 bytes instead of 4).
-// - Every time a pointer is released, the entire list of pointers to that
-//   object is traversed.  This class is therefore NOT SUITABLE when there
-//   will often be more than two or three pointers to a particular object.
-// - References are only tracked as long as linked_ptr<> objects are copied.
-//   If a linked_ptr<> is converted to a raw pointer and back, BAD THINGS
-//   will happen (double deletion).
-//
-// A good use of this class is storing object references in STL containers.
-// You can safely put linked_ptr<> in a vector<>.
-// Other uses may not be as good.
-//
-// Note: If you use an incomplete type with linked_ptr<>, the class
-// *containing* linked_ptr<> must have a constructor and destructor (even
-// if they do nothing!).
-//
-// Thread Safety:
-//   A linked_ptr is NOT thread safe. Copying a linked_ptr object is
-//   effectively a read-write operation.
-//
-// Alternative: to linked_ptr is shared_ptr, which
-//  - is also two pointers in size (8 bytes for 32 bit addresses)
-//  - is thread safe for copying and deletion
-//  - supports weak_ptrs
-
-#ifndef MEDIA_CDM_LIBRARY_CDM_LINKED_PTR_H_
-#define MEDIA_CDM_LIBRARY_CDM_LINKED_PTR_H_
-
-#include "ppapi/cpp/logging.h"
-
-// This is used internally by all instances of linked_ptr<>.  It needs to be
-// a non-template class because different types of linked_ptr<> can refer to
-// the same object (linked_ptr<Superclass>(obj) vs linked_ptr<Subclass>(obj)).
-// So, it needs to be possible for different types of linked_ptr to participate
-// in the same circular linked list, so we need a single class type here.
-//
-// DO NOT USE THIS CLASS DIRECTLY YOURSELF.  Use linked_ptr<T>.
-class linked_ptr_internal {
- public:
-  // Create a new circle that includes only this instance.
-  void join_new() { next_ = this; }
-
-  // Join an existing circle.
-  void join(linked_ptr_internal const* ptr) {
-    next_ = ptr->next_;
-    ptr->next_ = this;
-  }
-
-  // Leave whatever circle we're part of.  Returns true iff we were the
-  // last member of the circle.  Once this is done, you can join() another.
-  bool depart() {
-    if (next_ == this)
-      return true;
-    linked_ptr_internal const* p = next_;
-    while (p->next_ != this)
-      p = p->next_;
-    p->next_ = next_;
-    return false;
-  }
-
- private:
-  mutable linked_ptr_internal const* next_;
-};
-
-template <typename T>
-class linked_ptr {
- public:
-  typedef T element_type;
-
-  // Take over ownership of a raw pointer.  This should happen as soon as
-  // possible after the object is created.
-  explicit linked_ptr(T* ptr = NULL) { capture(ptr); }
-  ~linked_ptr() { depart(); }
-
-  // Copy an existing linked_ptr<>, adding ourselves to the list of references.
-  template <typename U>
-  linked_ptr(linked_ptr<U> const& ptr) {
-    copy(&ptr);
-  }
-
-  linked_ptr(linked_ptr const& ptr) {
-    PP_DCHECK(&ptr != this);
-    copy(&ptr);
-  }
-
-  // Assignment releases the old value and acquires the new.
-  template <typename U>
-  linked_ptr& operator=(linked_ptr<U> const& ptr) {
-    depart();
-    copy(&ptr);
-    return *this;
-  }
-
-  linked_ptr& operator=(linked_ptr const& ptr) {
-    if (&ptr != this) {
-      depart();
-      copy(&ptr);
-    }
-    return *this;
-  }
-
-  // Smart pointer members.
-  void reset(T* ptr = NULL) {
-    depart();
-    capture(ptr);
-  }
-  T* get() const { return value_; }
-  operator T*() const { return value_; }
-  T* operator->() const { return value_; }
-  T& operator*() const { return *value_; }
-  // Release ownership of the pointed object and returns it.
-  // Sole ownership by this linked_ptr object is required.
-  T* release() {
-    bool last = link_.depart();
-    PP_DCHECK(last);
-    (void)last;
-    T* v = value_;
-    value_ = NULL;
-    return v;
-  }
-
-  bool operator==(const T* p) const { return value_ == p; }
-  bool operator!=(const T* p) const { return value_ != p; }
-  template <typename U>
-  bool operator==(linked_ptr<U> const& ptr) const {
-    return value_ == ptr.get();
-  }
-  template <typename U>
-  bool operator!=(linked_ptr<U> const& ptr) const {
-    return value_ != ptr.get();
-  }
-
- private:
-  template <typename U>
-  friend class linked_ptr;
-
-  T* value_;
-  linked_ptr_internal link_;
-
-  void depart() {
-    if (link_.depart())
-      delete value_;
-  }
-
-  void capture(T* ptr) {
-    value_ = ptr;
-    link_.join_new();
-  }
-
-  template <typename U>
-  void copy(linked_ptr<U> const* ptr) {
-    value_ = ptr->get();
-    if (value_)
-      link_.join(&ptr->link_);
-    else
-      link_.join_new();
-  }
-};
-
-template <typename T>
-inline bool operator==(T* ptr, const linked_ptr<T>& x) {
-  return ptr == x.get();
-}
-
-template <typename T>
-inline bool operator!=(T* ptr, const linked_ptr<T>& x) {
-  return ptr != x.get();
-}
-
-// A function to convert T* into linked_ptr<T>
-// Doing e.g. make_linked_ptr(new FooBarBaz<type>(arg)) is a shorter notation
-// for linked_ptr<FooBarBaz<type> >(new FooBarBaz<type>(arg))
-template <typename T>
-linked_ptr<T> make_linked_ptr(T* ptr) {
-  return linked_ptr<T>(ptr);
-}
-
-#endif  // MEDIA_CDM_LIBRARY_CDM_LINKED_PTR_H_
diff --git a/media/cdm/library_cdm/ppapi_cdm_adapter.cc b/media/cdm/library_cdm/ppapi_cdm_adapter.cc
deleted file mode 100644
index a98f515f..0000000
--- a/media/cdm/library_cdm/ppapi_cdm_adapter.cc
+++ /dev/null
@@ -1,1467 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "media/cdm/library_cdm/ppapi_cdm_adapter.h"
-
-#include <string.h>
-
-#include "base/macros.h"
-#include "build/build_config.h"
-#include "media/base/limits.h"
-#include "media/cdm/library_cdm/cdm_file_io_impl.h"
-#include "media/cdm/library_cdm/cdm_logging.h"
-#include "media/cdm/supported_cdm_versions.h"
-#include "ppapi/c/ppb_console.h"
-#include "ppapi/cpp/private/uma_private.h"
-
-#if defined(CHECK_DOCUMENT_URL)
-#include "ppapi/cpp/dev/url_util_dev.h"
-#include "ppapi/cpp/instance_handle.h"
-#endif  // defined(CHECK_DOCUMENT_URL)
-
-namespace {
-
-// Constants for UMA reporting of file size (in KB) via HistogramCustomCounts().
-// Note that the histogram is log-scaled (rather than linear).
-const uint32_t kSizeKBMin = 1;
-const uint32_t kSizeKBMax = 512 * 1024;  // 512MB
-const uint32_t kSizeKBBuckets = 100;
-
-// Only support version 1 of Storage Id. However, the "latest" version can also
-// be requested.
-const uint32_t kRequestLatestStorageIdVersion = 0;
-const uint32_t kCurrentStorageIdVersion = 1;
-
-#if !defined(NDEBUG)
-#define DLOG_TO_CONSOLE(message) LogToConsole(message);
-#else
-#define DLOG_TO_CONSOLE(message) (void)(message);
-#endif
-
-bool IsMainThread() {
-  return pp::Module::Get()->core()->IsMainThread();
-}
-
-// Posts a task to run |cb| on the main thread. The task is posted even if the
-// current thread is the main thread.
-void PostOnMain(pp::CompletionCallback cb) {
-  pp::Module::Get()->core()->CallOnMainThread(0, cb, PP_OK);
-}
-
-// Ensures |cb| is called on the main thread, either because the current thread
-// is the main thread or by posting it to the main thread.
-void CallOnMain(pp::CompletionCallback cb) {
-  // TODO(tomfinegan): This is only necessary because PPAPI doesn't allow calls
-  // off the main thread yet. Remove this once the change lands.
-  if (IsMainThread())
-    cb.Run(PP_OK);
-  else
-    PostOnMain(cb);
-}
-
-// Configures a cdm::InputBuffer_2. |subsamples| must exist as long as
-// |input_buffer| is in use.
-void ConfigureInputBuffer(const pp::Buffer_Dev& encrypted_buffer,
-                          const PP_EncryptedBlockInfo& encrypted_block_info,
-                          std::vector<cdm::SubsampleEntry>* subsamples,
-                          cdm::InputBuffer_2* input_buffer) {
-  PP_DCHECK(subsamples);
-  PP_DCHECK(!encrypted_buffer.is_null());
-
-  input_buffer->data = static_cast<uint8_t*>(encrypted_buffer.data());
-  input_buffer->data_size = encrypted_block_info.data_size;
-  PP_DCHECK(encrypted_buffer.size() >= input_buffer->data_size);
-
-  PP_DCHECK(encrypted_block_info.key_id_size <=
-            arraysize(encrypted_block_info.key_id));
-  input_buffer->key_id_size = encrypted_block_info.key_id_size;
-  input_buffer->key_id =
-      input_buffer->key_id_size > 0 ? encrypted_block_info.key_id : NULL;
-
-  PP_DCHECK(encrypted_block_info.iv_size <= arraysize(encrypted_block_info.iv));
-  input_buffer->iv_size = encrypted_block_info.iv_size;
-  input_buffer->iv =
-      encrypted_block_info.iv_size > 0 ? encrypted_block_info.iv : NULL;
-
-  input_buffer->num_subsamples = encrypted_block_info.num_subsamples;
-  if (encrypted_block_info.num_subsamples > 0) {
-    subsamples->reserve(encrypted_block_info.num_subsamples);
-
-    for (uint32_t i = 0; i < encrypted_block_info.num_subsamples; ++i) {
-      subsamples->push_back({encrypted_block_info.subsamples[i].clear_bytes,
-                             encrypted_block_info.subsamples[i].cipher_bytes});
-    }
-
-    input_buffer->subsamples = &(*subsamples)[0];
-  }
-
-  input_buffer->timestamp = encrypted_block_info.tracking_info.timestamp;
-
-  // Pepper doesn't transfer encryption scheme info. So if |iv| is defined,
-  // the block is encrypted in 'cenc' mode. If not, it's unencrypted.
-  input_buffer->encryption_scheme = (encrypted_block_info.iv_size == 0)
-                                        ? cdm::EncryptionScheme::kUnencrypted
-                                        : cdm::EncryptionScheme::kCenc;
-  input_buffer->pattern = {0, 0};
-}
-
-cdm::HdcpVersion PpHdcpVersionToCdmHdcpVersion(PP_HdcpVersion hdcp_version) {
-  switch (hdcp_version) {
-    case PP_HDCPVERSION_NONE:
-      return cdm::kHdcpVersionNone;
-    case PP_HDCPVERSION_1_0:
-      return cdm::kHdcpVersion1_0;
-    case PP_HDCPVERSION_1_1:
-      return cdm::kHdcpVersion1_1;
-    case PP_HDCPVERSION_1_2:
-      return cdm::kHdcpVersion1_2;
-    case PP_HDCPVERSION_1_3:
-      return cdm::kHdcpVersion1_3;
-    case PP_HDCPVERSION_1_4:
-      return cdm::kHdcpVersion1_4;
-    case PP_HDCPVERSION_2_0:
-      return cdm::kHdcpVersion2_0;
-    case PP_HDCPVERSION_2_1:
-      return cdm::kHdcpVersion2_1;
-    case PP_HDCPVERSION_2_2:
-      return cdm::kHdcpVersion2_2;
-  }
-
-  PP_NOTREACHED();
-  return cdm::kHdcpVersion2_2;
-}
-
-PP_DecryptResult CdmStatusToPpDecryptResult(cdm::Status status) {
-  switch (status) {
-    case cdm::kSuccess:
-      return PP_DECRYPTRESULT_SUCCESS;
-    case cdm::kNoKey:
-      return PP_DECRYPTRESULT_DECRYPT_NOKEY;
-    case cdm::kNeedMoreData:
-      return PP_DECRYPTRESULT_NEEDMOREDATA;
-    case cdm::kDecryptError:
-      return PP_DECRYPTRESULT_DECRYPT_ERROR;
-    case cdm::kDecodeError:
-      return PP_DECRYPTRESULT_DECODE_ERROR;
-    case cdm::kInitializationError:
-    case cdm::kDeferredInitialization:
-      // kInitializationError and kDeferredInitialization are only used by the
-      // Initialize* methods internally and never returned. Deliver* methods
-      // should never use these values.
-      break;
-  }
-
-  PP_NOTREACHED();
-  return PP_DECRYPTRESULT_DECRYPT_ERROR;
-}
-
-PP_DecryptedFrameFormat CdmVideoFormatToPpDecryptedFrameFormat(
-    cdm::VideoFormat format) {
-  switch (format) {
-    case cdm::kYv12:
-      return PP_DECRYPTEDFRAMEFORMAT_YV12;
-    case cdm::kI420:
-      return PP_DECRYPTEDFRAMEFORMAT_I420;
-    default:
-      return PP_DECRYPTEDFRAMEFORMAT_UNKNOWN;
-  }
-}
-
-PP_DecryptedSampleFormat CdmAudioFormatToPpDecryptedSampleFormat(
-    cdm::AudioFormat format) {
-  switch (format) {
-    case cdm::kAudioFormatU8:
-      return PP_DECRYPTEDSAMPLEFORMAT_U8;
-    case cdm::kAudioFormatS16:
-      return PP_DECRYPTEDSAMPLEFORMAT_S16;
-    case cdm::kAudioFormatS32:
-      return PP_DECRYPTEDSAMPLEFORMAT_S32;
-    case cdm::kAudioFormatF32:
-      return PP_DECRYPTEDSAMPLEFORMAT_F32;
-    case cdm::kAudioFormatPlanarS16:
-      return PP_DECRYPTEDSAMPLEFORMAT_PLANAR_S16;
-    case cdm::kAudioFormatPlanarF32:
-      return PP_DECRYPTEDSAMPLEFORMAT_PLANAR_F32;
-    default:
-      return PP_DECRYPTEDSAMPLEFORMAT_UNKNOWN;
-  }
-}
-
-cdm::AudioCodec PpAudioCodecToCdmAudioCodec(PP_AudioCodec codec) {
-  switch (codec) {
-    case PP_AUDIOCODEC_VORBIS:
-      return cdm::kCodecVorbis;
-    case PP_AUDIOCODEC_AAC:
-      return cdm::kCodecAac;
-    default:
-      return cdm::kUnknownAudioCodec;
-  }
-}
-
-cdm::VideoCodec PpVideoCodecToCdmVideoCodec(PP_VideoCodec codec) {
-  switch (codec) {
-    case PP_VIDEOCODEC_VP8:
-      return cdm::kCodecVp8;
-    case PP_VIDEOCODEC_H264:
-      return cdm::kCodecH264;
-    case PP_VIDEOCODEC_VP9:
-      return cdm::kCodecVp9;
-    default:
-      return cdm::kUnknownVideoCodec;
-  }
-}
-
-cdm::VideoCodecProfile PpVCProfileToCdmVCProfile(PP_VideoCodecProfile profile) {
-  switch (profile) {
-    case PP_VIDEOCODECPROFILE_NOT_NEEDED:
-      return cdm::kProfileNotNeeded;
-    case PP_VIDEOCODECPROFILE_H264_BASELINE:
-      return cdm::kH264ProfileBaseline;
-    case PP_VIDEOCODECPROFILE_H264_MAIN:
-      return cdm::kH264ProfileMain;
-    case PP_VIDEOCODECPROFILE_H264_EXTENDED:
-      return cdm::kH264ProfileExtended;
-    case PP_VIDEOCODECPROFILE_H264_HIGH:
-      return cdm::kH264ProfileHigh;
-    case PP_VIDEOCODECPROFILE_H264_HIGH_10:
-      return cdm::kH264ProfileHigh10;
-    case PP_VIDEOCODECPROFILE_H264_HIGH_422:
-      return cdm::kH264ProfileHigh422;
-    case PP_VIDEOCODECPROFILE_H264_HIGH_444_PREDICTIVE:
-      return cdm::kH264ProfileHigh444Predictive;
-    default:
-      return cdm::kUnknownVideoCodecProfile;
-  }
-}
-
-cdm::VideoFormat PpDecryptedFrameFormatToCdmVideoFormat(
-    PP_DecryptedFrameFormat format) {
-  switch (format) {
-    case PP_DECRYPTEDFRAMEFORMAT_YV12:
-      return cdm::kYv12;
-    case PP_DECRYPTEDFRAMEFORMAT_I420:
-      return cdm::kI420;
-    default:
-      return cdm::kUnknownVideoFormat;
-  }
-}
-
-cdm::StreamType PpDecryptorStreamTypeToCdmStreamType(
-    PP_DecryptorStreamType stream_type) {
-  switch (stream_type) {
-    case PP_DECRYPTORSTREAMTYPE_AUDIO:
-      return cdm::kStreamTypeAudio;
-    case PP_DECRYPTORSTREAMTYPE_VIDEO:
-      return cdm::kStreamTypeVideo;
-  }
-
-  PP_NOTREACHED();
-  return cdm::kStreamTypeVideo;
-}
-
-cdm::SessionType PpSessionTypeToCdmSessionType(PP_SessionType session_type) {
-  switch (session_type) {
-    case PP_SESSIONTYPE_TEMPORARY:
-      return cdm::kTemporary;
-    case PP_SESSIONTYPE_PERSISTENT_LICENSE:
-      return cdm::kPersistentLicense;
-    case PP_SESSIONTYPE_PERSISTENT_RELEASE:
-      return cdm::kPersistentKeyRelease;
-  }
-
-  PP_NOTREACHED();
-  return cdm::kTemporary;
-}
-
-cdm::InitDataType PpInitDataTypeToCdmInitDataType(
-    PP_InitDataType init_data_type) {
-  switch (init_data_type) {
-    case PP_INITDATATYPE_CENC:
-      return cdm::kCenc;
-    case PP_INITDATATYPE_KEYIDS:
-      return cdm::kKeyIds;
-    case PP_INITDATATYPE_WEBM:
-      return cdm::kWebM;
-  }
-
-  PP_NOTREACHED();
-  return cdm::kKeyIds;
-}
-
-PP_CdmExceptionCode CdmExceptionTypeToPpCdmExceptionType(
-    cdm::Exception exception) {
-  switch (exception) {
-    case cdm::Exception::kExceptionNotSupportedError:
-      return PP_CDMEXCEPTIONCODE_NOTSUPPORTEDERROR;
-    case cdm::Exception::kExceptionInvalidStateError:
-      return PP_CDMEXCEPTIONCODE_INVALIDSTATEERROR;
-    case cdm::Exception::kExceptionTypeError:
-      return PP_CDMEXCEPTIONCODE_TYPEERROR;
-    case cdm::Exception::kExceptionQuotaExceededError:
-      return PP_CDMEXCEPTIONCODE_QUOTAEXCEEDEDERROR;
-  }
-
-  PP_NOTREACHED();
-  return PP_CDMEXCEPTIONCODE_INVALIDSTATEERROR;
-}
-
-cdm::Exception CdmErrorTypeToCdmExceptionType(cdm::Error error) {
-  switch (error) {
-    case cdm::kNotSupportedError:
-      return cdm::Exception::kExceptionNotSupportedError;
-    case cdm::kInvalidStateError:
-      return cdm::Exception::kExceptionInvalidStateError;
-    case cdm::kInvalidAccessError:
-      return cdm::Exception::kExceptionTypeError;
-    case cdm::kQuotaExceededError:
-      return cdm::Exception::kExceptionQuotaExceededError;
-
-    // TODO(jrummell): Remove these once CDM_8 is no longer supported.
-    // https://crbug.com/737296.
-    case cdm::kUnknownError:
-    case cdm::kClientError:
-    case cdm::kOutputError:
-      break;
-  }
-
-  PP_NOTREACHED();
-  return cdm::Exception::kExceptionInvalidStateError;
-}
-
-PP_CdmMessageType CdmMessageTypeToPpMessageType(cdm::MessageType message) {
-  switch (message) {
-    case cdm::kLicenseRequest:
-      return PP_CDMMESSAGETYPE_LICENSE_REQUEST;
-    case cdm::kLicenseRenewal:
-      return PP_CDMMESSAGETYPE_LICENSE_RENEWAL;
-    case cdm::kLicenseRelease:
-      return PP_CDMMESSAGETYPE_LICENSE_RELEASE;
-    case cdm::kIndividualizationRequest:
-      PP_NOTREACHED();
-      return PP_CDMMESSAGETYPE_LICENSE_REQUEST;
-  }
-
-  PP_NOTREACHED();
-  return PP_CDMMESSAGETYPE_LICENSE_REQUEST;
-}
-
-PP_CdmKeyStatus CdmKeyStatusToPpKeyStatus(cdm::KeyStatus status) {
-  switch (status) {
-    case cdm::kUsable:
-      return PP_CDMKEYSTATUS_USABLE;
-    case cdm::kInternalError:
-      return PP_CDMKEYSTATUS_INVALID;
-    case cdm::kExpired:
-      return PP_CDMKEYSTATUS_EXPIRED;
-    case cdm::kOutputRestricted:
-      return PP_CDMKEYSTATUS_OUTPUTRESTRICTED;
-    case cdm::kOutputDownscaled:
-      return PP_CDMKEYSTATUS_OUTPUTDOWNSCALED;
-    case cdm::kStatusPending:
-      return PP_CDMKEYSTATUS_STATUSPENDING;
-    case cdm::kReleased:
-      return PP_CDMKEYSTATUS_RELEASED;
-  }
-
-  PP_NOTREACHED();
-  return PP_CDMKEYSTATUS_INVALID;
-}
-
-}  // namespace
-
-namespace media {
-
-PpapiCdmAdapter::PpapiCdmAdapter(PP_Instance instance, pp::Module* module)
-    : pp::Instance(instance),
-      pp::ContentDecryptor_Private(this),
-      output_protection_(this),
-      output_link_mask_(0),
-      output_protection_mask_(0),
-      query_output_protection_in_progress_(false),
-      uma_for_output_protection_query_reported_(false),
-      uma_for_output_protection_positive_result_reported_(false),
-      platform_verification_(this),
-      allocator_(this),
-      cdm_(NULL),
-      allow_distinctive_identifier_(false),
-      allow_persistent_state_(false),
-      deferred_initialize_audio_decoder_(false),
-      deferred_audio_decoder_config_id_(0),
-      deferred_initialize_video_decoder_(false),
-      deferred_video_decoder_config_id_(0),
-      last_read_file_size_kb_(0),
-      file_size_uma_reported_(false) {
-  callback_factory_.Initialize(this);
-}
-
-PpapiCdmAdapter::~PpapiCdmAdapter() = default;
-
-CdmWrapper* PpapiCdmAdapter::CreateCdmInstance(const std::string& key_system) {
-  // The Pepper plugin will be staticly linked to the CDM, so pass the plugin's
-  // CreateCdmInstance() to CdmWrapper.
-  CdmWrapper* cdm = CdmWrapper::Create(::CreateCdmInstance, key_system.data(),
-                                       key_system.size(), GetCdmHost, this);
-
-  const std::string message = "CDM instance for " + key_system +
-                              (cdm ? "" : " could not be") + " created.";
-  DLOG_TO_CONSOLE(message);
-  CDM_DLOG() << message;
-
-  if (cdm) {
-    pp::UMAPrivate uma_interface(this);
-
-    // The interface version is relatively small. So using normal histogram
-    // instead of a sparse histogram is okay. The following DCHECK asserts this.
-    PP_DCHECK(cdm->GetInterfaceVersion() <= 30);
-    uma_interface.HistogramEnumeration(
-        "Media.EME.CdmInterfaceVersion", cdm->GetInterfaceVersion(),
-        // Sample value should always be less than the boundary. Hence use "+1".
-        // See the comment on HistogramEnumeration in ppb_uma_private.idl.
-        cdm::ContentDecryptionModule::kVersion + 1);
-  }
-
-  return cdm;
-}
-
-bool PpapiCdmAdapter::Init(uint32_t argc,
-                           const char* argn[],
-                           const char* argv[]) {
-  return true;
-}
-
-void PpapiCdmAdapter::Initialize(uint32_t promise_id,
-                                 const std::string& key_system,
-                                 bool allow_distinctive_identifier,
-                                 bool allow_persistent_state) {
-  PP_DCHECK(!key_system.empty());
-  PP_DCHECK(!cdm_);
-
-#if defined(CHECK_DOCUMENT_URL)
-  PP_URLComponents_Dev url_components = {};
-  const pp::URLUtil_Dev* url_util = pp::URLUtil_Dev::Get();
-  if (!url_util) {
-    RejectPromise(promise_id, cdm::Exception::kExceptionInvalidStateError, 0,
-                  "Unable to determine origin.");
-    return;
-  }
-
-  pp::Var href = url_util->GetDocumentURL(pp::InstanceHandle(pp_instance()),
-                                          &url_components);
-  PP_DCHECK(href.is_string());
-  std::string url = href.AsString();
-  PP_DCHECK(!url.empty());
-  std::string url_scheme =
-      url.substr(url_components.scheme.begin, url_components.scheme.len);
-  if (url_scheme != "file") {
-    // Skip this check for file:// URLs as they don't have a host component.
-    PP_DCHECK(url_components.host.begin);
-    PP_DCHECK(0 < url_components.host.len);
-  }
-#endif  // defined(CHECK_DOCUMENT_URL)
-
-  cdm_ = make_linked_ptr(CreateCdmInstance(key_system));
-  if (!cdm_) {
-    RejectPromise(promise_id, cdm::Exception::kExceptionInvalidStateError, 0,
-                  "Unable to create CDM.");
-    return;
-  }
-
-  key_system_ = key_system;
-  allow_distinctive_identifier_ = allow_distinctive_identifier;
-  allow_persistent_state_ = allow_persistent_state;
-  cdm_->Initialize(allow_distinctive_identifier, allow_persistent_state, false);
-  OnResolvePromise(promise_id);
-}
-
-void PpapiCdmAdapter::SetServerCertificate(
-    uint32_t promise_id,
-    pp::VarArrayBuffer server_certificate) {
-  const uint8_t* server_certificate_ptr =
-      static_cast<const uint8_t*>(server_certificate.Map());
-  const uint32_t server_certificate_size = server_certificate.ByteLength();
-
-  if (!server_certificate_ptr ||
-      server_certificate_size < media::limits::kMinCertificateLength ||
-      server_certificate_size > media::limits::kMaxCertificateLength) {
-    RejectPromise(promise_id, cdm::Exception::kExceptionTypeError, 0,
-                  "Incorrect certificate.");
-    return;
-  }
-
-  cdm_->SetServerCertificate(promise_id, server_certificate_ptr,
-                             server_certificate_size);
-}
-
-void PpapiCdmAdapter::GetStatusForPolicy(uint32_t promise_id,
-                                         PP_HdcpVersion min_hdcp_version) {
-  if (!cdm_->GetStatusForPolicy(
-          promise_id, PpHdcpVersionToCdmHdcpVersion(min_hdcp_version))) {
-    RejectPromise(promise_id, cdm::Exception::kExceptionNotSupportedError, 0,
-                  "GetStatusForPolicy not supported.");
-  }
-}
-
-void PpapiCdmAdapter::CreateSessionAndGenerateRequest(
-    uint32_t promise_id,
-    PP_SessionType session_type,
-    PP_InitDataType init_data_type,
-    pp::VarArrayBuffer init_data) {
-  cdm_->CreateSessionAndGenerateRequest(
-      promise_id, PpSessionTypeToCdmSessionType(session_type),
-      PpInitDataTypeToCdmInitDataType(init_data_type),
-      static_cast<const uint8_t*>(init_data.Map()), init_data.ByteLength());
-}
-
-void PpapiCdmAdapter::LoadSession(uint32_t promise_id,
-                                  PP_SessionType session_type,
-                                  const std::string& session_id) {
-  cdm_->LoadSession(promise_id, PpSessionTypeToCdmSessionType(session_type),
-                    session_id.data(), session_id.size());
-}
-
-void PpapiCdmAdapter::UpdateSession(uint32_t promise_id,
-                                    const std::string& session_id,
-                                    pp::VarArrayBuffer response) {
-  const uint8_t* response_ptr = static_cast<const uint8_t*>(response.Map());
-  const uint32_t response_size = response.ByteLength();
-
-  PP_DCHECK(!session_id.empty());
-  PP_DCHECK(response_ptr);
-  PP_DCHECK(response_size > 0);
-
-  cdm_->UpdateSession(promise_id, session_id.data(), session_id.length(),
-                      response_ptr, response_size);
-}
-
-void PpapiCdmAdapter::CloseSession(uint32_t promise_id,
-                                   const std::string& session_id) {
-  cdm_->CloseSession(promise_id, session_id.data(), session_id.length());
-}
-
-void PpapiCdmAdapter::RemoveSession(uint32_t promise_id,
-                                    const std::string& session_id) {
-  cdm_->RemoveSession(promise_id, session_id.data(), session_id.length());
-}
-
-// Note: In the following decryption/decoding related functions, errors are NOT
-// reported via KeyError, but are reported via corresponding PPB calls.
-
-void PpapiCdmAdapter::Decrypt(
-    pp::Buffer_Dev encrypted_buffer,
-    const PP_EncryptedBlockInfo& encrypted_block_info) {
-  PP_DCHECK(!encrypted_buffer.is_null());
-
-  // Release a buffer that the caller indicated it is finished with.
-  allocator_.Release(encrypted_block_info.tracking_info.buffer_id);
-
-  cdm::Status status = cdm::kDecryptError;
-  LinkedDecryptedBlock decrypted_block(new DecryptedBlockImpl());
-
-  if (cdm_) {
-    cdm::InputBuffer_2 input_buffer = {};
-    std::vector<cdm::SubsampleEntry> subsamples;
-    ConfigureInputBuffer(encrypted_buffer, encrypted_block_info, &subsamples,
-                         &input_buffer);
-    status = cdm_->Decrypt(input_buffer, decrypted_block.get());
-    PP_DCHECK(status != cdm::kSuccess ||
-              (decrypted_block->DecryptedBuffer() &&
-               decrypted_block->DecryptedBuffer()->Size()));
-  }
-
-  CallOnMain(callback_factory_.NewCallback(&PpapiCdmAdapter::DeliverBlock,
-                                           status, decrypted_block,
-                                           encrypted_block_info.tracking_info));
-}
-
-void PpapiCdmAdapter::InitializeAudioDecoder(
-    const PP_AudioDecoderConfig& decoder_config,
-    pp::Buffer_Dev extra_data_buffer) {
-  PP_DCHECK(!deferred_initialize_audio_decoder_);
-  PP_DCHECK(deferred_audio_decoder_config_id_ == 0);
-  cdm::Status status = cdm::kInitializationError;
-  if (cdm_) {
-    cdm::AudioDecoderConfig_2 cdm_decoder_config = {};
-    cdm_decoder_config.codec =
-        PpAudioCodecToCdmAudioCodec(decoder_config.codec);
-    cdm_decoder_config.channel_count = decoder_config.channel_count;
-    cdm_decoder_config.bits_per_channel = decoder_config.bits_per_channel;
-    cdm_decoder_config.samples_per_second = decoder_config.samples_per_second;
-    cdm_decoder_config.extra_data =
-        static_cast<uint8_t*>(extra_data_buffer.data());
-    cdm_decoder_config.extra_data_size = extra_data_buffer.size();
-    // Pepper only supports CDM8 and CDM9, which don't include the encryption
-    // scheme, so this value will be dropped. However, something should be
-    // specified, so indicate that the stream may be encrypted.
-    cdm_decoder_config.encryption_scheme = cdm::EncryptionScheme::kCenc;
-
-    status = cdm_->InitializeAudioDecoder(cdm_decoder_config);
-  }
-
-  if (status == cdm::kDeferredInitialization) {
-    deferred_initialize_audio_decoder_ = true;
-    deferred_audio_decoder_config_id_ = decoder_config.request_id;
-    return;
-  }
-
-  CallOnMain(callback_factory_.NewCallback(
-      &PpapiCdmAdapter::DecoderInitializeDone, PP_DECRYPTORSTREAMTYPE_AUDIO,
-      decoder_config.request_id, status == cdm::kSuccess));
-}
-
-void PpapiCdmAdapter::InitializeVideoDecoder(
-    const PP_VideoDecoderConfig& decoder_config,
-    pp::Buffer_Dev extra_data_buffer) {
-  PP_DCHECK(!deferred_initialize_video_decoder_);
-  PP_DCHECK(deferred_video_decoder_config_id_ == 0);
-  cdm::Status status = cdm::kInitializationError;
-  if (cdm_) {
-    cdm::VideoDecoderConfig_2 cdm_decoder_config = {};
-    cdm_decoder_config.codec =
-        PpVideoCodecToCdmVideoCodec(decoder_config.codec);
-    cdm_decoder_config.profile =
-        PpVCProfileToCdmVCProfile(decoder_config.profile);
-    cdm_decoder_config.format =
-        PpDecryptedFrameFormatToCdmVideoFormat(decoder_config.format);
-    cdm_decoder_config.coded_size.width = decoder_config.width;
-    cdm_decoder_config.coded_size.height = decoder_config.height;
-    cdm_decoder_config.extra_data =
-        static_cast<uint8_t*>(extra_data_buffer.data());
-    cdm_decoder_config.extra_data_size = extra_data_buffer.size();
-    // Pepper only supports CDM8 and CDM9, which don't include the encryption
-    // scheme, so this value will be dropped. However, something should be
-    // specified, so indicate that the stream may be encrypted.
-    cdm_decoder_config.encryption_scheme = cdm::EncryptionScheme::kCenc;
-
-    status = cdm_->InitializeVideoDecoder(cdm_decoder_config);
-  }
-
-  if (status == cdm::kDeferredInitialization) {
-    deferred_initialize_video_decoder_ = true;
-    deferred_video_decoder_config_id_ = decoder_config.request_id;
-    return;
-  }
-
-  CallOnMain(callback_factory_.NewCallback(
-      &PpapiCdmAdapter::DecoderInitializeDone, PP_DECRYPTORSTREAMTYPE_VIDEO,
-      decoder_config.request_id, status == cdm::kSuccess));
-}
-
-void PpapiCdmAdapter::DeinitializeDecoder(PP_DecryptorStreamType decoder_type,
-                                          uint32_t request_id) {
-  PP_DCHECK(cdm_);  // InitializeXxxxxDecoder should have succeeded.
-  if (cdm_) {
-    cdm_->DeinitializeDecoder(
-        PpDecryptorStreamTypeToCdmStreamType(decoder_type));
-  }
-
-  CallOnMain(callback_factory_.NewCallback(
-      &PpapiCdmAdapter::DecoderDeinitializeDone, decoder_type, request_id));
-}
-
-void PpapiCdmAdapter::ResetDecoder(PP_DecryptorStreamType decoder_type,
-                                   uint32_t request_id) {
-  PP_DCHECK(cdm_);  // InitializeXxxxxDecoder should have succeeded.
-  if (cdm_)
-    cdm_->ResetDecoder(PpDecryptorStreamTypeToCdmStreamType(decoder_type));
-
-  CallOnMain(callback_factory_.NewCallback(&PpapiCdmAdapter::DecoderResetDone,
-                                           decoder_type, request_id));
-}
-
-void PpapiCdmAdapter::DecryptAndDecode(
-    PP_DecryptorStreamType decoder_type,
-    pp::Buffer_Dev encrypted_buffer,
-    const PP_EncryptedBlockInfo& encrypted_block_info) {
-  PP_DCHECK(cdm_);  // InitializeXxxxxDecoder should have succeeded.
-  // Release a buffer that the caller indicated it is finished with.
-  allocator_.Release(encrypted_block_info.tracking_info.buffer_id);
-
-  cdm::InputBuffer_2 input_buffer = {};
-  std::vector<cdm::SubsampleEntry> subsamples;
-  if (cdm_ && !encrypted_buffer.is_null()) {
-    ConfigureInputBuffer(encrypted_buffer, encrypted_block_info, &subsamples,
-                         &input_buffer);
-  }
-
-  cdm::Status status = cdm::kDecodeError;
-
-  switch (decoder_type) {
-    case PP_DECRYPTORSTREAMTYPE_VIDEO: {
-      LinkedVideoFrame video_frame(new VideoFrameImpl());
-      if (cdm_)
-        status = cdm_->DecryptAndDecodeFrame(input_buffer, video_frame.get());
-      CallOnMain(callback_factory_.NewCallback(
-          &PpapiCdmAdapter::DeliverFrame, status, video_frame,
-          encrypted_block_info.tracking_info));
-      return;
-    }
-
-    case PP_DECRYPTORSTREAMTYPE_AUDIO: {
-      LinkedAudioFrames audio_frames(new AudioFramesImpl());
-      if (cdm_) {
-        status =
-            cdm_->DecryptAndDecodeSamples(input_buffer, audio_frames.get());
-      }
-      CallOnMain(callback_factory_.NewCallback(
-          &PpapiCdmAdapter::DeliverSamples, status, audio_frames,
-          encrypted_block_info.tracking_info));
-      return;
-    }
-
-    default:
-      PP_NOTREACHED();
-      return;
-  }
-}
-
-cdm::Buffer* PpapiCdmAdapter::Allocate(uint32_t capacity) {
-  return allocator_.Allocate(capacity);
-}
-
-void PpapiCdmAdapter::SetTimer(int64_t delay_ms, void* context) {
-  // NOTE: doesn't really need to run on the main thread; could just as well run
-  // on a helper thread if |cdm_| were thread-friendly and care was taken.  We
-  // only use CallOnMainThread() here to get delayed-execution behavior.
-  pp::Module::Get()->core()->CallOnMainThread(
-      delay_ms,
-      callback_factory_.NewCallback(&PpapiCdmAdapter::TimerExpired, context),
-      PP_OK);
-}
-
-void PpapiCdmAdapter::TimerExpired(int32_t result, void* context) {
-  PP_DCHECK(result == PP_OK);
-  cdm_->TimerExpired(context);
-}
-
-cdm::Time PpapiCdmAdapter::GetCurrentWallTime() {
-  return pp::Module::Get()->core()->GetTime();
-}
-
-void PpapiCdmAdapter::OnResolveKeyStatusPromise(uint32_t promise_id,
-                                                cdm::KeyStatus key_status) {
-  PostOnMain(callback_factory_.NewCallback(
-      &PpapiCdmAdapter::SendPromiseResolvedWithKeyStatusInternal, promise_id,
-      key_status));
-}
-
-void PpapiCdmAdapter::OnResolveNewSessionPromise(uint32_t promise_id,
-                                                 const char* session_id,
-                                                 uint32_t session_id_size) {
-  PostOnMain(callback_factory_.NewCallback(
-      &PpapiCdmAdapter::SendPromiseResolvedWithSessionInternal, promise_id,
-      std::string(session_id, session_id_size)));
-}
-
-void PpapiCdmAdapter::OnResolvePromise(uint32_t promise_id) {
-  PostOnMain(callback_factory_.NewCallback(
-      &PpapiCdmAdapter::SendPromiseResolvedInternal, promise_id));
-}
-
-void PpapiCdmAdapter::OnRejectPromise(uint32_t promise_id,
-                                      cdm::Exception exception,
-                                      uint32_t system_code,
-                                      const char* error_message,
-                                      uint32_t error_message_size) {
-  RejectPromise(promise_id, exception, system_code,
-                std::string(error_message, error_message_size));
-}
-
-void PpapiCdmAdapter::OnRejectPromise(uint32_t promise_id,
-                                      cdm::Error error,
-                                      uint32_t system_code,
-                                      const char* error_message,
-                                      uint32_t error_message_size) {
-  OnRejectPromise(promise_id, CdmErrorTypeToCdmExceptionType(error),
-                  system_code, error_message, error_message_size);
-}
-
-void PpapiCdmAdapter::RejectPromise(uint32_t promise_id,
-                                    cdm::Exception exception,
-                                    uint32_t system_code,
-                                    const std::string& error_message) {
-  PostOnMain(callback_factory_.NewCallback(
-      &PpapiCdmAdapter::SendPromiseRejectedInternal, promise_id,
-      SessionError(exception, system_code, error_message)));
-}
-
-void PpapiCdmAdapter::OnSessionMessage(const char* session_id,
-                                       uint32_t session_id_size,
-                                       cdm::MessageType message_type,
-                                       const char* message,
-                                       uint32_t message_size) {
-  PostOnMain(callback_factory_.NewCallback(
-      &PpapiCdmAdapter::SendSessionMessageInternal,
-      SessionMessage(std::string(session_id, session_id_size), message_type,
-                     message, message_size)));
-}
-
-void PpapiCdmAdapter::OnSessionMessage(const char* session_id,
-                                       uint32_t session_id_size,
-                                       cdm::MessageType message_type,
-                                       const char* message,
-                                       uint32_t message_size,
-                                       const char* legacy_destination_url,
-                                       uint32_t legacy_destination_url_size) {
-  // |legacy_destination_url| is obsolete and will be removed as part of
-  // https://crbug.com/570216.
-  // License requests should not specify |legacy_destination_url|.
-  PP_DCHECK(legacy_destination_url_size == 0 ||
-            message_type != cdm::MessageType::kLicenseRequest);
-  OnSessionMessage(session_id, session_id_size, message_type, message,
-                   message_size);
-}
-
-void PpapiCdmAdapter::OnSessionKeysChange(const char* session_id,
-                                          uint32_t session_id_size,
-                                          bool has_additional_usable_key,
-                                          const cdm::KeyInformation* keys_info,
-                                          uint32_t keys_info_count) {
-  std::vector<PP_KeyInformation> key_information;
-  for (uint32_t i = 0; i < keys_info_count; ++i) {
-    const auto& key_info = keys_info[i];
-    PP_KeyInformation next_key = {};
-
-    if (key_info.key_id_size > sizeof(next_key.key_id)) {
-      PP_NOTREACHED();
-      continue;
-    }
-
-    // Copy key_id into |next_key|.
-    memcpy(next_key.key_id, key_info.key_id, key_info.key_id_size);
-
-    // Set remaining fields on |next_key|.
-    next_key.key_id_size = key_info.key_id_size;
-    next_key.key_status = CdmKeyStatusToPpKeyStatus(key_info.status);
-    next_key.system_code = key_info.system_code;
-    key_information.push_back(next_key);
-  }
-
-  PostOnMain(callback_factory_.NewCallback(
-      &PpapiCdmAdapter::SendSessionKeysChangeInternal,
-      std::string(session_id, session_id_size), has_additional_usable_key,
-      key_information));
-}
-
-void PpapiCdmAdapter::OnExpirationChange(const char* session_id,
-                                         uint32_t session_id_size,
-                                         cdm::Time new_expiry_time) {
-  PostOnMain(callback_factory_.NewCallback(
-      &PpapiCdmAdapter::SendExpirationChangeInternal,
-      std::string(session_id, session_id_size), new_expiry_time));
-}
-
-void PpapiCdmAdapter::OnSessionClosed(const char* session_id,
-                                      uint32_t session_id_size) {
-  PostOnMain(
-      callback_factory_.NewCallback(&PpapiCdmAdapter::SendSessionClosedInternal,
-                                    std::string(session_id, session_id_size)));
-}
-
-void PpapiCdmAdapter::OnLegacySessionError(const char* session_id,
-                                           uint32_t session_id_size,
-                                           cdm::Error error,
-                                           uint32_t system_code,
-                                           const char* error_message,
-                                           uint32_t error_message_size) {
-  // Obsolete and will be removed as part of https://crbug.com/570216.
-}
-
-// Helpers to pass the event to Pepper.
-
-void PpapiCdmAdapter::SendPromiseResolvedInternal(int32_t result,
-                                                  uint32_t promise_id) {
-  PP_DCHECK(result == PP_OK);
-  pp::ContentDecryptor_Private::PromiseResolved(promise_id);
-}
-
-void PpapiCdmAdapter::SendPromiseResolvedWithKeyStatusInternal(
-    int32_t result,
-    uint32_t promise_id,
-    cdm::KeyStatus key_status) {
-  PP_DCHECK(result == PP_OK);
-  pp::ContentDecryptor_Private::PromiseResolvedWithKeyStatus(
-      promise_id, CdmKeyStatusToPpKeyStatus(key_status));
-}
-
-void PpapiCdmAdapter::SendPromiseResolvedWithSessionInternal(
-    int32_t result,
-    uint32_t promise_id,
-    const std::string& session_id) {
-  PP_DCHECK(result == PP_OK);
-  pp::ContentDecryptor_Private::PromiseResolvedWithSession(promise_id,
-                                                           session_id);
-}
-
-void PpapiCdmAdapter::SendPromiseRejectedInternal(int32_t result,
-                                                  uint32_t promise_id,
-                                                  const SessionError& error) {
-  PP_DCHECK(result == PP_OK);
-  pp::ContentDecryptor_Private::PromiseRejected(
-      promise_id, CdmExceptionTypeToPpCdmExceptionType(error.exception),
-      error.system_code, error.error_description);
-}
-
-void PpapiCdmAdapter::SendSessionMessageInternal(
-    int32_t result,
-    const SessionMessage& message) {
-  PP_DCHECK(result == PP_OK);
-
-  pp::VarArrayBuffer message_array_buffer(message.message.size());
-  if (message.message.size() > 0) {
-    memcpy(message_array_buffer.Map(), message.message.data(),
-           message.message.size());
-  }
-
-  pp::ContentDecryptor_Private::SessionMessage(
-      message.session_id, CdmMessageTypeToPpMessageType(message.message_type),
-      message_array_buffer, std::string());
-}
-
-void PpapiCdmAdapter::SendSessionClosedInternal(int32_t result,
-                                                const std::string& session_id) {
-  PP_DCHECK(result == PP_OK);
-  pp::ContentDecryptor_Private::SessionClosed(session_id);
-}
-
-void PpapiCdmAdapter::SendSessionKeysChangeInternal(
-    int32_t result,
-    const std::string& session_id,
-    bool has_additional_usable_key,
-    const std::vector<PP_KeyInformation>& key_info) {
-  PP_DCHECK(result == PP_OK);
-  pp::ContentDecryptor_Private::SessionKeysChange(
-      session_id, has_additional_usable_key, key_info);
-}
-
-void PpapiCdmAdapter::SendExpirationChangeInternal(
-    int32_t result,
-    const std::string& session_id,
-    cdm::Time new_expiry_time) {
-  PP_DCHECK(result == PP_OK);
-  pp::ContentDecryptor_Private::SessionExpirationChange(session_id,
-                                                        new_expiry_time);
-}
-
-void PpapiCdmAdapter::DeliverBlock(
-    int32_t result,
-    const cdm::Status& status,
-    const LinkedDecryptedBlock& decrypted_block,
-    const PP_DecryptTrackingInfo& tracking_info) {
-  PP_DCHECK(result == PP_OK);
-  PP_DecryptedBlockInfo decrypted_block_info = {};
-  decrypted_block_info.tracking_info = tracking_info;
-  decrypted_block_info.tracking_info.timestamp = decrypted_block->Timestamp();
-  decrypted_block_info.tracking_info.buffer_id = 0;
-  decrypted_block_info.data_size = 0;
-  decrypted_block_info.result = CdmStatusToPpDecryptResult(status);
-
-  pp::Buffer_Dev buffer;
-
-  if (decrypted_block_info.result == PP_DECRYPTRESULT_SUCCESS) {
-    PP_DCHECK(decrypted_block.get() && decrypted_block->DecryptedBuffer());
-    if (!decrypted_block.get() || !decrypted_block->DecryptedBuffer()) {
-      PP_NOTREACHED();
-      decrypted_block_info.result = PP_DECRYPTRESULT_DECRYPT_ERROR;
-    } else {
-      PpbBuffer* ppb_buffer =
-          static_cast<PpbBuffer*>(decrypted_block->DecryptedBuffer());
-      decrypted_block_info.tracking_info.buffer_id = ppb_buffer->buffer_id();
-      decrypted_block_info.data_size = ppb_buffer->Size();
-
-      buffer = ppb_buffer->TakeBuffer();
-    }
-  }
-
-  pp::ContentDecryptor_Private::DeliverBlock(buffer, decrypted_block_info);
-}
-
-void PpapiCdmAdapter::DecoderInitializeDone(int32_t result,
-                                            PP_DecryptorStreamType decoder_type,
-                                            uint32_t request_id,
-                                            bool success) {
-  PP_DCHECK(result == PP_OK);
-  pp::ContentDecryptor_Private::DecoderInitializeDone(decoder_type, request_id,
-                                                      success);
-}
-
-void PpapiCdmAdapter::DecoderDeinitializeDone(
-    int32_t result,
-    PP_DecryptorStreamType decoder_type,
-    uint32_t request_id) {
-  pp::ContentDecryptor_Private::DecoderDeinitializeDone(decoder_type,
-                                                        request_id);
-}
-
-void PpapiCdmAdapter::DecoderResetDone(int32_t result,
-                                       PP_DecryptorStreamType decoder_type,
-                                       uint32_t request_id) {
-  pp::ContentDecryptor_Private::DecoderResetDone(decoder_type, request_id);
-}
-
-void PpapiCdmAdapter::DeliverFrame(
-    int32_t result,
-    const cdm::Status& status,
-    const LinkedVideoFrame& video_frame,
-    const PP_DecryptTrackingInfo& tracking_info) {
-  PP_DCHECK(result == PP_OK);
-  PP_DecryptedFrameInfo decrypted_frame_info = {};
-  decrypted_frame_info.tracking_info.request_id = tracking_info.request_id;
-  decrypted_frame_info.tracking_info.buffer_id = 0;
-  decrypted_frame_info.result = CdmStatusToPpDecryptResult(status);
-
-  pp::Buffer_Dev buffer;
-
-  if (decrypted_frame_info.result == PP_DECRYPTRESULT_SUCCESS) {
-    if (!IsValidVideoFrame(video_frame)) {
-      PP_NOTREACHED();
-      decrypted_frame_info.result = PP_DECRYPTRESULT_DECODE_ERROR;
-    } else {
-      PpbBuffer* ppb_buffer =
-          static_cast<PpbBuffer*>(video_frame->FrameBuffer());
-
-      decrypted_frame_info.tracking_info.timestamp = video_frame->Timestamp();
-      decrypted_frame_info.tracking_info.buffer_id = ppb_buffer->buffer_id();
-      decrypted_frame_info.format =
-          CdmVideoFormatToPpDecryptedFrameFormat(video_frame->Format());
-      decrypted_frame_info.width = video_frame->Size().width;
-      decrypted_frame_info.height = video_frame->Size().height;
-      decrypted_frame_info.plane_offsets[PP_DECRYPTEDFRAMEPLANES_Y] =
-          video_frame->PlaneOffset(cdm::VideoFrame::kYPlane);
-      decrypted_frame_info.plane_offsets[PP_DECRYPTEDFRAMEPLANES_U] =
-          video_frame->PlaneOffset(cdm::VideoFrame::kUPlane);
-      decrypted_frame_info.plane_offsets[PP_DECRYPTEDFRAMEPLANES_V] =
-          video_frame->PlaneOffset(cdm::VideoFrame::kVPlane);
-      decrypted_frame_info.strides[PP_DECRYPTEDFRAMEPLANES_Y] =
-          video_frame->Stride(cdm::VideoFrame::kYPlane);
-      decrypted_frame_info.strides[PP_DECRYPTEDFRAMEPLANES_U] =
-          video_frame->Stride(cdm::VideoFrame::kUPlane);
-      decrypted_frame_info.strides[PP_DECRYPTEDFRAMEPLANES_V] =
-          video_frame->Stride(cdm::VideoFrame::kVPlane);
-
-      buffer = ppb_buffer->TakeBuffer();
-    }
-  }
-
-  pp::ContentDecryptor_Private::DeliverFrame(buffer, decrypted_frame_info);
-}
-
-void PpapiCdmAdapter::DeliverSamples(
-    int32_t result,
-    const cdm::Status& status,
-    const LinkedAudioFrames& audio_frames,
-    const PP_DecryptTrackingInfo& tracking_info) {
-  PP_DCHECK(result == PP_OK);
-
-  PP_DecryptedSampleInfo decrypted_sample_info = {};
-  decrypted_sample_info.tracking_info = tracking_info;
-  decrypted_sample_info.tracking_info.timestamp = 0;
-  decrypted_sample_info.tracking_info.buffer_id = 0;
-  decrypted_sample_info.data_size = 0;
-  decrypted_sample_info.result = CdmStatusToPpDecryptResult(status);
-
-  pp::Buffer_Dev buffer;
-
-  if (decrypted_sample_info.result == PP_DECRYPTRESULT_SUCCESS) {
-    PP_DCHECK(audio_frames.get() && audio_frames->FrameBuffer());
-    if (!audio_frames.get() || !audio_frames->FrameBuffer()) {
-      PP_NOTREACHED();
-      decrypted_sample_info.result = PP_DECRYPTRESULT_DECRYPT_ERROR;
-    } else {
-      PpbBuffer* ppb_buffer =
-          static_cast<PpbBuffer*>(audio_frames->FrameBuffer());
-
-      decrypted_sample_info.tracking_info.buffer_id = ppb_buffer->buffer_id();
-      decrypted_sample_info.data_size = ppb_buffer->Size();
-      decrypted_sample_info.format =
-          CdmAudioFormatToPpDecryptedSampleFormat(audio_frames->Format());
-
-      buffer = ppb_buffer->TakeBuffer();
-    }
-  }
-
-  pp::ContentDecryptor_Private::DeliverSamples(buffer, decrypted_sample_info);
-}
-
-bool PpapiCdmAdapter::IsValidVideoFrame(const LinkedVideoFrame& video_frame) {
-  if (!video_frame.get() || !video_frame->FrameBuffer() ||
-      (video_frame->Format() != cdm::kI420 &&
-       video_frame->Format() != cdm::kYv12)) {
-    CDM_DLOG() << "Invalid video frame!";
-    return false;
-  }
-
-  PpbBuffer* ppb_buffer = static_cast<PpbBuffer*>(video_frame->FrameBuffer());
-
-  for (uint32_t i = 0; i < cdm::VideoFrame::kMaxPlanes; ++i) {
-    int plane_height = (i == cdm::VideoFrame::kYPlane)
-                           ? video_frame->Size().height
-                           : (video_frame->Size().height + 1) / 2;
-    cdm::VideoFrame::VideoPlane plane =
-        static_cast<cdm::VideoFrame::VideoPlane>(i);
-    if (ppb_buffer->Size() < video_frame->PlaneOffset(plane) +
-                                 plane_height * video_frame->Stride(plane)) {
-      return false;
-    }
-  }
-
-  return true;
-}
-
-void PpapiCdmAdapter::OnFirstFileRead(int32_t file_size_bytes) {
-  PP_DCHECK(IsMainThread());
-  PP_DCHECK(file_size_bytes >= 0);
-
-  last_read_file_size_kb_ = file_size_bytes / 1024;
-
-  if (file_size_uma_reported_)
-    return;
-
-  pp::UMAPrivate uma_interface(this);
-  uma_interface.HistogramCustomCounts(
-      "Media.EME.CdmFileIO.FileSizeKBOnFirstRead", last_read_file_size_kb_,
-      kSizeKBMin, kSizeKBMax, kSizeKBBuckets);
-  file_size_uma_reported_ = true;
-}
-
-#if !defined(NDEBUG)
-void PpapiCdmAdapter::LogToConsole(const pp::Var& value) {
-  PP_DCHECK(IsMainThread());
-  const PPB_Console* console = reinterpret_cast<const PPB_Console*>(
-      pp::Module::Get()->GetBrowserInterface(PPB_CONSOLE_INTERFACE));
-  console->Log(pp_instance(), PP_LOGLEVEL_LOG, value.pp_var());
-}
-#endif  // !defined(NDEBUG)
-
-void PpapiCdmAdapter::SendPlatformChallenge(const char* service_id,
-                                            uint32_t service_id_size,
-                                            const char* challenge,
-                                            uint32_t challenge_size) {
-#if defined(OS_CHROMEOS)
-  // If access to a distinctive identifier is not allowed, block platform
-  // verification to prevent access to such an identifier.
-  if (allow_distinctive_identifier_) {
-    pp::VarArrayBuffer challenge_var(challenge_size);
-    uint8_t* var_data = static_cast<uint8_t*>(challenge_var.Map());
-    memcpy(var_data, challenge, challenge_size);
-
-    std::string service_id_str(service_id, service_id_size);
-
-    linked_ptr<PepperPlatformChallengeResponse> response(
-        new PepperPlatformChallengeResponse());
-
-    int32_t result = platform_verification_.ChallengePlatform(
-        pp::Var(service_id_str), challenge_var, &response->signed_data,
-        &response->signed_data_signature, &response->platform_key_certificate,
-        callback_factory_.NewCallback(
-            &PpapiCdmAdapter::SendPlatformChallengeDone, response));
-    challenge_var.Unmap();
-    if (result == PP_OK_COMPLETIONPENDING)
-      return;
-
-    // Fall through on error and issue an empty OnPlatformChallengeResponse().
-    PP_DCHECK(result != PP_OK);
-  }
-#endif
-
-  cdm::PlatformChallengeResponse platform_challenge_response = {};
-  cdm_->OnPlatformChallengeResponse(platform_challenge_response);
-}
-
-void PpapiCdmAdapter::EnableOutputProtection(uint32_t desired_protection_mask) {
-  int32_t result = output_protection_.EnableProtection(
-      desired_protection_mask,
-      callback_factory_.NewCallback(&PpapiCdmAdapter::EnableProtectionDone));
-
-  // Errors are ignored since clients must call QueryOutputProtectionStatus() to
-  // inspect the protection status on a regular basis.
-
-  if (result != PP_OK && result != PP_OK_COMPLETIONPENDING)
-    CDM_DLOG() << __func__ << " failed!";
-}
-
-void PpapiCdmAdapter::QueryOutputProtectionStatus() {
-  PP_DCHECK(!query_output_protection_in_progress_);
-
-  output_link_mask_ = output_protection_mask_ = 0;
-  const int32_t result = output_protection_.QueryStatus(
-      &output_link_mask_, &output_protection_mask_,
-      callback_factory_.NewCallback(
-          &PpapiCdmAdapter::QueryOutputProtectionStatusDone));
-  if (result == PP_OK_COMPLETIONPENDING) {
-    query_output_protection_in_progress_ = true;
-    ReportOutputProtectionQuery();
-    return;
-  }
-
-  // Fall through on error and issue an empty OnQueryOutputProtectionStatus().
-  PP_DCHECK(result != PP_OK);
-  CDM_DLOG() << __func__ << " failed, result = " << result;
-}
-
-void PpapiCdmAdapter::OnDeferredInitializationDone(cdm::StreamType stream_type,
-                                                   cdm::Status decoder_status) {
-  switch (stream_type) {
-    case cdm::kStreamTypeAudio:
-      PP_DCHECK(deferred_initialize_audio_decoder_);
-      CallOnMain(callback_factory_.NewCallback(
-          &PpapiCdmAdapter::DecoderInitializeDone, PP_DECRYPTORSTREAMTYPE_AUDIO,
-          deferred_audio_decoder_config_id_, decoder_status == cdm::kSuccess));
-      deferred_initialize_audio_decoder_ = false;
-      deferred_audio_decoder_config_id_ = 0;
-      break;
-    case cdm::kStreamTypeVideo:
-      PP_DCHECK(deferred_initialize_video_decoder_);
-      CallOnMain(callback_factory_.NewCallback(
-          &PpapiCdmAdapter::DecoderInitializeDone, PP_DECRYPTORSTREAMTYPE_VIDEO,
-          deferred_video_decoder_config_id_, decoder_status == cdm::kSuccess));
-      deferred_initialize_video_decoder_ = false;
-      deferred_video_decoder_config_id_ = 0;
-      break;
-  }
-}
-
-void PpapiCdmAdapter::RequestStorageId(uint32_t version) {
-  PP_DCHECK(version < 0x80000000);  // Reserved versions not allowed.
-
-  // If persistent storage is not allowed, no need to get the Storage ID.
-  // As well, only allow the request if the current version (or "latest")
-  // is requested.
-  if (allow_persistent_state_ && (version == kCurrentStorageIdVersion ||
-                                  version == kRequestLatestStorageIdVersion)) {
-    linked_ptr<pp::Var> response(new pp::Var());
-    int32_t result = platform_verification_.GetStorageId(
-        response.get(), callback_factory_.NewCallback(
-                            &PpapiCdmAdapter::RequestStorageIdDone, response));
-    if (result == PP_OK_COMPLETIONPENDING)
-      return;
-
-    // Fall through on error and provide an empty storage_id.
-    PP_DCHECK(result != PP_OK);
-  }
-
-  cdm_->OnStorageId(version, nullptr, 0);
-}
-
-// The CDM owns the returned object and must call FileIO::Close() to release it.
-cdm::FileIO* PpapiCdmAdapter::CreateFileIO(cdm::FileIOClient* client) {
-  if (!allow_persistent_state_) {
-    CDM_DLOG()
-        << "Cannot create FileIO because persistent state is not allowed.";
-    return nullptr;
-  }
-
-  return new CdmFileIOImpl(
-      client, pp_instance(),
-      callback_factory_.NewCallback(&PpapiCdmAdapter::OnFirstFileRead));
-}
-
-void PpapiCdmAdapter::ReportOutputProtectionUMA(OutputProtectionStatus status) {
-  pp::UMAPrivate uma_interface(this);
-  uma_interface.HistogramEnumeration("Media.EME.OutputProtection", status,
-                                     OUTPUT_PROTECTION_MAX);
-}
-
-void PpapiCdmAdapter::ReportOutputProtectionQuery() {
-  if (uma_for_output_protection_query_reported_)
-    return;
-
-  ReportOutputProtectionUMA(OUTPUT_PROTECTION_QUERIED);
-  uma_for_output_protection_query_reported_ = true;
-}
-
-void PpapiCdmAdapter::ReportOutputProtectionQueryResult() {
-  if (uma_for_output_protection_positive_result_reported_)
-    return;
-
-  // Report UMAs for output protection query result.
-  uint32_t external_links = (output_link_mask_ & ~cdm::kLinkTypeInternal);
-
-  if (!external_links) {
-    ReportOutputProtectionUMA(OUTPUT_PROTECTION_NO_EXTERNAL_LINK);
-    uma_for_output_protection_positive_result_reported_ = true;
-    return;
-  }
-
-  const uint32_t kProtectableLinks =
-      cdm::kLinkTypeHDMI | cdm::kLinkTypeDVI | cdm::kLinkTypeDisplayPort;
-  bool is_unprotectable_link_connected =
-      (external_links & ~kProtectableLinks) != 0;
-  bool is_hdcp_enabled_on_all_protectable_links =
-      (output_protection_mask_ & cdm::kProtectionHDCP) != 0;
-
-  if (!is_unprotectable_link_connected &&
-      is_hdcp_enabled_on_all_protectable_links) {
-    ReportOutputProtectionUMA(OUTPUT_PROTECTION_ALL_EXTERNAL_LINKS_PROTECTED);
-    uma_for_output_protection_positive_result_reported_ = true;
-    return;
-  }
-
-  // Do not report a negative result because it could be a false negative.
-  // Instead, we will calculate number of negatives using the total number of
-  // queries and success results.
-}
-
-#if defined(OS_CHROMEOS)
-void PpapiCdmAdapter::SendPlatformChallengeDone(
-    int32_t result,
-    const linked_ptr<PepperPlatformChallengeResponse>& response) {
-  if (result != PP_OK) {
-    CDM_DLOG() << __func__ << ": Platform challenge failed!";
-    cdm::PlatformChallengeResponse platform_challenge_response = {};
-    cdm_->OnPlatformChallengeResponse(platform_challenge_response);
-    return;
-  }
-
-  pp::VarArrayBuffer signed_data_var(response->signed_data);
-  pp::VarArrayBuffer signed_data_signature_var(response->signed_data_signature);
-  std::string platform_key_certificate_string =
-      response->platform_key_certificate.AsString();
-
-  cdm::PlatformChallengeResponse platform_challenge_response = {
-      static_cast<uint8_t*>(signed_data_var.Map()),
-      signed_data_var.ByteLength(),
-      static_cast<uint8_t*>(signed_data_signature_var.Map()),
-      signed_data_signature_var.ByteLength(),
-      reinterpret_cast<const uint8_t*>(platform_key_certificate_string.data()),
-      static_cast<uint32_t>(platform_key_certificate_string.length())};
-  cdm_->OnPlatformChallengeResponse(platform_challenge_response);
-
-  signed_data_var.Unmap();
-  signed_data_signature_var.Unmap();
-}
-#endif
-
-void PpapiCdmAdapter::EnableProtectionDone(int32_t result) {
-  // Does nothing since clients must call QueryOutputProtectionStatus() to
-  // inspect the protection status on a regular basis.
-  CDM_DLOG() << __func__ << " : " << result;
-}
-
-void PpapiCdmAdapter::QueryOutputProtectionStatusDone(int32_t result) {
-  PP_DCHECK(query_output_protection_in_progress_);
-  query_output_protection_in_progress_ = false;
-
-  // Return a query status of failed on error.
-  cdm::QueryResult query_result;
-  if (result != PP_OK) {
-    CDM_DLOG() << __func__ << " failed, result = " << result;
-    output_link_mask_ = output_protection_mask_ = 0;
-    query_result = cdm::kQueryFailed;
-  } else {
-    query_result = cdm::kQuerySucceeded;
-    ReportOutputProtectionQueryResult();
-  }
-
-  cdm_->OnQueryOutputProtectionStatus(query_result, output_link_mask_,
-                                      output_protection_mask_);
-}
-
-void PpapiCdmAdapter::RequestStorageIdDone(
-    int32_t result,
-    const linked_ptr<pp::Var>& response) {
-  uint8_t* storage_id_ptr;
-  uint32_t storage_id_size;
-
-  if (result == PP_OK && response->is_array_buffer()) {
-    pp::VarArrayBuffer storage_id(*response);
-    storage_id_ptr = static_cast<uint8_t*>(storage_id.Map());
-    storage_id_size = storage_id.ByteLength();
-  } else {
-    CDM_DLOG() << __func__ << " failed, result = " << result;
-    storage_id_ptr = nullptr;
-    storage_id_size = 0;
-  }
-
-  // Pepper only supports a single version of Storage ID.
-  cdm_->OnStorageId(kCurrentStorageIdVersion, storage_id_ptr, storage_id_size);
-}
-
-PpapiCdmAdapter::SessionError::SessionError(
-    cdm::Exception exception,
-    uint32_t system_code,
-    const std::string& error_description)
-    : exception(exception),
-      system_code(system_code),
-      error_description(error_description) {}
-
-PpapiCdmAdapter::SessionMessage::SessionMessage(const std::string& session_id,
-                                                cdm::MessageType message_type,
-                                                const char* message,
-                                                uint32_t message_size)
-    : session_id(session_id),
-      message_type(message_type),
-      message(message, message + message_size) {}
-
-PpapiCdmAdapter::SessionMessage::SessionMessage(const SessionMessage&) =
-    default;
-
-PpapiCdmAdapter::SessionMessage::~SessionMessage() = default;
-
-void* GetCdmHost(int host_interface_version, void* user_data) {
-  if (!host_interface_version || !user_data)
-    return NULL;
-
-  static_assert(
-      cdm::ContentDecryptionModule::Host::kVersion == cdm::Host_9::kVersion,
-      "update the code below");
-
-  // Ensure IsSupportedCdmHostVersion matches implementation of this function.
-  // Always update this DCHECK when updating this function.
-  // If this check fails, update this function and DCHECK or update
-  // IsSupportedCdmHostVersion.
-
-  PP_DCHECK(
-      // Future version is not supported.
-      !IsSupportedCdmHostVersion(cdm::Host_10::kVersion + 1) &&
-      // Current version is supported.
-      IsSupportedCdmHostVersion(cdm::Host_10::kVersion) &&
-      // Include all previous supported versions (if any) here.
-      IsSupportedCdmHostVersion(cdm::Host_8::kVersion) &&
-      // One older than the oldest supported version is not supported.
-      !IsSupportedCdmHostVersion(cdm::Host_8::kVersion - 1));
-  PP_DCHECK(IsSupportedCdmHostVersion(host_interface_version));
-
-  PpapiCdmAdapter* cdm_adapter = static_cast<PpapiCdmAdapter*>(user_data);
-  CDM_DLOG() << "Create CDM Host with version " << host_interface_version;
-  switch (host_interface_version) {
-    case cdm::Host_8::kVersion:
-      return static_cast<cdm::Host_8*>(cdm_adapter);
-    case cdm::Host_9::kVersion:
-      return static_cast<cdm::Host_9*>(cdm_adapter);
-    default:
-      PP_NOTREACHED();
-      return NULL;
-  }
-}
-
-// This object is the global object representing this plugin library as long
-// as it is loaded.
-class PpapiCdmAdapterModule : public pp::Module {
- public:
-  PpapiCdmAdapterModule() : pp::Module() {
-    // This function blocks the renderer thread (PluginInstance::Initialize()).
-    // Move this call to other places if this may be a concern in the future.
-    INITIALIZE_CDM_MODULE();
-  }
-  ~PpapiCdmAdapterModule() override { DeinitializeCdmModule(); }
-
-  // pp::Module implementation.
-  pp::Instance* CreateInstance(PP_Instance instance) override {
-    return new PpapiCdmAdapter(instance, this);
-  }
-
- private:
-  CdmFileIOImpl::ResourceTracker cdm_file_io_impl_resource_tracker;
-};
-
-}  // namespace media
-
-namespace pp {
-
-// Factory function for your specialization of the Module object.
-Module* CreateModule() {
-  return new media::PpapiCdmAdapterModule();
-}
-
-}  // namespace pp
diff --git a/media/cdm/library_cdm/ppapi_cdm_adapter.gni b/media/cdm/library_cdm/ppapi_cdm_adapter.gni
deleted file mode 100644
index 90e1a57..0000000
--- a/media/cdm/library_cdm/ppapi_cdm_adapter.gni
+++ /dev/null
@@ -1,76 +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.
-
-import("//build/config/compiler/compiler.gni")
-
-# This template defines a CDM adapter target. Just use this as you would a
-# normal target and everything should work correctly.
-template("ppapi_cdm_adapter") {
-  if (is_mac || is_linux) {
-    _target_type = "loadable_module"
-  } else {
-    _target_type = "shared_library"
-  }
-
-  target(_target_type, target_name) {
-    # Don't filter sources list again.
-    set_sources_assignment_filter([])
-    cflags = []
-    sources = []
-    ldflags = []
-    libs = []
-    forward_variables_from(invoker, "*")
-
-    defines += [ "USE_PPAPI_CDM_ADAPTER" ]
-    deps += [
-      "//build/config:exe_and_shlib_deps",
-      "//media/cdm:cdm_api",
-      "//ppapi/cpp",
-    ]
-    sources += [
-      "//media/cdm/cdm_helpers.cc",
-      "//media/cdm/cdm_helpers.h",
-      "//media/cdm/cdm_wrapper.h",
-      "//media/cdm/library_cdm/cdm_file_io_impl.cc",
-      "//media/cdm/library_cdm/cdm_file_io_impl.h",
-      "//media/cdm/library_cdm/cdm_logging.cc",
-      "//media/cdm/library_cdm/cdm_logging.h",
-      "//media/cdm/library_cdm/linked_ptr.h",
-      "//media/cdm/library_cdm/ppapi_cdm_adapter.cc",
-      "//media/cdm/library_cdm/ppapi_cdm_adapter.h",
-      "//media/cdm/library_cdm/ppapi_cdm_buffer.cc",
-      "//media/cdm/library_cdm/ppapi_cdm_buffer.h",
-      "//media/cdm/supported_cdm_versions.cc",
-      "//media/cdm/supported_cdm_versions.h",
-    ]
-    if (is_mac) {
-      ldflags += [
-        # Not to strip important symbols by -Wl,-dead_strip.
-        "-Wl,-exported_symbol,_PPP_GetInterface",
-        "-Wl,-exported_symbol,_PPP_InitializeModule",
-        "-Wl,-exported_symbol,_PPP_ShutdownModule",
-      ]
-
-      output_extension = "plugin"
-    } else if (is_posix) {
-      cflags += [ "-fvisibility=hidden" ]
-
-      # Required for clock_gettime()
-      libs += [ "rt" ]
-    }
-
-    if (is_linux) {
-      # CDM adapter depends on a CDM in component and non-component builds.
-      configs += [ "//build/config/gcc:rpath_for_built_shared_libraries" ]
-
-      if (use_lld) {
-        # TODO(crbug.com/795158) LLD warns about libwidevinecdm.so
-        configs -= [ "//build/config/compiler:default_fatal_linker_warnings" ]
-      }
-    }
-
-    # TODO(jschuh) crbug.com/167187
-    configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
-  }
-}
diff --git a/media/cdm/library_cdm/ppapi_cdm_adapter.h b/media/cdm/library_cdm/ppapi_cdm_adapter.h
deleted file mode 100644
index 8e25bb2..0000000
--- a/media/cdm/library_cdm/ppapi_cdm_adapter.h
+++ /dev/null
@@ -1,315 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MEDIA_CDM_LIBRARY_CDM_PPAPI_CDM_ADAPTER_H_
-#define MEDIA_CDM_LIBRARY_CDM_PPAPI_CDM_ADAPTER_H_
-
-#include <string>
-#include <vector>
-
-#include "base/compiler_specific.h"
-#include "base/macros.h"
-#include "build/build_config.h"
-#include "media/cdm/api/content_decryption_module.h"
-#include "media/cdm/cdm_helpers.h"
-#include "media/cdm/cdm_wrapper.h"
-#include "media/cdm/library_cdm/linked_ptr.h"
-#include "media/cdm/library_cdm/ppapi_cdm_buffer.h"
-#include "ppapi/c/pp_stdint.h"
-#include "ppapi/c/private/pp_content_decryptor.h"
-#include "ppapi/cpp/completion_callback.h"
-#include "ppapi/cpp/private/content_decryptor_private.h"
-#include "ppapi/cpp/private/output_protection_private.h"
-#include "ppapi/cpp/private/platform_verification.h"
-#include "ppapi/cpp/var.h"
-#include "ppapi/cpp/var_array_buffer.h"
-#include "ppapi/utility/completion_callback_factory.h"
-
-namespace media {
-
-// GetCdmHostFunc implementation.
-void* GetCdmHost(int host_interface_version, void* user_data);
-
-// An adapter class for abstracting away PPAPI interaction and threading for a
-// Content Decryption Module (CDM).
-class PpapiCdmAdapter : public pp::Instance,
-                        public pp::ContentDecryptor_Private,
-                        public cdm::Host_8,
-                        public cdm::Host_9 {
- public:
-  PpapiCdmAdapter(PP_Instance instance, pp::Module* module);
-  ~PpapiCdmAdapter() override;
-
-  // pp::Instance implementation.
-  bool Init(uint32_t argc, const char* argn[], const char* argv[]) override;
-
-  // PPP_ContentDecryptor_Private implementation.
-  // Note: Results of calls to these methods must be reported through the
-  // PPB_ContentDecryptor_Private interface.
-  void Initialize(uint32_t promise_id,
-                  const std::string& key_system,
-                  bool allow_distinctive_identifier,
-                  bool allow_persistent_state) override;
-  void SetServerCertificate(uint32_t promise_id,
-                            pp::VarArrayBuffer server_certificate) override;
-  void GetStatusForPolicy(uint32_t promise_id,
-                          PP_HdcpVersion min_hdcp_version) override;
-  void CreateSessionAndGenerateRequest(uint32_t promise_id,
-                                       PP_SessionType session_type,
-                                       PP_InitDataType init_data_type,
-                                       pp::VarArrayBuffer init_data) override;
-  void LoadSession(uint32_t promise_id,
-                   PP_SessionType session_type,
-                   const std::string& session_id) override;
-  void UpdateSession(uint32_t promise_id,
-                     const std::string& session_id,
-                     pp::VarArrayBuffer response) override;
-  void CloseSession(uint32_t promise_id,
-                    const std::string& session_id) override;
-  void RemoveSession(uint32_t promise_id,
-                     const std::string& session_id) override;
-  void Decrypt(pp::Buffer_Dev encrypted_buffer,
-               const PP_EncryptedBlockInfo& encrypted_block_info) override;
-  void InitializeAudioDecoder(const PP_AudioDecoderConfig& decoder_config,
-                              pp::Buffer_Dev extra_data_buffer) override;
-  void InitializeVideoDecoder(const PP_VideoDecoderConfig& decoder_config,
-                              pp::Buffer_Dev extra_data_buffer) override;
-  void DeinitializeDecoder(PP_DecryptorStreamType decoder_type,
-                           uint32_t request_id) override;
-  void ResetDecoder(PP_DecryptorStreamType decoder_type,
-                    uint32_t request_id) override;
-  void DecryptAndDecode(
-      PP_DecryptorStreamType decoder_type,
-      pp::Buffer_Dev encrypted_buffer,
-      const PP_EncryptedBlockInfo& encrypted_block_info) override;
-
-  // cdm::Host_9 implementation.
-  cdm::Buffer* Allocate(uint32_t capacity) override;
-  void SetTimer(int64_t delay_ms, void* context) override;
-  cdm::Time GetCurrentWallTime() override;
-  void OnResolveKeyStatusPromise(uint32_t promise_id,
-                                 cdm::KeyStatus key_status) override;
-  void OnResolveNewSessionPromise(uint32_t promise_id,
-                                  const char* session_id,
-                                  uint32_t session_id_size) override;
-  void OnResolvePromise(uint32_t promise_id) override;
-  void OnRejectPromise(uint32_t promise_id,
-                       cdm::Exception exception,
-                       uint32_t system_code,
-                       const char* error_message,
-                       uint32_t error_message_size) override;
-  void OnSessionMessage(const char* session_id,
-                        uint32_t session_id_size,
-                        cdm::MessageType message_type,
-                        const char* message,
-                        uint32_t message_size) override;
-  void OnSessionKeysChange(const char* session_id,
-                           uint32_t session_id_size,
-                           bool has_additional_usable_key,
-                           const cdm::KeyInformation* keys_info,
-                           uint32_t keys_info_count) override;
-  void OnExpirationChange(const char* session_id,
-                          uint32_t session_id_size,
-                          cdm::Time new_expiry_time) override;
-  void OnSessionClosed(const char* session_id,
-                       uint32_t session_id_size) override;
-  void SendPlatformChallenge(const char* service_id,
-                             uint32_t service_id_size,
-                             const char* challenge,
-                             uint32_t challenge_size) override;
-  void EnableOutputProtection(uint32_t desired_protection_mask) override;
-  void QueryOutputProtectionStatus() override;
-  void OnDeferredInitializationDone(cdm::StreamType stream_type,
-                                    cdm::Status decoder_status) override;
-  void RequestStorageId(uint32_t version) override;
-  cdm::FileIO* CreateFileIO(cdm::FileIOClient* client) override;
-
-  // cdm::Host_8 implementation (differences from Host_9).
-  void OnSessionMessage(const char* session_id,
-                        uint32_t session_id_size,
-                        cdm::MessageType message_type,
-                        const char* message,
-                        uint32_t message_size,
-                        const char* legacy_destination_url,
-                        uint32_t legacy_destination_url_size) override;
-  void OnRejectPromise(uint32_t promise_id,
-                       cdm::Error error,
-                       uint32_t system_code,
-                       const char* error_message,
-                       uint32_t error_message_size) override;
-  void OnLegacySessionError(const char* session_id,
-                            uint32_t session_id_size,
-                            cdm::Error error,
-                            uint32_t system_code,
-                            const char* error_message,
-                            uint32_t error_message_size) override;
-
- private:
-  // These are reported to UMA server. Do not change the existing values!
-  enum OutputProtectionStatus {
-    OUTPUT_PROTECTION_QUERIED = 0,
-    OUTPUT_PROTECTION_NO_EXTERNAL_LINK = 1,
-    OUTPUT_PROTECTION_ALL_EXTERNAL_LINKS_PROTECTED = 2,
-    OUTPUT_PROTECTION_MAX = 3
-  };
-
-  typedef linked_ptr<DecryptedBlockImpl> LinkedDecryptedBlock;
-  typedef linked_ptr<VideoFrameImpl> LinkedVideoFrame;
-  typedef linked_ptr<AudioFramesImpl> LinkedAudioFrames;
-
-  struct SessionError {
-    SessionError(cdm::Exception exception,
-                 uint32_t system_code,
-                 const std::string& error_description);
-    cdm::Exception exception;
-    uint32_t system_code;
-    std::string error_description;
-  };
-
-  struct SessionMessage {
-    SessionMessage(const std::string& session_id,
-                   cdm::MessageType message_type,
-                   const char* message,
-                   uint32_t message_size);
-    SessionMessage(const SessionMessage&);  // Allows copy.
-    ~SessionMessage();
-
-    std::string session_id;
-    cdm::MessageType message_type;
-    std::vector<uint8_t> message;
-  };
-
-  // Create an instance of the |key_system| CDM. Caller owns the returned
-  // pointer. On error (unable to load CDM, does not support |key_system|,
-  // does not support an supported interface, etc.) NULL will be returned.
-  CdmWrapper* CreateCdmInstance(const std::string& key_system);
-
-  // <code>PPB_ContentDecryptor_Private</code> dispatchers. These are passed to
-  // <code>callback_factory_</code> to ensure that calls into
-  // <code>PPP_ContentDecryptor_Private</code> are asynchronous.
-  void SendPromiseResolvedInternal(int32_t result, uint32_t promise_id);
-  void SendPromiseResolvedWithKeyStatusInternal(int32_t result,
-                                                uint32_t promise_id,
-                                                cdm::KeyStatus key_status);
-  void SendPromiseResolvedWithSessionInternal(int32_t result,
-                                              uint32_t promise_id,
-                                              const std::string& session_id);
-  void SendPromiseRejectedInternal(int32_t result,
-                                   uint32_t promise_id,
-                                   const SessionError& error);
-  void SendSessionMessageInternal(int32_t result,
-                                  const SessionMessage& message);
-  void SendSessionClosedInternal(int32_t result, const std::string& session_id);
-  void SendSessionKeysChangeInternal(
-      int32_t result,
-      const std::string& session_id,
-      bool has_additional_usable_key,
-      const std::vector<PP_KeyInformation>& key_info);
-  void SendExpirationChangeInternal(int32_t result,
-                                    const std::string& session_id,
-                                    cdm::Time new_expiry_time);
-  void RejectPromise(uint32_t promise_id,
-                     cdm::Exception exception,
-                     uint32_t system_code,
-                     const std::string& error_message);
-
-  void DeliverBlock(int32_t result,
-                    const cdm::Status& status,
-                    const LinkedDecryptedBlock& decrypted_block,
-                    const PP_DecryptTrackingInfo& tracking_info);
-  void DecoderInitializeDone(int32_t result,
-                             PP_DecryptorStreamType decoder_type,
-                             uint32_t request_id,
-                             bool success);
-  void DecoderDeinitializeDone(int32_t result,
-                               PP_DecryptorStreamType decoder_type,
-                               uint32_t request_id);
-  void DecoderResetDone(int32_t result,
-                        PP_DecryptorStreamType decoder_type,
-                        uint32_t request_id);
-  void DeliverFrame(int32_t result,
-                    const cdm::Status& status,
-                    const LinkedVideoFrame& video_frame,
-                    const PP_DecryptTrackingInfo& tracking_info);
-  void DeliverSamples(int32_t result,
-                      const cdm::Status& status,
-                      const LinkedAudioFrames& audio_frames,
-                      const PP_DecryptTrackingInfo& tracking_info);
-
-  // Helper for SetTimer().
-  void TimerExpired(int32_t result, void* context);
-
-  bool IsValidVideoFrame(const LinkedVideoFrame& video_frame);
-
-  // Callback to report |file_size_bytes| of the first file read by FileIO.
-  void OnFirstFileRead(int32_t file_size_bytes);
-
-#if !defined(NDEBUG)
-  // Logs the given message to the JavaScript console associated with the
-  // CDM adapter instance. The name of the CDM adapter issuing the log message
-  // will be automatically prepended to the message.
-  void LogToConsole(const pp::Var& value);
-#endif  // !defined(NDEBUG)
-
-  void ReportOutputProtectionUMA(OutputProtectionStatus status);
-  void ReportOutputProtectionQuery();
-  void ReportOutputProtectionQueryResult();
-
-  void EnableProtectionDone(int32_t result);
-  void QueryOutputProtectionStatusDone(int32_t result);
-
-#if defined(OS_CHROMEOS)
-  struct PepperPlatformChallengeResponse {
-    pp::Var signed_data;
-    pp::Var signed_data_signature;
-    pp::Var platform_key_certificate;
-  };
-
-  void SendPlatformChallengeDone(
-      int32_t result,
-      const linked_ptr<PepperPlatformChallengeResponse>& response);
-#endif
-
-  void RequestStorageIdDone(int32_t result,
-                            const linked_ptr<pp::Var>& response);
-
-  pp::OutputProtection_Private output_protection_;
-
-  // Same as above, these are only read by QueryOutputProtectionStatusDone().
-  uint32_t output_link_mask_;
-  uint32_t output_protection_mask_;
-  bool query_output_protection_in_progress_;
-
-  // Tracks whether an output protection query and a positive query result (no
-  // unprotected external link) have been reported to UMA.
-  bool uma_for_output_protection_query_reported_;
-  bool uma_for_output_protection_positive_result_reported_;
-
-  // Used to implement platform challenge (ChromeOS only) and access Storage ID.
-  pp::PlatformVerification platform_verification_;
-
-  PpbBufferAllocator allocator_;
-  pp::CompletionCallbackFactory<PpapiCdmAdapter> callback_factory_;
-  linked_ptr<CdmWrapper> cdm_;
-  std::string key_system_;
-  bool allow_distinctive_identifier_;
-  bool allow_persistent_state_;
-
-  // If the CDM returned kDeferredInitialization during InitializeAudioDecoder()
-  // or InitializeVideoDecoder(), the (Audio|Video)DecoderConfig.request_id is
-  // saved for the future call to OnDeferredInitializationDone().
-  bool deferred_initialize_audio_decoder_;
-  uint32_t deferred_audio_decoder_config_id_;
-  bool deferred_initialize_video_decoder_;
-  uint32_t deferred_video_decoder_config_id_;
-
-  uint32_t last_read_file_size_kb_;
-  bool file_size_uma_reported_;
-
-  DISALLOW_COPY_AND_ASSIGN(PpapiCdmAdapter);
-};
-
-}  // namespace media
-
-#endif  // MEDIA_CDM_LIBRARY_CDM_PPAPI_CDM_ADAPTER_H_
diff --git a/media/cdm/library_cdm/ppapi_cdm_buffer.cc b/media/cdm/library_cdm/ppapi_cdm_buffer.cc
deleted file mode 100644
index b9f569d4..0000000
--- a/media/cdm/library_cdm/ppapi_cdm_buffer.cc
+++ /dev/null
@@ -1,141 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "media/cdm/library_cdm/ppapi_cdm_buffer.h"
-
-#include <algorithm>
-
-#include "ppapi/cpp/core.h"
-#include "ppapi/cpp/module.h"
-
-namespace media {
-
-// static
-PpbBuffer* PpbBuffer::Create(const pp::Buffer_Dev& buffer,
-                             uint32_t buffer_id,
-                             PpbBufferAllocator* allocator) {
-  PP_DCHECK(buffer.data());
-  PP_DCHECK(buffer.size());
-  PP_DCHECK(buffer_id);
-  PP_DCHECK(allocator);
-  return new PpbBuffer(buffer, buffer_id, allocator);
-}
-
-void PpbBuffer::Destroy() {
-  delete this;
-}
-
-uint32_t PpbBuffer::Capacity() const {
-  return buffer_.size();
-}
-
-uint8_t* PpbBuffer::Data() {
-  return static_cast<uint8_t*>(buffer_.data());
-}
-
-void PpbBuffer::SetSize(uint32_t size) {
-  PP_DCHECK(size <= Capacity());
-  if (size > Capacity()) {
-    size_ = 0;
-    return;
-  }
-
-  size_ = size;
-}
-
-uint32_t PpbBuffer::Size() const {
-  return size_;
-}
-
-pp::Buffer_Dev PpbBuffer::TakeBuffer() {
-  PP_DCHECK(!buffer_.is_null());
-  pp::Buffer_Dev buffer;
-  std::swap(buffer, buffer_);
-  buffer_id_ = 0;
-  size_ = 0;
-  return buffer;
-}
-
-PpbBuffer::PpbBuffer(pp::Buffer_Dev buffer,
-                     uint32_t buffer_id,
-                     PpbBufferAllocator* allocator)
-    : buffer_(buffer), buffer_id_(buffer_id), size_(0), allocator_(allocator) {}
-
-PpbBuffer::~PpbBuffer() {
-  PP_DCHECK(!buffer_id_ == buffer_.is_null());
-  // If still owning the |buffer_|, release it in the |allocator_|.
-  if (buffer_id_)
-    allocator_->Release(buffer_id_);
-}
-
-PpbBufferAllocator::PpbBufferAllocator(pp::Instance* instance)
-    : instance_(instance), next_buffer_id_(1) {}
-
-PpbBufferAllocator::~PpbBufferAllocator() {}
-
-cdm::Buffer* PpbBufferAllocator::Allocate(uint32_t capacity) {
-  PP_DCHECK(pp::Module::Get()->core()->IsMainThread());
-
-  if (!capacity)
-    return NULL;
-
-  pp::Buffer_Dev buffer;
-  uint32_t buffer_id = 0;
-
-  // Reuse a buffer in the free list if there is one that fits |capacity|.
-  // Otherwise, create a new one.
-  FreeBufferMap::iterator found = free_buffers_.lower_bound(capacity);
-  if (found == free_buffers_.end()) {
-    // TODO(xhwang): Report statistics about how many new buffers are allocated.
-    buffer = AllocateNewBuffer(capacity);
-    if (buffer.is_null())
-      return NULL;
-    buffer_id = next_buffer_id_++;
-  } else {
-    buffer = found->second.second;
-    buffer_id = found->second.first;
-    free_buffers_.erase(found);
-  }
-
-  allocated_buffers_.insert(std::make_pair(buffer_id, buffer));
-
-  return PpbBuffer::Create(buffer, buffer_id, this);
-}
-
-void PpbBufferAllocator::Release(uint32_t buffer_id) {
-  if (!buffer_id)
-    return;
-
-  AllocatedBufferMap::iterator found = allocated_buffers_.find(buffer_id);
-  if (found == allocated_buffers_.end())
-    return;
-
-  pp::Buffer_Dev& buffer = found->second;
-  free_buffers_.insert(
-      std::make_pair(buffer.size(), std::make_pair(buffer_id, buffer)));
-
-  allocated_buffers_.erase(found);
-}
-
-pp::Buffer_Dev PpbBufferAllocator::AllocateNewBuffer(uint32_t capacity) {
-  // Always pad new allocated buffer so that we don't need to reallocate
-  // buffers frequently if requested sizes fluctuate slightly.
-  static const uint32_t kBufferPadding = 512;
-
-  // Maximum number of free buffers we can keep when allocating new buffers.
-  static const uint32_t kFreeLimit = 3;
-
-  // Destroy the smallest buffer before allocating a new bigger buffer if the
-  // number of free buffers exceeds a limit. This mechanism helps avoid ending
-  // up with too many small buffers, which could happen if the size to be
-  // allocated keeps increasing.
-  if (free_buffers_.size() >= kFreeLimit)
-    free_buffers_.erase(free_buffers_.begin());
-
-  // Creation of pp::Buffer_Dev is expensive! It involves synchronous IPC calls.
-  // That's why we try to avoid AllocateNewBuffer() as much as we can.
-  return pp::Buffer_Dev(instance_, capacity + kBufferPadding);
-}
-
-}  // namespace media
diff --git a/media/cdm/library_cdm/ppapi_cdm_buffer.h b/media/cdm/library_cdm/ppapi_cdm_buffer.h
deleted file mode 100644
index 6c6800a..0000000
--- a/media/cdm/library_cdm/ppapi_cdm_buffer.h
+++ /dev/null
@@ -1,96 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MEDIA_CDM_LIBRARY_CDM_PPAPI_CDM_BUFFER_H_
-#define MEDIA_CDM_LIBRARY_CDM_PPAPI_CDM_BUFFER_H_
-
-#include <map>
-#include <utility>
-
-#include "base/compiler_specific.h"
-#include "base/macros.h"
-#include "build/build_config.h"
-#include "media/cdm/api/content_decryption_module.h"
-#include "ppapi/c/pp_errors.h"
-#include "ppapi/c/pp_stdint.h"
-#include "ppapi/cpp/dev/buffer_dev.h"
-#include "ppapi/cpp/instance.h"
-#include "ppapi/cpp/logging.h"
-
-namespace media {
-
-class PpbBufferAllocator;
-
-// cdm::Buffer implementation that provides access to memory owned by a
-// pp::Buffer_Dev.
-// This class holds a reference to the Buffer_Dev throughout its lifetime.
-// TODO(xhwang): Find a better name. It's confusing to have PpbBuffer,
-// pp::Buffer_Dev and PPB_Buffer_Dev.
-class PpbBuffer : public cdm::Buffer {
- public:
-  static PpbBuffer* Create(const pp::Buffer_Dev& buffer,
-                           uint32_t buffer_id,
-                           PpbBufferAllocator* allocator);
-
-  // cdm::Buffer implementation.
-  void Destroy() override;
-  uint32_t Capacity() const override;
-  uint8_t* Data() override;
-  void SetSize(uint32_t size) override;
-  uint32_t Size() const override;
-
-  // Takes the |buffer_| from this class and returns it.
-  // Note: The caller must ensure |allocator->Release()| is called later so that
-  // the buffer can be reused by the allocator.
-  // Since pp::Buffer_Dev is ref-counted, the caller now holds one reference to
-  // the buffer and this class holds no reference. Note that other references
-  // may still exist. For example, PpbBufferAllocator always holds a reference
-  // to all allocated buffers.
-  pp::Buffer_Dev TakeBuffer();
-
-  uint32_t buffer_id() const { return buffer_id_; }
-
- private:
-  PpbBuffer(pp::Buffer_Dev buffer,
-            uint32_t buffer_id,
-            PpbBufferAllocator* allocator);
-  ~PpbBuffer() override;
-
-  pp::Buffer_Dev buffer_;
-  uint32_t buffer_id_;
-  uint32_t size_;
-  PpbBufferAllocator* allocator_;
-
-  DISALLOW_COPY_AND_ASSIGN(PpbBuffer);
-};
-
-class PpbBufferAllocator {
- public:
-  explicit PpbBufferAllocator(pp::Instance* instance);
-  ~PpbBufferAllocator();
-
-  cdm::Buffer* Allocate(uint32_t capacity);
-
-  // Releases the buffer with |buffer_id|. A buffer can be recycled after
-  // it is released.
-  void Release(uint32_t buffer_id);
-
- private:
-  typedef std::map<uint32_t, pp::Buffer_Dev> AllocatedBufferMap;
-  typedef std::multimap<uint32_t, std::pair<uint32_t, pp::Buffer_Dev>>
-      FreeBufferMap;
-
-  pp::Buffer_Dev AllocateNewBuffer(uint32_t capacity);
-
-  pp::Instance* const instance_;
-  uint32_t next_buffer_id_;
-  AllocatedBufferMap allocated_buffers_;
-  FreeBufferMap free_buffers_;
-
-  DISALLOW_COPY_AND_ASSIGN(PpbBufferAllocator);
-};
-
-}  // namespace media
-
-#endif  // MEDIA_CDM_LIBRARY_CDM_PPAPI_CDM_BUFFER_H_
diff --git a/media/cdm/supported_cdm_versions.h b/media/cdm/supported_cdm_versions.h
index f2e19dd..dd572b91 100644
--- a/media/cdm/supported_cdm_versions.h
+++ b/media/cdm/supported_cdm_versions.h
@@ -5,24 +5,16 @@
 #ifndef MEDIA_CDM_SUPPORTED_CDM_VERSIONS_H_
 #define MEDIA_CDM_SUPPORTED_CDM_VERSIONS_H_
 
-#ifdef USE_PPAPI_CDM_ADAPTER
-// When building the adapter these functions need to be local.
-#define FUNCTION_EXPORT
-#else
-#include "media/base/media_export.h"  // nogncheck
-#define FUNCTION_EXPORT MEDIA_EXPORT
-#endif
+#include "media/base/media_export.h"
 
 namespace media {
 
-FUNCTION_EXPORT bool IsSupportedCdmModuleVersion(int version);
+MEDIA_EXPORT bool IsSupportedCdmModuleVersion(int version);
 
-FUNCTION_EXPORT bool IsSupportedCdmInterfaceVersion(int version);
+MEDIA_EXPORT bool IsSupportedCdmInterfaceVersion(int version);
 
-FUNCTION_EXPORT bool IsSupportedCdmHostVersion(int version);
+MEDIA_EXPORT bool IsSupportedCdmHostVersion(int version);
 
 }  // namespace media
 
-#undef FUNCTION_EXPORT
-
 #endif  // MEDIA_CDM_SUPPORTED_CDM_VERSIONS_H_
diff --git a/media/midi/midi_message_queue_fuzzer.cc b/media/midi/midi_message_queue_fuzzer.cc
index e77140ad..0767774 100644
--- a/media/midi/midi_message_queue_fuzzer.cc
+++ b/media/midi/midi_message_queue_fuzzer.cc
@@ -5,6 +5,8 @@
 #include <stddef.h>
 #include <stdint.h>
 
+#include <memory>
+
 #include "media/midi/midi_message_queue.h"
 
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
diff --git a/mojo/edk/system/channel_win.cc b/mojo/edk/system/channel_win.cc
index 421fd54..285ccf4 100644
--- a/mojo/edk/system/channel_win.cc
+++ b/mojo/edk/system/channel_win.cc
@@ -27,48 +27,6 @@
 
 namespace {
 
-// A view over a Channel::Message object. The write queue uses these since
-// large messages may need to be sent in chunks.
-class MessageView {
- public:
-  // Owns |message|. |offset| indexes the first unsent byte in the message.
-  MessageView(Channel::MessagePtr message, size_t offset)
-      : message_(std::move(message)),
-        offset_(offset) {
-    DCHECK_GT(message_->data_num_bytes(), offset_);
-  }
-
-  MessageView(MessageView&& other) { *this = std::move(other); }
-
-  MessageView& operator=(MessageView&& other) {
-    message_ = std::move(other.message_);
-    offset_ = other.offset_;
-    return *this;
-  }
-
-  ~MessageView() {}
-
-  const void* data() const {
-    return static_cast<const char*>(message_->data()) + offset_;
-  }
-
-  size_t data_num_bytes() const { return message_->data_num_bytes() - offset_; }
-
-  size_t data_offset() const { return offset_; }
-  void advance_data_offset(size_t num_bytes) {
-    DCHECK_GE(message_->data_num_bytes(), offset_ + num_bytes);
-    offset_ += num_bytes;
-  }
-
-  Channel::MessagePtr TakeChannelMessage() { return std::move(message_); }
-
- private:
-  Channel::MessagePtr message_;
-  size_t offset_;
-
-  DISALLOW_COPY_AND_ASSIGN(MessageView);
-};
-
 class ChannelWin : public Channel,
                    public base::MessageLoop::DestructionObserver,
                    public base::MessageLoopForIO::IOHandler {
@@ -102,7 +60,7 @@
         return;
 
       bool write_now = !delay_writes_ && outgoing_messages_.empty();
-      outgoing_messages_.emplace_back(std::move(message), 0);
+      outgoing_messages_.emplace_back(std::move(message));
       if (write_now && !WriteNoLock(outgoing_messages_.front()))
         reject_writes_ = write_error = true;
     }
@@ -184,7 +142,8 @@
       }
     }
 
-    // Keep this alive in case we synchronously run shutdown.
+    // Keep this alive in case we synchronously run shutdown, via OnError(),
+    // as a result of a ReadFile() failure on the channel.
     scoped_refptr<ChannelWin> keep_alive(this);
     ReadMore(0);
   }
@@ -263,21 +222,22 @@
     {
       base::AutoLock lock(write_lock_);
 
+      DCHECK(is_write_pending_);
+      is_write_pending_ = false;
       DCHECK(!outgoing_messages_.empty());
 
-      MessageView& message_view = outgoing_messages_.front();
-      message_view.advance_data_offset(bytes_written);
-      if (message_view.data_num_bytes() == 0) {
-        Channel::MessagePtr message = message_view.TakeChannelMessage();
-        outgoing_messages_.pop_front();
+      Channel::MessagePtr message = std::move(outgoing_messages_.front());
+      outgoing_messages_.pop_front();
 
-        // Clear any handles so they don't get closed on destruction.
-        std::vector<ScopedPlatformHandle> handles = message->TakeHandles();
-        for (auto& handle : handles)
-          ignore_result(handle.release());
-      }
+      // Clear any handles so they don't get closed on destruction.
+      std::vector<ScopedPlatformHandle> handles = message->TakeHandles();
+      for (auto& handle : handles)
+        ignore_result(handle.release());
 
-      if (!WriteNextNoLock())
+      // Overlapped WriteFile() to a pipe should always fully complete.
+      if (message->data_num_bytes() != bytes_written)
+        reject_writes_ = write_error = true;
+      else if (!WriteNextNoLock())
         reject_writes_ = write_error = true;
     }
     if (write_error)
@@ -308,14 +268,13 @@
   // Attempts to write a message directly to the channel. If the full message
   // cannot be written, it's queued and a wait is initiated to write the message
   // ASAP on the I/O thread.
-  bool WriteNoLock(const MessageView& message_view) {
-    BOOL ok = WriteFile(handle_.get().handle,
-                        message_view.data(),
-                        static_cast<DWORD>(message_view.data_num_bytes()),
-                        NULL,
+  bool WriteNoLock(const Channel::MessagePtr& message) {
+    BOOL ok = WriteFile(handle_.get().handle, message->data(),
+                        static_cast<DWORD>(message->data_num_bytes()), NULL,
                         &write_context_.overlapped);
 
     if (ok || GetLastError() == ERROR_IO_PENDING) {
+      is_write_pending_ = true;
       AddRef();
       return true;
     }
@@ -347,19 +306,20 @@
   scoped_refptr<Channel> self_;
 
   ScopedPlatformHandle handle_;
-  scoped_refptr<base::TaskRunner> io_task_runner_;
+  const scoped_refptr<base::TaskRunner> io_task_runner_;
 
   base::MessageLoopForIO::IOContext connect_context_;
   base::MessageLoopForIO::IOContext read_context_;
-  base::MessageLoopForIO::IOContext write_context_;
   bool is_connect_pending_ = false;
   bool is_read_pending_ = false;
 
-  // Protects |delay_writes_|, |reject_writes_| and |outgoing_messages_|.
+  // Protects all fields potentially accessed on multiple threads via Write().
   base::Lock write_lock_;
-  base::circular_deque<MessageView> outgoing_messages_;
+  base::MessageLoopForIO::IOContext write_context_;
+  base::circular_deque<Channel::MessagePtr> outgoing_messages_;
   bool delay_writes_ = true;
   bool reject_writes_ = false;
+  bool is_write_pending_ = false;
 
   bool leak_handle_ = false;
 
diff --git a/mojo/public/cpp/bindings/BUILD.gn b/mojo/public/cpp/bindings/BUILD.gn
index 55b7ba7c..cefb31d 100644
--- a/mojo/public/cpp/bindings/BUILD.gn
+++ b/mojo/public/cpp/bindings/BUILD.gn
@@ -56,7 +56,6 @@
     "lib/serialization_forward.h",
     "lib/serialization_util.h",
     "lib/string_serialization.h",
-    "lib/string_traits_string16.cc",
     "lib/template_util.h",
     "lib/unserialized_message_context.cc",
     "lib/unserialized_message_context.h",
@@ -77,7 +76,6 @@
     "string_data_view.h",
     "string_traits.h",
     "string_traits_stl.h",
-    "string_traits_string16.h",
     "string_traits_string_piece.h",
     "struct_ptr.h",
     "struct_traits.h",
diff --git a/mojo/public/cpp/bindings/lib/serialization.h b/mojo/public/cpp/bindings/lib/serialization.h
index d4fdfd6..98bc273 100644
--- a/mojo/public/cpp/bindings/lib/serialization.h
+++ b/mojo/public/cpp/bindings/lib/serialization.h
@@ -22,7 +22,6 @@
 #include "mojo/public/cpp/bindings/map_traits_stl.h"
 #include "mojo/public/cpp/bindings/message.h"
 #include "mojo/public/cpp/bindings/string_traits_stl.h"
-#include "mojo/public/cpp/bindings/string_traits_string16.h"
 #include "mojo/public/cpp/bindings/string_traits_string_piece.h"
 
 namespace mojo {
diff --git a/mojo/public/cpp/bindings/lib/string_traits_string16.cc b/mojo/public/cpp/bindings/lib/string_traits_string16.cc
deleted file mode 100644
index 95ff6ccf..0000000
--- a/mojo/public/cpp/bindings/lib/string_traits_string16.cc
+++ /dev/null
@@ -1,42 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "mojo/public/cpp/bindings/string_traits_string16.h"
-
-#include <string>
-
-#include "base/strings/utf_string_conversions.h"
-
-namespace mojo {
-
-// static
-void* StringTraits<base::string16>::SetUpContext(const base::string16& input) {
-  return new std::string(base::UTF16ToUTF8(input));
-}
-
-// static
-void StringTraits<base::string16>::TearDownContext(const base::string16& input,
-                                                   void* context) {
-  delete static_cast<std::string*>(context);
-}
-
-// static
-size_t StringTraits<base::string16>::GetSize(const base::string16& input,
-                                             void* context) {
-  return static_cast<std::string*>(context)->size();
-}
-
-// static
-const char* StringTraits<base::string16>::GetData(const base::string16& input,
-                                                  void* context) {
-  return static_cast<std::string*>(context)->data();
-}
-
-// static
-bool StringTraits<base::string16>::Read(StringDataView input,
-                                        base::string16* output) {
-  return base::UTF8ToUTF16(input.storage(), input.size(), output);
-}
-
-}  // namespace mojo
diff --git a/mojo/public/cpp/bindings/string_traits_string16.h b/mojo/public/cpp/bindings/string_traits_string16.h
deleted file mode 100644
index 26f7f1db..0000000
--- a/mojo/public/cpp/bindings/string_traits_string16.h
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MOJO_PUBLIC_CPP_BINDINGS_STRING_TRAITS_STRING16_H_
-#define MOJO_PUBLIC_CPP_BINDINGS_STRING_TRAITS_STRING16_H_
-
-#include "base/component_export.h"
-#include "base/strings/string16.h"
-#include "mojo/public/cpp/bindings/string_data_view.h"
-#include "mojo/public/cpp/bindings/string_traits.h"
-
-namespace mojo {
-
-template <>
-struct COMPONENT_EXPORT(MOJO_CPP_BINDINGS_BASE) StringTraits<base::string16> {
-  static bool IsNull(const base::string16& input) {
-    // base::string16 is always converted to non-null mojom string.
-    return false;
-  }
-
-  static void SetToNull(base::string16* output) {
-    // Convert null to an "empty" base::string16.
-    output->clear();
-  }
-
-  static void* SetUpContext(const base::string16& input);
-  static void TearDownContext(const base::string16& input, void* context);
-
-  static size_t GetSize(const base::string16& input, void* context);
-  static const char* GetData(const base::string16& input, void* context);
-
-  static bool Read(StringDataView input, base::string16* output);
-};
-
-}  // namespace mojo
-
-#endif  // MOJO_PUBLIC_CPP_BINDINGS_STRING_TRAITS_STRING16_H_
diff --git a/net/http/bidirectional_stream.cc b/net/http/bidirectional_stream.cc
index 6f3d354..ffbe1f52 100644
--- a/net/http/bidirectional_stream.cc
+++ b/net/http/bidirectional_stream.cc
@@ -104,10 +104,6 @@
                    base::Unretained(&request_info_->extra_headers)));
   }
 
-  SSLConfig server_ssl_config;
-  session->ssl_config_service()->GetSSLConfig(&server_ssl_config);
-  session->GetAlpnProtos(&server_ssl_config.alpn_protos);
-
   if (!request_info_->url.SchemeIs(url::kHttpsScheme)) {
     base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
@@ -116,22 +112,11 @@
     return;
   }
 
-  HttpRequestInfo http_request_info;
-  http_request_info.url = request_info_->url;
-  http_request_info.method = request_info_->method;
-  http_request_info.extra_headers = request_info_->extra_headers;
-  http_request_info.socket_tag = request_info_->socket_tag;
-  stream_request_ =
-      session->http_stream_factory()->RequestBidirectionalStreamImpl(
-          http_request_info, request_info_->priority, server_ssl_config,
-          server_ssl_config, this,
-          /* enable_ip_based_pooling = */ true,
-          /* enable_alternative_services = */ true, net_log_);
-  // Check that this call cannot fail to set a non-NULL |stream_request_|.
-  DCHECK(stream_request_);
-  // Check that HttpStreamFactory does not invoke OnBidirectionalStreamImplReady
-  // synchronously.
-  DCHECK(!stream_impl_);
+  SSLConfig ssl_config;
+  session->ssl_config_service()->GetSSLConfig(&ssl_config);
+  session->GetAlpnProtos(&ssl_config.alpn_protos);
+
+  StartRequest(ssl_config);
 }
 
 BidirectionalStream::~BidirectionalStream() {
@@ -220,6 +205,26 @@
     stream_impl_->PopulateNetErrorDetails(details);
 }
 
+void BidirectionalStream::StartRequest(const SSLConfig& ssl_config) {
+  DCHECK(!stream_request_);
+  HttpRequestInfo http_request_info;
+  http_request_info.url = request_info_->url;
+  http_request_info.method = request_info_->method;
+  http_request_info.extra_headers = request_info_->extra_headers;
+  http_request_info.socket_tag = request_info_->socket_tag;
+  stream_request_ =
+      session_->http_stream_factory()->RequestBidirectionalStreamImpl(
+          http_request_info, request_info_->priority, ssl_config, ssl_config,
+          this,
+          /* enable_ip_based_pooling = */ true,
+          /* enable_alternative_services = */ true, net_log_);
+  // Check that this call does not fail.
+  DCHECK(stream_request_);
+  // Check that HttpStreamFactory does not invoke OnBidirectionalStreamImplReady
+  // synchronously.
+  DCHECK(!stream_impl_);
+}
+
 void BidirectionalStream::OnStreamReady(bool request_headers_sent) {
   request_headers_sent_ = request_headers_sent;
   if (net_log_.IsCapturing()) {
@@ -402,7 +407,16 @@
                                             SSLCertRequestInfo* cert_info) {
   DCHECK(stream_request_);
 
-  NotifyFailed(ERR_SSL_CLIENT_AUTH_CERT_NEEDED);
+  // BidirectionalStream doesn't support client auth. It ignores client auth
+  // requests with null client cert and key.
+  SSLConfig ssl_config = used_ssl_config;
+  ssl_config.send_client_cert = true;
+  ssl_config.client_cert = nullptr;
+  ssl_config.client_private_key = nullptr;
+  session_->ssl_client_auth_cache()->Add(cert_info->host_and_port, nullptr,
+                                         nullptr);
+  stream_request_ = nullptr;
+  StartRequest(ssl_config);
 }
 
 void BidirectionalStream::OnHttpsProxyTunnelResponse(
diff --git a/net/http/bidirectional_stream.h b/net/http/bidirectional_stream.h
index 6fffad72..854bb29 100644
--- a/net/http/bidirectional_stream.h
+++ b/net/http/bidirectional_stream.h
@@ -176,6 +176,7 @@
   void PopulateNetErrorDetails(NetErrorDetails* details);
 
  private:
+  void StartRequest(const SSLConfig& ssl_config);
   // BidirectionalStreamImpl::Delegate implementation:
   void OnStreamReady(bool request_headers_sent) override;
   void OnHeadersReceived(const SpdyHeaderBlock& response_headers) override;
diff --git a/net/http/bidirectional_stream_unittest.cc b/net/http/bidirectional_stream_unittest.cc
index b78e099..5d736e96 100644
--- a/net/http/bidirectional_stream_unittest.cc
+++ b/net/http/bidirectional_stream_unittest.cc
@@ -32,6 +32,7 @@
 #include "net/socket/socket_test_util.h"
 #include "net/spdy/chromium/spdy_session.h"
 #include "net/spdy/chromium/spdy_test_util_common.h"
+#include "net/ssl/ssl_cert_request_info.h"
 #include "net/test/cert_test_util.h"
 #include "net/test/gtest_util.h"
 #include "net/test/test_data_directory.h"
@@ -579,6 +580,70 @@
   base::RunLoop().RunUntilIdle();
 }
 
+TEST_F(BidirectionalStreamTest, ClientAuthRequestIgnored) {
+  scoped_refptr<SSLCertRequestInfo> cert_request(new SSLCertRequestInfo());
+  cert_request->host_and_port = host_port_pair_;
+
+  // First attempt receives client auth request.
+  SSLSocketDataProvider ssl_data1(ASYNC, ERR_SSL_CLIENT_AUTH_CERT_NEEDED);
+  ssl_data1.next_proto = kProtoHTTP2;
+  ssl_data1.cert_request_info = cert_request.get();
+
+  session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_data1);
+  StaticSocketDataProvider socket_data1(nullptr, 0, nullptr, 0);
+  session_deps_.socket_factory->AddSocketDataProvider(&socket_data1);
+
+  // Second attempt succeeds.
+  SpdySerializedFrame req(spdy_util_.ConstructSpdyGet(kDefaultUrl, 1, LOWEST));
+  MockWrite writes[] = {
+      CreateMockWrite(req, 0),
+  };
+  SpdySerializedFrame resp(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
+  SpdySerializedFrame body_frame(spdy_util_.ConstructSpdyDataFrame(1, true));
+  MockRead reads[] = {
+      CreateMockRead(resp, 1), CreateMockRead(body_frame, 2),
+      MockRead(SYNCHRONOUS, net::OK, 3),
+  };
+
+  SSLSocketDataProvider ssl_data2(ASYNC, OK);
+  ssl_data2.next_proto = kProtoHTTP2;
+  session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_data2);
+  SequencedSocketData socket_data2(reads, arraysize(reads), writes,
+                                   arraysize(writes));
+  session_deps_.socket_factory->AddSocketDataProvider(&socket_data2);
+
+  http_session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps_);
+  SpdySessionKey key(host_port_pair_, ProxyServer::Direct(),
+                     PRIVACY_MODE_DISABLED, SocketTag());
+  std::unique_ptr<BidirectionalStreamRequestInfo> request_info(
+      new BidirectionalStreamRequestInfo);
+  request_info->method = "GET";
+  request_info->url = default_url_;
+  request_info->end_stream_on_headers = true;
+  request_info->priority = LOWEST;
+
+  scoped_refptr<IOBuffer> read_buffer(new IOBuffer(kReadBufferSize));
+  std::unique_ptr<TestDelegateBase> delegate(
+      new TestDelegateBase(read_buffer.get(), kReadBufferSize));
+
+  delegate->SetRunUntilCompletion(true);
+  delegate->Start(std::move(request_info), http_session_.get());
+
+  // Ensure the certificate was added to the client auth cache.
+  scoped_refptr<X509Certificate> client_cert;
+  scoped_refptr<SSLPrivateKey> client_private_key;
+  ASSERT_TRUE(http_session_->ssl_client_auth_cache()->Lookup(
+      host_port_pair_, &client_cert, &client_private_key));
+  ASSERT_FALSE(client_cert);
+  ASSERT_FALSE(client_private_key);
+
+  const SpdyHeaderBlock& response_headers = delegate->response_headers();
+  EXPECT_EQ("200", response_headers.find(":status")->second);
+  EXPECT_EQ(1, delegate->on_data_read_count());
+  EXPECT_EQ(0, delegate->on_data_sent_count());
+  EXPECT_EQ(kProtoHTTP2, delegate->GetProtocol());
+}
+
 // Simulates user calling ReadData after END_STREAM has been received in
 // BidirectionalStreamSpdyImpl.
 TEST_F(BidirectionalStreamTest, TestReadDataAfterClose) {
diff --git a/net/socket/fuzzed_socket.cc b/net/socket/fuzzed_socket.cc
index be62fff..0ac8a6cb 100644
--- a/net/socket/fuzzed_socket.cc
+++ b/net/socket/fuzzed_socket.cc
@@ -19,6 +19,8 @@
 
 namespace {
 
+const int kMaxAsyncReadsAndWrites = 1000;
+
 // Some of the socket errors that can be returned by normal socket connection
 // attempts.
 const Error kConnectErrors[] = {
@@ -57,8 +59,12 @@
     result = net_error_;
     sync = !error_pending_;
   } else {
-    // Otherwise, use |data_provider_|.
-    sync = data_provider_->ConsumeBool();
+    // Otherwise, use |data_provider_|. Always consume a bool, even when
+    // ForceSync() is true, to behave more consistently against input mutations.
+    sync = data_provider_->ConsumeBool() || ForceSync();
+
+    num_async_reads_and_writes_ += static_cast<int>(!sync);
+
     std::string data = data_provider_->ConsumeRandomLengthString(buf_len);
     result = data.size();
 
@@ -106,8 +112,12 @@
     result = net_error_;
     sync = !error_pending_;
   } else {
-    // Otherwise, use |data_|.
-    sync = data_provider_->ConsumeBool();
+    // Otherwise, use |data_provider_|. Always consume a bool, even when
+    // ForceSync() is true, to behave more consistently against input mutations.
+    sync = data_provider_->ConsumeBool() || ForceSync();
+
+    num_async_reads_and_writes_ += static_cast<int>(!sync);
+
     result = data_provider_->ConsumeUint8();
     if (result > buf_len)
       result = buf_len;
@@ -283,4 +293,8 @@
   callback.Run(result);
 }
 
+bool FuzzedSocket::ForceSync() const {
+  return (num_async_reads_and_writes_ >= kMaxAsyncReadsAndWrites);
+}
+
 }  // namespace net
diff --git a/net/socket/fuzzed_socket.h b/net/socket/fuzzed_socket.h
index 3340e43..f4dcaab 100644
--- a/net/socket/fuzzed_socket.h
+++ b/net/socket/fuzzed_socket.h
@@ -99,6 +99,12 @@
   void OnWriteComplete(const CompletionCallback& callback, int result);
   void OnConnectComplete(const CompletionCallback& callback, int result);
 
+  // Returns whether all operations should be synchronous.  Starts returning
+  // true once there have been too many async reads and writes, as spinning the
+  // message loop too often tends to cause fuzzers to time out.
+  // See https://crbug.com/823012
+  bool ForceSync() const;
+
   base::FuzzedDataProvider* data_provider_;
 
   // If true, the result of the Connect() call is fuzzed - it can succeed or
@@ -122,6 +128,8 @@
   int64_t total_bytes_read_ = 0;
   int64_t total_bytes_written_ = 0;
 
+  int num_async_reads_and_writes_ = 0;
+
   NetLogWithSource net_log_;
 
   IPEndPoint remote_address_;
diff --git a/net/spdy/core/hpack/hpack_entry.cc b/net/spdy/core/hpack/hpack_entry.cc
index a948877..84e21f5 100644
--- a/net/spdy/core/hpack/hpack_entry.cc
+++ b/net/spdy/core/hpack/hpack_entry.cc
@@ -7,6 +7,7 @@
 #include "base/logging.h"
 #include "base/strings/string_number_conversions.h"
 #include "net/spdy/platform/api/spdy_estimate_memory_usage.h"
+#include "net/spdy/platform/api/spdy_string_utils.h"
 
 namespace net {
 
@@ -75,11 +76,10 @@
 }
 
 SpdyString HpackEntry::GetDebugString() const {
-  return "{ name: \"" + SpdyString(name_ref_) + "\", value: \"" +
-         SpdyString(value_ref_) +
-         "\", index: " + base::NumberToString(insertion_index_) +
-         (IsStatic() ? " static" : (IsLookup() ? " lookup" : " dynamic")) +
-         " }";
+  return SpdyStringPrintf(
+      "{ name: \"%.*s\", value: \"%.*s\", index: %d %s }", name_ref_.size(),
+      name_ref_.data(), value_ref_.size(), value_ref_.data(), insertion_index_,
+      (IsStatic() ? " static" : (IsLookup() ? " lookup" : " dynamic")));
 }
 
 size_t HpackEntry::EstimateMemoryUsage() const {
diff --git a/net/url_request/url_request_http_job.cc b/net/url_request/url_request_http_job.cc
index da697315..7ed0c12 100644
--- a/net/url_request/url_request_http_job.cc
+++ b/net/url_request/url_request_http_job.cc
@@ -229,22 +229,32 @@
                             EPHEMERALITY_MAX);
 }
 
-void LogCookieAgeForNonSecureRequest(const net::CookieList& cookie_list,
-                                     const net::URLRequest& request) {
-  base::Time oldest = base::Time::Max();
-  for (const auto& cookie : cookie_list)
-    oldest = std::min(cookie.CreationDate(), oldest);
-  base::TimeDelta delta = base::Time::Now() - oldest;
+void LogCookieUMA(const net::CookieList& cookie_list,
+                  const net::URLRequest& request,
+                  const net::HttpRequestInfo& request_info) {
+  const bool secure_request = request_info.url.SchemeIsCryptographic();
+  const bool same_site = net::registry_controlled_domains::SameDomainOrHost(
+      request.url(), request.site_for_cookies(),
+      net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES);
 
-  if (net::registry_controlled_domains::SameDomainOrHost(
-          request.url(), request.site_for_cookies(),
-          net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES)) {
-    UMA_HISTOGRAM_COUNTS_1000("Cookie.AgeForNonSecureSameSiteRequest",
-                              delta.InDays());
-  } else {
-    UMA_HISTOGRAM_COUNTS_1000("Cookie.AgeForNonSecureCrossSiteRequest",
-                              delta.InDays());
+  const base::Time now = base::Time::Now();
+  base::Time oldest = base::Time::Max();
+  for (const auto& cookie : cookie_list) {
+    const std::string histogram_name =
+        std::string("Cookie.AllAgesFor") +
+        (secure_request ? "Secure" : "NonSecure") +
+        (same_site ? "SameSite" : "CrossSite") + "Request";
+    const int age_in_days = (now - cookie.CreationDate()).InDays();
+    base::UmaHistogramCounts1000(histogram_name, age_in_days);
+
+    oldest = std::min(cookie.CreationDate(), oldest);
   }
+
+  const std::string histogram_name =
+      std::string("Cookie.AgeFor") + (secure_request ? "Secure" : "NonSecure") +
+      (same_site ? "SameSite" : "CrossSite") + "Request";
+  const int age_in_days = (now - oldest).InDays();
+  base::UmaHistogramCounts1000(histogram_name, age_in_days);
 }
 
 }  // namespace
@@ -680,8 +690,7 @@
 
 void URLRequestHttpJob::SetCookieHeaderAndStart(const CookieList& cookie_list) {
   if (!cookie_list.empty() && CanGetCookies(cookie_list)) {
-    if (!request_info_.url.SchemeIsCryptographic())
-      LogCookieAgeForNonSecureRequest(cookie_list, *request_);
+    LogCookieUMA(cookie_list, *request_, request_info_);
 
     std::string cookie_line = CanonicalCookie::BuildCookieLine(cookie_list);
     UMA_HISTOGRAM_COUNTS_10000("Cookie.HeaderLength", cookie_line.length());
diff --git a/net/url_request/url_request_unittest.cc b/net/url_request/url_request_unittest.cc
index e4983b01..222829a3e 100644
--- a/net/url_request/url_request_unittest.cc
+++ b/net/url_request/url_request_unittest.cc
@@ -3318,23 +3318,54 @@
   {
     TestDelegate d;
     std::unique_ptr<URLRequest> req(default_context_.CreateRequest(
-        http_server.GetURL(kHost, "/set-cookie?cookie=value"), DEFAULT_PRIORITY,
-        &d, TRAFFIC_ANNOTATION_FOR_TESTS));
+        http_server.GetURL(kHost, "/set-cookie?cookie=value&cookie2=value2"),
+        DEFAULT_PRIORITY, &d, TRAFFIC_ANNOTATION_FOR_TESTS));
     req->Start();
     base::RunLoop().Run();
-    ASSERT_EQ(1, network_delegate.set_cookie_count());
+    ASSERT_EQ(2, network_delegate.set_cookie_count());
   }
 
-  // Make a secure request to `example.test`: we shouldn't record data.
+  // Make a secure same-site request.
   {
     TestDelegate d;
     std::unique_ptr<URLRequest> req(default_context_.CreateRequest(
         https_server.GetURL(kHost, "/echoheader?Cookie"), DEFAULT_PRIORITY, &d,
         TRAFFIC_ANNOTATION_FOR_TESTS));
+    req->set_site_for_cookies(https_server.GetURL(kHost, "/"));
+    req->set_initiator(url::Origin::Create(https_server.GetURL(kHost, "/")));
     req->Start();
     base::RunLoop().Run();
     histograms.ExpectTotalCount("Cookie.AgeForNonSecureCrossSiteRequest", 0);
     histograms.ExpectTotalCount("Cookie.AgeForNonSecureSameSiteRequest", 0);
+    histograms.ExpectTotalCount("Cookie.AgeForSecureCrossSiteRequest", 0);
+    histograms.ExpectTotalCount("Cookie.AgeForSecureSameSiteRequest", 1);
+    histograms.ExpectTotalCount("Cookie.AllAgesForNonSecureCrossSiteRequest",
+                                0);
+    histograms.ExpectTotalCount("Cookie.AllAgesForNonSecureSameSiteRequest", 0);
+    histograms.ExpectTotalCount("Cookie.AllAgesForSecureCrossSiteRequest", 0);
+    histograms.ExpectTotalCount("Cookie.AllAgesForSecureSameSiteRequest", 2);
+  }
+
+  // Make a secure cross-site request.
+  {
+    TestDelegate d;
+    std::unique_ptr<URLRequest> req(default_context_.CreateRequest(
+        https_server.GetURL(kHost, "/echoheader?Cookie"), DEFAULT_PRIORITY, &d,
+        TRAFFIC_ANNOTATION_FOR_TESTS));
+    req->set_site_for_cookies(https_server.GetURL(kCrossHost, "/"));
+    req->set_initiator(
+        url::Origin::Create(https_server.GetURL(kCrossHost, "/")));
+    req->Start();
+    base::RunLoop().Run();
+    histograms.ExpectTotalCount("Cookie.AgeForNonSecureCrossSiteRequest", 0);
+    histograms.ExpectTotalCount("Cookie.AgeForNonSecureSameSiteRequest", 0);
+    histograms.ExpectTotalCount("Cookie.AgeForSecureCrossSiteRequest", 1);
+    histograms.ExpectTotalCount("Cookie.AgeForSecureSameSiteRequest", 1);
+    histograms.ExpectTotalCount("Cookie.AllAgesForNonSecureCrossSiteRequest",
+                                0);
+    histograms.ExpectTotalCount("Cookie.AllAgesForNonSecureSameSiteRequest", 0);
+    histograms.ExpectTotalCount("Cookie.AllAgesForSecureCrossSiteRequest", 2);
+    histograms.ExpectTotalCount("Cookie.AllAgesForSecureSameSiteRequest", 2);
   }
 
   // Make a non-secure same-site request.
@@ -3349,6 +3380,13 @@
     base::RunLoop().Run();
     histograms.ExpectTotalCount("Cookie.AgeForNonSecureCrossSiteRequest", 0);
     histograms.ExpectTotalCount("Cookie.AgeForNonSecureSameSiteRequest", 1);
+    histograms.ExpectTotalCount("Cookie.AgeForSecureCrossSiteRequest", 1);
+    histograms.ExpectTotalCount("Cookie.AgeForSecureSameSiteRequest", 1);
+    histograms.ExpectTotalCount("Cookie.AllAgesForNonSecureCrossSiteRequest",
+                                0);
+    histograms.ExpectTotalCount("Cookie.AllAgesForNonSecureSameSiteRequest", 2);
+    histograms.ExpectTotalCount("Cookie.AllAgesForSecureCrossSiteRequest", 2);
+    histograms.ExpectTotalCount("Cookie.AllAgesForSecureSameSiteRequest", 2);
   }
 
   // Make a non-secure cross-site request.
@@ -3364,6 +3402,13 @@
     base::RunLoop().Run();
     histograms.ExpectTotalCount("Cookie.AgeForNonSecureCrossSiteRequest", 1);
     histograms.ExpectTotalCount("Cookie.AgeForNonSecureSameSiteRequest", 1);
+    histograms.ExpectTotalCount("Cookie.AgeForSecureCrossSiteRequest", 1);
+    histograms.ExpectTotalCount("Cookie.AgeForSecureSameSiteRequest", 1);
+    histograms.ExpectTotalCount("Cookie.AllAgesForNonSecureCrossSiteRequest",
+                                2);
+    histograms.ExpectTotalCount("Cookie.AllAgesForNonSecureSameSiteRequest", 2);
+    histograms.ExpectTotalCount("Cookie.AllAgesForSecureCrossSiteRequest", 2);
+    histograms.ExpectTotalCount("Cookie.AllAgesForSecureSameSiteRequest", 2);
   }
 }
 
diff --git a/pdf/pdfium/pdfium_range.cc b/pdf/pdfium/pdfium_range.cc
index fb1d94b..cfe4e562 100644
--- a/pdf/pdfium/pdfium_range.cc
+++ b/pdf/pdfium/pdfium_range.cc
@@ -46,6 +46,10 @@
     char_count *= -1;
     char_index -= char_count - 1;
   }
+  DCHECK_GE(char_index, 0) << "start: " << char_index_
+                           << " count: " << char_count_;
+  DCHECK_LT(char_index, FPDFText_CountChars(page_->GetTextPage()))
+      << "start: " << char_index_ << " count: " << char_count_;
 
   int count = FPDFText_CountRects(page_->GetTextPage(), char_index, char_count);
   for (int i = 0; i < count; ++i) {
diff --git a/remoting/host/file_proxy_wrapper_linux_unittest.cc b/remoting/host/file_proxy_wrapper_linux_unittest.cc
index 69efa45..e32d486 100644
--- a/remoting/host/file_proxy_wrapper_linux_unittest.cc
+++ b/remoting/host/file_proxy_wrapper_linux_unittest.cc
@@ -87,7 +87,7 @@
   final_state_ = FileProxyWrapper::kUninitialized;
   done_callback_succeeded_ = false;
 
-  read_chunks_ = {};
+  read_chunks_ = base::queue<std::vector<char>>();
   read_filesize_ = 0;
 }
 
diff --git a/remoting/host/linux/BUILD.gn b/remoting/host/linux/BUILD.gn
index c58650e8..89a9c708 100644
--- a/remoting/host/linux/BUILD.gn
+++ b/remoting/host/linux/BUILD.gn
@@ -2,6 +2,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import("//build/config/c++/c++.gni")
 import("//remoting/build/config/remoting_build.gni")
 
 group("all_tests") {
@@ -58,16 +59,14 @@
     ]
     deps = [
       ":remoting_user_session",
+      "//build/config:exe_and_shlib_deps",
     ]
     if (is_component_build) {
-      sources += [
-        "$root_build_dir/libbase.so",
-        "$root_build_dir/libc++.so",
-      ]
-      deps += [
-        "//base:base",
-        "//buildtools/third_party/libc++:libc++",
-      ]
+      sources += [ "$root_build_dir/libbase.so" ]
+      deps += [ "//base:base" ]
+    }
+    if (!libcpp_is_static && use_custom_libcxx) {
+      sources += [ "$root_build_dir/libc++.so" ]
     }
   }
 
diff --git a/sandbox/BUILD.gn b/sandbox/BUILD.gn
index ac5e2c6..90893fae 100644
--- a/sandbox/BUILD.gn
+++ b/sandbox/BUILD.gn
@@ -40,19 +40,21 @@
 
 # This target must be here and not in win/ otherwise it would require a full
 # parse of win/BUILD.gn which fails on non-Windows platforms.
-fuzzer_test("sandbox_ipc_fuzzer") {
-  set_sources_assignment_filter([])
-  sources = [
-    "ipc.dict",
-    "win/fuzzer/fuzzer_defines.h",
-    "win/fuzzer/sandbox_ipc_fuzzer.cc",
-    "win/src/crosscall_server.cc",
-    "win/src/ipc_args.cc",
-  ]
-  defines = [ "SANDBOX_FUZZ_TARGET" ]
-  deps = [
-    "//base",
-  ]
-  dict = "ipc.dict"
-  libfuzzer_options = [ "max_len=1024" ]
+if (is_win) {
+  fuzzer_test("sandbox_ipc_fuzzer") {
+    set_sources_assignment_filter([])
+    sources = [
+      "ipc.dict",
+      "win/fuzzer/fuzzer_defines.h",
+      "win/fuzzer/sandbox_ipc_fuzzer.cc",
+      "win/src/crosscall_server.cc",
+      "win/src/ipc_args.cc",
+    ]
+    defines = [ "SANDBOX_FUZZ_TARGET" ]
+    deps = [
+      "//base",
+    ]
+    dict = "ipc.dict"
+    libfuzzer_options = [ "max_len=1024" ]
+  }
 }
diff --git a/services/viz/public/cpp/compositing/local_surface_id_struct_traits.h b/services/viz/public/cpp/compositing/local_surface_id_struct_traits.h
index 6325933..6c0aba8 100644
--- a/services/viz/public/cpp/compositing/local_surface_id_struct_traits.h
+++ b/services/viz/public/cpp/compositing/local_surface_id_struct_traits.h
@@ -23,16 +23,16 @@
     return local_surface_id.child_sequence_number();
   }
 
-  static const base::UnguessableToken& nonce(
+  static const base::UnguessableToken& embed_token(
       const viz::LocalSurfaceId& local_surface_id) {
-    return local_surface_id.nonce();
+    return local_surface_id.embed_token();
   }
 
   static bool Read(viz::mojom::LocalSurfaceIdDataView data,
                    viz::LocalSurfaceId* out) {
     out->parent_sequence_number_ = data.parent_sequence_number();
     out->child_sequence_number_ = data.child_sequence_number();
-    return data.ReadNonce(&out->nonce_) && out->is_valid();
+    return data.ReadEmbedToken(&out->embed_token_) && out->is_valid();
   }
 };
 
diff --git a/services/viz/public/interfaces/compositing/local_surface_id.mojom b/services/viz/public/interfaces/compositing/local_surface_id.mojom
index 1b5ef00..295b186 100644
--- a/services/viz/public/interfaces/compositing/local_surface_id.mojom
+++ b/services/viz/public/interfaces/compositing/local_surface_id.mojom
@@ -16,6 +16,6 @@
   // its own surface.
   uint32 child_sequence_number;
 
-  mojo.common.mojom.UnguessableToken nonce;
+  mojo.common.mojom.UnguessableToken embed_token;
 };
 
diff --git a/skia/config/SkUserConfig.h b/skia/config/SkUserConfig.h
index 628eaac..cc2a6b35 100644
--- a/skia/config/SkUserConfig.h
+++ b/skia/config/SkUserConfig.h
@@ -208,11 +208,6 @@
 #define SK_SUPPORT_LEGACY_SVG_ARC_TO
 #endif
 
-// Remove after M66 branch to use new read/writePixels implementations
-#ifndef SK_LEGACY_GPU_PIXEL_OPS
-#define SK_LEGACY_GPU_PIXEL_OPS
-#endif
-
 #ifndef SK_SUPPORT_LEGACY_YUV_COLORSPACE
 #define SK_SUPPORT_LEGACY_YUV_COLORSPACE
 #endif
@@ -220,9 +215,6 @@
 // Max. verb count for paths rendered by the edge-AA tessellating path renderer.
 #define GR_AA_TESSELLATOR_MAX_VERB_COUNT 10
 
-#ifndef SK_SUPPORT_LEGACY_PRECISION_BOUNDARY
-#define SK_SUPPORT_LEGACY_PRECISION_BOUNDARY
-#endif
 
 ///////////////////////// Imported from BUILD.gn and skia_common.gypi
 
diff --git a/testing/buildbot/chromium.perf.fyi.json b/testing/buildbot/chromium.perf.fyi.json
index b6378741..df14891 100644
--- a/testing/buildbot/chromium.perf.fyi.json
+++ b/testing/buildbot/chromium.perf.fyi.json
@@ -424,6 +424,8 @@
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
             {
+              "gpu": "8086:1626",
+              "os": "Mac-10.12",
               "pool": "Chrome-perf-fyi"
             }
           ],
@@ -503,6 +505,7 @@
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
             {
+              "os": "Linux",
               "pool": "Chrome-perf-fyi"
             }
           ],
diff --git a/testing/buildbot/filters/mojo.fyi.network_browser_tests.filter b/testing/buildbot/filters/mojo.fyi.network_browser_tests.filter
index e15cde8..c64d148 100644
--- a/testing/buildbot/filters/mojo.fyi.network_browser_tests.filter
+++ b/testing/buildbot/filters/mojo.fyi.network_browser_tests.filter
@@ -2,8 +2,6 @@
 # See https://crbug.com/769401
 
 # Uncategorized timeouts or test failures.
--AdsPageLoadMetricsObserverBrowserTest.DocOverwritesNavigation
--AdsPageLoadMetricsObserverBrowserTest.SubresourceFilter
 -BackgroundXhrTest.HttpAuth
 -BackgroundXhrTest.TlsClientAuth
 -ChromeSecurityExploitBrowserTest.CreateFilesystemURLInExtensionOrigin
@@ -25,10 +23,6 @@
 -MediaGalleriesPlatformAppBrowserTest.ToURL
 -NetInternalsTest.netInternalsSessionBandwidthSucceed
 -NewlibPackagedAppTest.SuccessfulLoad
--PageLoadMetricsBrowserTest.LoadingMetrics
--PageLoadMetricsBrowserTest.LoadingMetricsFailed
--PageLoadMetricsBrowserTest.PayloadSize
--PageLoadMetricsBrowserTest.PayloadSizeChildFrame
 -PKPModelClientTest.PKPBypass
 -PKPModelClientTest.PKPEnforced
 -PlatformAppBrowserTest.AppWindowAdjustBoundsToBeVisibleOnScreen
@@ -44,12 +38,7 @@
 -RegisterProtocolHandlerBrowserTest.CustomHandler
 -SafeBrowsingTriggeredPopupBlockerBrowserTest.NoFeature_NoMessages
 -SubresourceFilterBrowserTest.FailedProvisionalLoadInMainframe
--TaskManagerBrowserTest.SentDataObserved
--TaskManagerBrowserTest.TotalSentDataObserved
 -TaskManagerUtilityProcessBrowserTest.UtilityJSHeapMemory
--WebSocketBrowserTest.WebSocketAppliesHSTS
--WebSocketBrowserTest.WebSocketBasicAuthInHTTPSURL
--WebSocketBrowserTest.WebSocketBasicAuthInHTTPURL
 -WebstoreInstallerBrowserTest.SimultaneousInstall
 -WebViewTests/WebViewTest.ClearData/0
 -WebViewTests/WebViewTest.ClearData/1
@@ -57,6 +46,7 @@
 -WebViewTests/WebViewTest.ClearDataCache/1
 -WebViewTests/WebViewTest.WebViewInBackgroundPage/0
 -WebViewTests/WebViewTest.WebViewInBackgroundPage/1
+
 # Need support for blocking cookies via content settings:
 # https://crbug.com/803452.
 -ClientHintsBrowserTest.ClientHintsLifetimeNotAttachedCookiesBlocked
@@ -65,6 +55,18 @@
 -ContentSettingsTest.RedirectCrossOrigin
 -ContentSettingsTest.RedirectLoopCookies
 
+# http://crbug.com/816684 Track Page Load Metrics.
+-AdsPageLoadMetricsObserverBrowserTest.DocOverwritesNavigation
+-AdsPageLoadMetricsObserverBrowserTest.SubresourceFilter
+-PageLoadMetricsBrowserTest.LoadingMetrics
+-PageLoadMetricsBrowserTest.LoadingMetricsFailed
+-PageLoadMetricsBrowserTest.PayloadSize
+-PageLoadMetricsBrowserTest.PayloadSizeChildFrame
+
+# http://crbug.com/822415 Plumb metrics from network process to browser.
+-TaskManagerBrowserTest.SentDataObserved
+-TaskManagerBrowserTest.TotalSentDataObserved
+
 # http://crbug.com/823297 StoragePartition::ClearData needs to use
 # CookieManager.
 -BrowsingDataRemoverBrowserTest.CookieDeletion
@@ -73,6 +75,12 @@
 -WebViewTests/WebViewTest.ClearSessionCookies/0
 -WebViewTests/WebViewTest.ClearSessionCookies/1
 
+# http://crbug.com/721400 support WebSockets.
+-WebSocketBrowserTest.WebSocketAppliesHSTS
+-WebSocketBrowserTest.WebSocketBasicAuthInHTTPSURL
+-WebSocketBrowserTest.WebSocketBasicAuthInHTTPURL
+-WebSocketBrowserTest.ReuseMainPageBasicAuthCredentialsForWebSocket
+
 # Accessing cookies after they were set in onload handler is flaky:
 # https://crbug.com/820969.
 -ContentSettingsTest.BasicCookies
@@ -145,7 +153,6 @@
 -LoginPromptBrowserTest.NoLoginPromptForFavicon
 -LoginPromptBrowserTest.NoLoginPromptForXHRWithBadCredentials
 -LoginPromptBrowserTest.TestCancelAuth_OnForward
--WebSocketBrowserTest.ReuseMainPageBasicAuthCredentialsForWebSocket
 
 # These rely on proxy configuration and PAC execution being configured on the
 # legacy in-process URLRequestContext. They should be removed or updated to
diff --git a/testing/buildbot/filters/mojo.fyi.network_content_browsertests.filter b/testing/buildbot/filters/mojo.fyi.network_content_browsertests.filter
index aa88f219..9ae9a94 100644
--- a/testing/buildbot/filters/mojo.fyi.network_content_browsertests.filter
+++ b/testing/buildbot/filters/mojo.fyi.network_content_browsertests.filter
@@ -93,7 +93,6 @@
 # service.
 # https://crbug.com/786505 (cross site document blocking)
 # https://crbug.com/792546 (cross site document blocking in network service)
--SiteIsolationStatsGathererBrowserTest.CrossSiteDocumentBlockingForMimeType
 -CrossSiteDocumentBlockingTest.BlockDocuments
 -CrossSiteDocumentBlockingTest.BlockHeaders
 -CrossSiteDocumentBlockingTest.BlockRequestFromErrorPage
diff --git a/testing/buildbot/filters/mojo.fyi.viz.content_browsertests.filter b/testing/buildbot/filters/mojo.fyi.viz.content_browsertests.filter
new file mode 100644
index 0000000..72cdaaf
--- /dev/null
+++ b/testing/buildbot/filters/mojo.fyi.viz.content_browsertests.filter
@@ -0,0 +1,93 @@
+#### Dev Tools
+# content::DevToolsProtocolTest::WaitForResponse times out
+# http://crbug.com/784941
+-CaptureScreenshotTest.*
+
+#### GPU
+# GPU Shutdown https://crbug.com/781714
+-WebRtcCaptureFromElementBrowserTest.CaptureFromCanvas2DHandlesContextLoss
+-WebRtcCaptureFromElementBrowserTest.CaptureFromOpaqueCanvas2DHandlesContextLoss
+
+# TODO: investigate flaky failure http://crbug.com/783434
+-GpuProcessHostBrowserTest.Shutdown
+
+#### WaitForChildFrameSurfaceReady
+# WaitForChildFrameSurfaceReady doesn't work http://crbug.com/763452
+-PointerLockBrowserTest.*
+-SitePerProcessGestureHitTestBrowserTest.*
+-SitePerProcessHighDPIHitTestBrowserTest.*
+-SitePerProcessInternalsHitTestBrowserTest.*
+-SitePerProcessMouseWheelHitTestBrowserTest.*
+-TouchSelectionForCrossProcessFramesTests/TouchSelectionControllerClientAuraSiteIsolationTest.*
+
+# Further WaitForChildFrameSurfaceReady doesn't work http://crbug.com/787945
+-SitePerProcessBrowserTest.CompositorViewportPixelSizeTest
+-SitePerProcessBrowserTest.GestureFlingStartEventsBubble
+-SitePerProcessBrowserTest.GestureFlingStart
+-SitePerProcessBrowserTest.NavigateCrashedSubframeToSameSite
+-SitePerProcessBrowserTest.OOPIFDetachDuringAnimation
+-SitePerProcessBrowserTest.ScrollBubblingFromNestedOOPIFTest
+-SitePerProcessBrowserTest.ScrollBubblingFromOOPIFTest
+-SitePerProcessBrowserTest.ScrollBubblingFromOOPIFWithBodyOverflowHidden
+-SitePerProcessBrowserTest.ScrollLocalSubframeInOOPIF
+-SitePerProcessBrowserTest.TwoSubframesCreatePopupMenuWidgetsSimultaneously
+-SitePerProcessBrowserTest.ViewBoundsInNestedFrameTest
+-SitePerProcessHitTestBrowserTest.AsynchronousHitTestChildTimeout*
+-SitePerProcessHitTestBrowserTest.CancelWheelScrollBubblingOnWheelTargetDeletion*
+-SitePerProcessHitTestBrowserTest.CreateContextMenuTest*
+-SitePerProcessHitTestBrowserTest.CrossProcessMouseCapture*
+-SitePerProcessHitTestBrowserTest.CrossProcessMouseEnterAndLeaveTest*
+-SitePerProcessHitTestBrowserTest.CursorUpdateReceivedFromCrossSiteIframe*
+-SitePerProcessHitTestBrowserTest.HitTestLayerSquashing*
+-SitePerProcessHitTestBrowserTest.HitTestNestedFrames*
+-SitePerProcessHitTestBrowserTest.HitTestWatermark*
+-SitePerProcessHitTestBrowserTest.InputEventRouterGesturePreventDefaultTargetMapTest*
+-SitePerProcessHitTestBrowserTest.InputEventRouterGestureTargetMapTest*
+-SitePerProcessHitTestBrowserTest.InputEventRouterTouchpadGestureTargetTest*
+-SitePerProcessHitTestBrowserTest.InputEventRouterWheelCoalesceTest*
+-SitePerProcessHitTestBrowserTest.NestedSurfaceHitTestTest*
+-SitePerProcessHitTestBrowserTest.OverlapSurfaceHitTestTest*
+-SitePerProcessHitTestBrowserTest.PopupMenuTest*
+-SitePerProcessHitTestBrowserTest.RootConsumesScrollDuringOverscrollGesture*
+-SitePerProcessHitTestBrowserTest.ScrollEventToOOPIF*
+-SitePerProcessHitTestBrowserTest.SubframeTouchEventRouting*
+-SitePerProcessHitTestBrowserTest.SurfaceHitTestPointerEventsNone*
+-SitePerProcessHitTestBrowserTest.SurfaceHitTestTest*
+-SitePerProcessNonIntegerScaleFactorHitTestBrowserTest.NestedSurfaceHitTestTest*
+
+#### Compositor Frame Submission
+# Waiting for CompositorFrames times out http://crbug.com/787941
+-SitePerProcessBrowserTest.CompositorFrameSwapped
+-SitePerProcessBrowserTest.HiddenOOPIFWillNotGenerateCompositorFrames
+-SitePerProcessBrowserTest.HiddenOOPIFWillNotGenerateCompositorFramesAfterNavigation
+
+# Touch selection information is not provided to the browser
+# http://crbug.com/777882
+-TouchSelectionControllerClientAuraScaleFactorTest.*
+-TouchSelectionControllerClientAuraTest.*
+
+#### Tab Capture
+# Copy Surface timing out http://crbug.com/785257
+-GLAndSoftwareCompositing/CompositingRenderWidgetHostViewBrowserTestHiDPI.*
+-GLAndSoftwareCompositing/CompositingRenderWidgetHostViewBrowserTestTabCapture.*
+-GLAndSoftwareCompositing/CompositingRenderWidgetHostViewBrowserTestTabCaptureHighDPI.*
+
+# GetSnapshotFromBrowser doesn't return snapshots http://crbug.com/785308
+-SnapshotBrowserTest.*
+
+#### VizProcessTransportFactory
+# No ContextProvider http://crbug.com/785268
+-ImageTransportFactoryTearDownBrowserTest.*
+-ImageTransportFactoryBrowserTest.TestLostContext
+
+#### Surface Invariants
+# Surface Invariants Failure on Mac http://crbug.com/817827
+-NavigationControllerBrowserTest.FrameNavigationEntry_RecreatedSubframeBackForward
+
+#### GL Renderer
+# GL Renderer Check Failure on Mac https://crbug.com/817830
+-WebContentsVideoCaptureDeviceBrowserTestP.CapturesContentChanges/*
+
+#### Hit Testing
+# Flaky Result on Windows-7 http://crbug.com/883463
+-MainThreadEventQueueBrowserTest.MouseMove
diff --git a/testing/buildbot/filters/viz.content_browsertests.filter b/testing/buildbot/filters/viz.content_browsertests.filter
index d8262a5..91059889 100644
--- a/testing/buildbot/filters/viz.content_browsertests.filter
+++ b/testing/buildbot/filters/viz.content_browsertests.filter
@@ -23,6 +23,7 @@
 # Further WaitForChildFrameSurfaceReady doesn't work http://crbug.com/787945
 -SitePerProcessBrowserTest.CompositorViewportPixelSizeTest
 -SitePerProcessBrowserTest.GestureFlingStartEventsBubble
+-SitePerProcessBrowserTest.GestureFlingStart
 -SitePerProcessBrowserTest.NavigateCrashedSubframeToSameSite
 -SitePerProcessBrowserTest.OOPIFDetachDuringAnimation
 -SitePerProcessBrowserTest.PhysicalBackingSizeTest
@@ -95,5 +96,8 @@
 # Flaky Result on Windows-7 http://crbug.com/883463
 -MainThreadEventQueueBrowserTest.MouseMove
 
+# Browser side fling cannot use SetNeedsBeginFrame on viz https://crbug.com/823310
+-NonBlockingEventBrowserTest.TouchStartDuringFling
+
 # Uses LatencyInfo for input info https://crbug.com/791557
 -MouseLatencyBrowserTest.CoalescedMouseMovesCorrectlyTerminated
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index 158eeda..5b9fa970 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -779,21 +779,6 @@
             ]
         }
     ],
-    "ChromeHomeSuggestionsMemoryReduction": [
-        {
-            "platforms": [
-                "android"
-            ],
-            "experiments": [
-                {
-                    "name": "DropAllButFirstThumbnail",
-                    "enable_features": [
-                        "ChromeHomeDropAllButFirstThumbnail"
-                    ]
-                }
-            ]
-        }
-    ],
     "ChromeModernDesign": [
         {
             "platforms": [
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
index ddba4f77b..7b21d31 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
@@ -40,9 +40,9 @@
 crbug.com/626703 external/wpt/css/css-writing-modes/sizing-orthog-prct-htb-in-vlr-002.xht [ Pass ]
 crbug.com/626703 external/wpt/css/css-writing-modes/sizing-orthog-prct-htb-in-vlr-005.xht [ Pass ]
 crbug.com/626703 external/wpt/css/css-writing-modes/sizing-orthog-prct-htb-in-vlr-006.xht [ Pass ]
-crbug.com/626703 external/wpt/css/css-writing-modes/sizing-orthog-prct-htb-in-vrl-001.xht [ Failure Pass ]
+crbug.com/626703 external/wpt/css/css-writing-modes/sizing-orthog-prct-htb-in-vrl-001.xht [ Pass ]
 crbug.com/626703 external/wpt/css/css-writing-modes/sizing-orthog-prct-htb-in-vrl-002.xht [ Pass ]
-crbug.com/626703 external/wpt/css/css-writing-modes/sizing-orthog-prct-htb-in-vrl-005.xht [ Failure Pass ]
+crbug.com/626703 external/wpt/css/css-writing-modes/sizing-orthog-prct-htb-in-vrl-005.xht [ Pass ]
 crbug.com/626703 external/wpt/css/css-writing-modes/sizing-orthog-prct-htb-in-vrl-006.xht [ Pass ]
 crbug.com/626703 external/wpt/css/css-writing-modes/sizing-orthog-prct-vlr-in-htb-001.xht [ Pass ]
 crbug.com/626703 external/wpt/css/css-writing-modes/sizing-orthog-prct-vlr-in-htb-002.xht [ Pass ]
@@ -97,7 +97,7 @@
 crbug.com/591099 animations/animation-ready-reject-script-forbidden.html [ Timeout ]
 crbug.com/591099 animations/cross-fade-list-style-image.html [ Failure ]
 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/line-height-interpolation.html [ Pass Timeout ]
 crbug.com/591099 animations/interpolation/svg-stroke-dasharray-interpolation.html [ Timeout ]
 crbug.com/591099 animations/interpolation/webkit-clip-path-interpolation.html [ Pass Timeout ]
 crbug.com/591099 animations/rotate-transform-equivalent.html [ Failure ]
@@ -115,7 +115,6 @@
 crbug.com/714962 compositing/gestures/gesture-tapHighlight-2-overflow-div-scrolled-inner.html [ Failure ]
 crbug.com/714962 compositing/gestures/gesture-tapHighlight-on-promoted-overflow-div-scrolled.html [ Failure ]
 crbug.com/591099 compositing/iframes/floating-self-painting-frame.html [ Failure ]
-crbug.com/591099 compositing/layer-creation/fixed-position-nonscrollable-iframes-in-scrollable-page.html [ Failure ]
 crbug.com/591099 compositing/layer-creation/rotate3d-overlap.html [ Failure ]
 crbug.com/591099 compositing/overflow/border-radius-above-composited-subframe.html [ Failure ]
 crbug.com/591099 compositing/overflow/get-transform-from-non-box-container.html [ Failure ]
@@ -141,8 +140,6 @@
 crbug.com/714962 css2.1/20110323/overflow-applies-to-012.htm [ Failure ]
 crbug.com/591099 css2.1/20110323/table-caption-margins-001.htm [ Failure ]
 crbug.com/591099 css2.1/t0510-c25-pseudo-elmnt-00-c.html [ Failure ]
-crbug.com/591099 css2.1/t051201-c23-first-line-00-b.html [ Crash Failure ]
-crbug.com/591099 css2.1/t051202-c26-psudo-nest-00-c.html [ Crash Failure ]
 crbug.com/591099 css2.1/t0905-c414-flt-wrap-01-d-g.html [ Failure ]
 crbug.com/591099 css2.1/t100801-c544-valgn-00-a-ag.html [ Failure ]
 crbug.com/591099 css2.1/t100801-c544-valgn-03-d-agi.html [ Failure ]
@@ -196,7 +193,7 @@
 crbug.com/591099 editing/execCommand/findString.html [ Failure ]
 crbug.com/591099 editing/execCommand/format-block-multiple-paragraphs-in-pre.html [ Failure ]
 crbug.com/591099 editing/execCommand/format-block-multiple-paragraphs.html [ Failure ]
-crbug.com/591099 editing/execCommand/query-format-block.html [ Pass Timeout ]
+crbug.com/591099 editing/execCommand/query-format-block.html [ Timeout ]
 crbug.com/591099 editing/execCommand/remove-list-from-range-selection.html [ Failure ]
 crbug.com/591099 editing/inserting/4875189-1.html [ Failure ]
 crbug.com/591099 editing/inserting/4959067.html [ Failure ]
@@ -226,7 +223,7 @@
 crbug.com/591099 editing/selection/dont-select-text-overflow-ellipsis-when-wrapping-rtl-mixed.html [ Failure ]
 crbug.com/591099 editing/selection/dont-select-text-overflow-ellipsis-when-wrapping-rtl.html [ Failure ]
 crbug.com/591099 editing/selection/dont-select-text-overflow-ellipsis-when-wrapping.html [ Failure ]
-crbug.com/591099 editing/selection/doubleclick-beside-cr-span.html [ Failure Timeout ]
+crbug.com/591099 editing/selection/doubleclick-beside-cr-span.html [ Failure ]
 crbug.com/591099 editing/selection/drag-in-iframe.html [ Failure ]
 crbug.com/591099 editing/selection/extend-inside-transforms-backward.html [ Failure ]
 crbug.com/591099 editing/selection/extend-inside-transforms-forward.html [ Failure ]
@@ -281,7 +278,7 @@
 crbug.com/591099 external/wpt/WebCryptoAPI/generateKey/failures_RSA-PSS.worker.html [ Timeout ]
 crbug.com/591099 external/wpt/WebCryptoAPI/generateKey/failures_RSASSA-PKCS1-v1_5.worker.html [ Timeout ]
 crbug.com/591099 external/wpt/WebCryptoAPI/generateKey/successes.worker.html [ Timeout ]
-crbug.com/591099 external/wpt/WebCryptoAPI/import_export/rsa_importKey.https.worker.html [ Timeout ]
+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 [ Pass Timeout ]
@@ -311,12 +308,10 @@
 crbug.com/591099 external/wpt/css/css-flexbox/percentage-heights-003.html [ Pass ]
 crbug.com/714962 external/wpt/css/css-fonts/font-features-across-space-1.html [ Pass ]
 crbug.com/714962 external/wpt/css/css-fonts/font-features-across-space-3.html [ Pass ]
-crbug.com/591099 external/wpt/css/css-fonts/font-kerning-03.html [ Pass ]
 crbug.com/591099 external/wpt/css/css-fonts/matching/fixed-stretch-style-over-weight.html [ Pass ]
 crbug.com/591099 external/wpt/css/css-fonts/matching/stretch-distance-over-weight-distance.html [ Pass ]
 crbug.com/591099 external/wpt/css/css-fonts/matching/style-ranges-over-weight-direction.html [ Pass ]
 crbug.com/591099 external/wpt/css/css-fonts/test_font_family_parsing.html [ Timeout ]
-crbug.com/714962 external/wpt/css/css-grid/abspos/grid-positioned-children-writing-modes-001.html [ Failure Pass ]
 crbug.com/591099 external/wpt/css/css-grid/abspos/positioned-grid-items-should-not-take-up-space-001.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-grid/alignment/grid-self-alignment-non-static-positioned-items-009.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-grid/alignment/grid-self-alignment-non-static-positioned-items-010.html [ Failure ]
@@ -846,7 +841,7 @@
 crbug.com/591099 external/wpt/dom/ranges/Range-set.html [ Timeout ]
 crbug.com/591099 external/wpt/dom/ranges/Range-surroundContents.html [ Timeout ]
 crbug.com/591099 external/wpt/domxpath/xml_xpath_runner.html [ Timeout ]
-crbug.com/591099 external/wpt/editing/run/backcolor.html [ Pass Timeout ]
+crbug.com/591099 external/wpt/editing/run/backcolor.html [ Timeout ]
 crbug.com/591099 external/wpt/editing/run/bold.html [ Timeout ]
 crbug.com/591099 external/wpt/editing/run/fontname.html [ Timeout ]
 crbug.com/591099 external/wpt/editing/run/fontsize.html [ Timeout ]
@@ -855,7 +850,7 @@
 crbug.com/591099 external/wpt/editing/run/forwarddelete.html [ Timeout ]
 crbug.com/591099 external/wpt/editing/run/hilitecolor.html [ Timeout ]
 crbug.com/591099 external/wpt/editing/run/indent.html [ Timeout ]
-crbug.com/591099 external/wpt/editing/run/inserthorizontalrule.html [ Timeout ]
+crbug.com/591099 external/wpt/editing/run/inserthorizontalrule.html [ Pass Timeout ]
 crbug.com/591099 external/wpt/editing/run/inserthtml.html [ Timeout ]
 crbug.com/591099 external/wpt/editing/run/insertlinebreak.html [ Timeout ]
 crbug.com/591099 external/wpt/editing/run/insertorderedlist.html [ Timeout ]
@@ -872,7 +867,7 @@
 crbug.com/591099 external/wpt/editing/run/removeformat.html [ Timeout ]
 crbug.com/591099 external/wpt/editing/run/strikethrough.html [ Timeout ]
 crbug.com/591099 external/wpt/editing/run/subscript.html [ Timeout ]
-crbug.com/591099 external/wpt/editing/run/superscript.html [ Timeout ]
+crbug.com/591099 external/wpt/editing/run/superscript.html [ Pass Timeout ]
 crbug.com/591099 external/wpt/editing/run/underline.html [ Timeout ]
 crbug.com/591099 external/wpt/encoding/api-invalid-label.html [ Timeout ]
 crbug.com/591099 external/wpt/encoding/legacy-mb-japanese/euc-jp/eucjp-decode-cseucpkdfmtjapanese.html [ Timeout ]
@@ -984,7 +979,6 @@
 crbug.com/591099 external/wpt/html/rendering/replaced-elements/svg-embedded-sizing/svg-in-img-auto.html [ Failure ]
 crbug.com/591099 external/wpt/html/rendering/replaced-elements/svg-embedded-sizing/svg-in-img-percentage.html [ Failure ]
 crbug.com/591099 external/wpt/html/rendering/replaced-elements/svg-inline-sizing/svg-inline.html [ Timeout ]
-crbug.com/591099 external/wpt/html/semantics/document-metadata/the-link-element/stylesheet-change-href.html [ Failure Pass ]
 crbug.com/591099 external/wpt/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-non-snap-to-lines.html [ Failure ]
 crbug.com/591099 external/wpt/html/semantics/grouping-content/the-li-element/grouping-li-reftest-list-owner-menu.html [ Failure ]
 crbug.com/591099 external/wpt/html/semantics/grouping-content/the-li-element/grouping-li-reftest-list-owner-skip-no-boxes.html [ Failure ]
@@ -1095,6 +1089,7 @@
 crbug.com/591099 fast/block/float/overlapping-floats-paint-hittest-order-1.html [ Failure ]
 crbug.com/591099 fast/block/line-layout/floats-do-not-fit-on-line.html [ Failure ]
 crbug.com/591099 fast/block/line-layout/line-break-removal-near-textarea-crash.html [ Failure ]
+crbug.com/591099 fast/block/margin-collapse/103.html [ Failure ]
 crbug.com/591099 fast/block/margin-collapse/webkit-margin-collapse-container.html [ Failure ]
 crbug.com/591099 fast/block/margin-collapse/webkit-margin-collapse-separate-position.html [ Failure ]
 crbug.com/591099 fast/block/margin-collapse/webkit-margin-collapse-siblings.html [ Failure ]
@@ -1206,7 +1201,6 @@
 crbug.com/591099 fast/css-grid-layout/grid-item-border-overflow-paint.html [ Failure ]
 crbug.com/591099 fast/css-grid-layout/grid-item-change-order-auto-flow.html [ Failure ]
 crbug.com/591099 fast/css-grid-layout/grid-item-column-row-get-set.html [ Timeout ]
-crbug.com/714962 fast/css-grid-layout/grid-item-margins-and-writing-modes.html [ Failure Pass ]
 crbug.com/591099 fast/css-grid-layout/grid-item-multiple-minmax-content-resolution.html [ Failure ]
 crbug.com/591099 fast/css-grid-layout/grid-item-named-grid-area-resolution.html [ Failure ]
 crbug.com/591099 fast/css-grid-layout/grid-item-named-grid-line-resolution.html [ Failure ]
@@ -1216,7 +1210,6 @@
 crbug.com/591099 fast/css-grid-layout/grid-item-order-paint-order.html [ Failure ]
 crbug.com/591099 fast/css-grid-layout/grid-item-overflow-paint.html [ Failure ]
 crbug.com/591099 fast/css-grid-layout/grid-item-overflow.html [ Failure ]
-crbug.com/714962 fast/css-grid-layout/grid-item-paddings-and-writing-modes.html [ Failure Pass ]
 crbug.com/591099 fast/css-grid-layout/grid-item-position-changed-dynamic.html [ Failure ]
 crbug.com/591099 fast/css-grid-layout/grid-item-removal-auto-placement-update.html [ Failure ]
 crbug.com/591099 fast/css-grid-layout/grid-item-removal-track-breadth-update.html [ Failure ]
@@ -1325,6 +1318,7 @@
 crbug.com/591099 fast/css/large-numbers.html [ Timeout ]
 crbug.com/591099 fast/css/last-child-pseudo-class.html [ Failure ]
 crbug.com/591099 fast/css/last-of-type-pseudo-class.html [ Failure ]
+crbug.com/591099 fast/css/line-thickness-underline-strikethrough-overline.html [ Failure ]
 crbug.com/591099 fast/css/margin-top-bottom-dynamic.html [ Failure ]
 crbug.com/591099 fast/css/negative-text-indent-in-inline-block.html [ Failure ]
 crbug.com/591099 fast/css/non-empty-span.html [ Failure ]
@@ -1336,7 +1330,6 @@
 crbug.com/591099 fast/css/overflow-rtl-border-after.html [ Failure ]
 crbug.com/591099 fast/css/percent-min-width-img-src-change.html [ Failure ]
 crbug.com/591099 fast/css/percent-width-img-src-change.html [ Failure ]
-crbug.com/591099 fast/css/pseudo-first-line-border-width.html [ Failure ]
 crbug.com/591099 fast/css/resize-corner-tracking.html [ Failure ]
 crbug.com/591099 fast/css/sticky/sticky-top-overflow-scroll-by-fragment.html [ Failure ]
 crbug.com/591099 fast/css/text-overflow-ellipsis-strict.html [ Failure ]
@@ -1437,7 +1430,7 @@
 crbug.com/591099 fast/events/wheel/mainthread-touchpad-fling-latching.html [ Pass ]
 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/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 ]
@@ -1477,7 +1470,7 @@
 crbug.com/591099 fast/inline-block/contenteditable-baseline.html [ Failure ]
 crbug.com/714962 fast/inline-block/tricky-baseline.html [ Failure ]
 crbug.com/591099 fast/inline-block/vertical-align-top-and-bottom-2.html [ Failure ]
-crbug.com/591099 fast/inline/absolute-positioned-inline-in-centred-block.html [ Crash Failure ]
+crbug.com/591099 fast/inline/absolute-positioned-inline-in-centred-block.html [ Failure ]
 crbug.com/591099 fast/inline/bpm-inline-ancestors.html [ Failure ]
 crbug.com/714962 fast/inline/continuation-outlines-with-layers-2.html [ Failure ]
 crbug.com/591099 fast/inline/continuation-outlines-with-layers.html [ Failure ]
@@ -1497,7 +1490,6 @@
 crbug.com/591099 fast/js/dfg-arguments-alias-activation.html [ Timeout ]
 crbug.com/591099 fast/js/dfg-byte-array-put.html [ Timeout ]
 crbug.com/591099 fast/js/document-all-triggers-masquerades-watchpoint.html [ Timeout ]
-crbug.com/591099 fast/layers/overflow-scroll-auto-switch.html [ Failure ]
 crbug.com/591099 fast/layers/scroll-rect-to-visible.html [ Failure ]
 crbug.com/591099 fast/lists/001-vertical.html [ Failure ]
 crbug.com/591099 fast/lists/001.html [ Failure ]
@@ -1506,7 +1498,6 @@
 crbug.com/591099 fast/lists/003.html [ Failure ]
 crbug.com/591099 fast/lists/004.html [ Failure ]
 crbug.com/591099 fast/lists/005-vertical.html [ Failure ]
-crbug.com/591099 fast/lists/006-vertical.html [ Failure Pass ]
 crbug.com/591099 fast/lists/007-vertical.html [ Failure ]
 crbug.com/591099 fast/lists/008-vertical.html [ Failure ]
 crbug.com/591099 fast/lists/009-vertical.html [ Failure ]
@@ -1555,7 +1546,6 @@
 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 ]
@@ -2064,7 +2054,6 @@
 crbug.com/714962 fast/table/040-vertical.html [ Failure ]
 crbug.com/714962 fast/table/040.html [ Failure ]
 crbug.com/714962 fast/table/absolute-table-at-bottom.html [ Failure ]
-crbug.com/714962 fast/table/auto-with-percent-height-vertical.html [ Failure Pass ]
 crbug.com/714962 fast/table/backgr_border-table-cell.html [ Failure ]
 crbug.com/714962 fast/table/backgr_border-table-column-group.html [ Failure ]
 crbug.com/714962 fast/table/backgr_border-table-column.html [ Failure ]
@@ -2110,7 +2099,7 @@
 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 Pass ]
-crbug.com/591099 fast/table/percent-height-overflow-scroll-content-in-cell.html [ Failure ]
+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 ]
 crbug.com/714962 fast/table/split-table-section-before-anonymous-block-3.html [ Failure ]
@@ -2454,7 +2443,7 @@
 crbug.com/591099 http/tests/devtools/tracing/timeline-paint/timeline-paint-with-layout-invalidations.js [ Failure ]
 crbug.com/591099 http/tests/devtools/tracing/timeline-paint/timeline-paint-with-style-recalc-invalidations.js [ Failure ]
 crbug.com/591099 http/tests/images/restyle-decode-error.html [ Failure ]
-crbug.com/783102 http/tests/incremental/frame-focus-before-load.html [ Pass Timeout ]
+crbug.com/783102 http/tests/incremental/frame-focus-before-load.html [ Timeout ]
 crbug.com/591099 http/tests/incremental/slow-utf8-text.pl [ Pass Timeout ]
 crbug.com/591099 http/tests/loading/nested_bad_objects.php [ Failure ]
 crbug.com/591099 http/tests/loading/preload-picture-nested.html [ Failure ]
@@ -2522,7 +2511,7 @@
 crbug.com/591099 inspector-protocol/accessibility/accessibility-nameSources-visiblity.js [ Timeout ]
 crbug.com/591099 inspector-protocol/css/css-add-rule.js [ Timeout ]
 crbug.com/714962 inspector-protocol/css/css-get-platform-fonts.js [ Failure ]
-crbug.com/591099 inspector-protocol/css/css-set-style-text.js [ Timeout ]
+crbug.com/591099 inspector-protocol/css/css-set-style-text.js [ Pass Timeout ]
 crbug.com/714962 inspector-protocol/dom-snapshot/dom-snapshot-getSnapshot-viewport.js [ Failure ]
 crbug.com/591099 inspector-protocol/dom-snapshot/dom-snapshot-getSnapshot.js [ Timeout ]
 crbug.com/591099 inspector-protocol/input/dispatchTouchEvent.js [ Pass Timeout ]
@@ -2748,7 +2737,6 @@
 crbug.com/591099 paint/invalidation/scroll/resize-scrollable-div.html [ Failure ]
 crbug.com/591099 paint/invalidation/scroll/resize-scrollable-iframe.html [ Failure ]
 crbug.com/591099 paint/invalidation/scroll/scroll-descendant-with-cached-cliprects.html [ Failure ]
-crbug.com/591099 paint/invalidation/scroll/scrolled-iframe-scrollbar-change.html [ Failure ]
 crbug.com/591099 paint/invalidation/selection/invalidation-rect-includes-newline-for-rtl.html [ Failure ]
 crbug.com/591099 paint/invalidation/selection/invalidation-rect-includes-newline-for-vertical-lr.html [ Failure ]
 crbug.com/591099 paint/invalidation/selection/invalidation-rect-includes-newline-for-vertical-rl.html [ Failure ]
@@ -2802,8 +2790,6 @@
 crbug.com/591099 paint/invalidation/svg/text-rescale.html [ Failure ]
 crbug.com/591099 paint/invalidation/svg/use-setAttribute-crash.svg [ Failure ]
 crbug.com/591099 paint/invalidation/table/add-table-overpaint.html [ Failure ]
-crbug.com/591099 paint/invalidation/table/border-collapse-change-collapse-to-separate.html [ Failure ]
-crbug.com/591099 paint/invalidation/table/border-collapse-change-separate-to-collapse.html [ Failure ]
 crbug.com/591099 paint/invalidation/table/cached-cell-append.html [ Failure ]
 crbug.com/591099 paint/invalidation/table/cached-change-cell-border-color.html [ Failure ]
 crbug.com/591099 paint/invalidation/table/cached-change-cell-border-width.html [ Failure ]
@@ -2816,22 +2802,8 @@
 crbug.com/591099 paint/invalidation/table/caret-contenteditable-content-after.html [ Failure ]
 crbug.com/591099 paint/invalidation/table/collapsed-border-cell-resize.html [ Failure ]
 crbug.com/591099 paint/invalidation/table/collapsed-border-change-rowspan.html [ Failure ]
-crbug.com/591099 paint/invalidation/table/composited-table-background-col-initial-empty.html [ Failure ]
-crbug.com/591099 paint/invalidation/table/composited-table-background-col-span-initial-empty.html [ Failure ]
-crbug.com/591099 paint/invalidation/table/composited-table-background-col-span.html [ Failure ]
-crbug.com/591099 paint/invalidation/table/composited-table-background-col.html [ Failure ]
-crbug.com/591099 paint/invalidation/table/composited-table-background-colgroup-initial-empty.html [ Failure ]
-crbug.com/591099 paint/invalidation/table/composited-table-background-colgroup.html [ Failure ]
-crbug.com/591099 paint/invalidation/table/composited-table-background-composited-row-initial-empty.html [ Failure ]
-crbug.com/591099 paint/invalidation/table/composited-table-background-composited-row.html [ Failure ]
-crbug.com/591099 paint/invalidation/table/composited-table-background-section-composited-row-initial-empty.html [ Failure ]
-crbug.com/591099 paint/invalidation/table/composited-table-background-section-composited-row.html [ Failure ]
-crbug.com/591099 paint/invalidation/table/composited-table-background-section-initial-empty.html [ Failure ]
-crbug.com/591099 paint/invalidation/table/composited-table-background-section.html [ Failure ]
-crbug.com/591099 paint/invalidation/table/composited-table-background.html [ Failure ]
 crbug.com/591099 paint/invalidation/table/composited-table-row.html [ Failure ]
 crbug.com/591099 paint/invalidation/table/dynamic-table-vertical-alignment-change.html [ Failure ]
-crbug.com/591099 paint/invalidation/table/invalidate-cell-in-row-with-offset.html [ Failure ]
 crbug.com/591099 paint/invalidation/table/repaint-table-row-in-composited-document.html [ Failure ]
 crbug.com/591099 paint/invalidation/table/resize-table-repaint-percent-size-cell.html [ Failure ]
 crbug.com/591099 paint/invalidation/table/resize-table-repaint-vertical-align-cell.html [ Failure ]
@@ -2983,7 +2955,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 ]
@@ -3002,7 +2974,9 @@
 crbug.com/591099 svg/text/text-repaint-rects.xhtml [ Failure ]
 crbug.com/714962 svg/text/tspan-multiple-outline.svg [ Failure ]
 crbug.com/591099 svg/transforms/text-with-pattern-inside-transformed-html.xhtml [ Failure ]
+crbug.com/591099 svg/wicd/test-rightsizing-a.xhtml [ Failure ]
 crbug.com/591099 svg/wicd/test-scalable-background-image1.xhtml [ Failure ]
+crbug.com/591099 svg/wicd/test-scalable-background-image2.xhtml [ Failure ]
 crbug.com/591099 tables/mozilla/bugs/bug101674.html [ Failure ]
 crbug.com/591099 tables/mozilla/bugs/bug110566.html [ Failure ]
 crbug.com/714962 tables/mozilla/bugs/bug11384q.html [ Failure ]
@@ -3101,7 +3075,6 @@
 crbug.com/591099 virtual/gpu-rasterization/images/color-profile-layer.html [ Failure ]
 crbug.com/591099 virtual/gpu-rasterization/images/color-profile-munsell-adobe-to-srgb.html [ Failure ]
 crbug.com/591099 virtual/gpu-rasterization/images/color-profile-reflection.html [ Failure ]
-crbug.com/591099 virtual/gpu-rasterization/images/image-hover-display-alt.html [ Failure ]
 crbug.com/591099 virtual/gpu-rasterization/images/percent-height-image.html [ Failure ]
 crbug.com/591099 virtual/gpu-rasterization/images/png-suite/test.html [ Failure ]
 crbug.com/591099 virtual/gpu-rasterization/images/rendering-broken-0px-images-quirk.html [ Failure ]
@@ -3139,20 +3112,19 @@
 crbug.com/591099 virtual/mouseevent_fractional/fast/events/onclick-list-marker.html [ Failure ]
 crbug.com/591099 virtual/mouseevent_fractional/fast/events/pointer-events-2.html [ Failure ]
 crbug.com/591099 virtual/mouseevent_fractional/fast/events/pointerevents/mouse-pointer-capture-transition-events.html [ Timeout ]
-crbug.com/591099 virtual/mouseevent_fractional/fast/events/pointerevents/mouse-pointer-capture.html [ Timeout ]
+crbug.com/591099 virtual/mouseevent_fractional/fast/events/pointerevents/mouse-pointer-capture.html [ Pass Timeout ]
 crbug.com/591099 virtual/mouseevent_fractional/fast/events/pointerevents/mouse-pointer-preventdefault.html [ Timeout ]
 crbug.com/591099 virtual/mouseevent_fractional/fast/events/pointerevents/multi-pointer-preventdefault.html [ Pass Timeout ]
 crbug.com/591099 virtual/mouseevent_fractional/fast/events/pointerevents/touch-capture-in-iframe.html [ Timeout ]
 crbug.com/591099 virtual/mouseevent_fractional/fast/events/pointerevents/touch-capture.html [ Timeout ]
 crbug.com/591099 virtual/mouseevent_fractional/fast/events/select-element.html [ Timeout ]
-crbug.com/591099 virtual/mouseevent_fractional/fast/events/selectstart-by-double-triple-clicks.html [ Failure Pass ]
 crbug.com/591099 virtual/mouseevent_fractional/fast/events/sequential-focus-navigation-starting-point.html [ Failure ]
 crbug.com/591099 virtual/mouseevent_fractional/fast/events/touch/compositor-touch-hit-rects-scroll.html [ Failure ]
 crbug.com/591099 virtual/mouseevent_fractional/fast/events/touch/compositor-touch-hit-rects.html [ Failure ]
 crbug.com/591099 virtual/mouseevent_fractional/fast/events/wheel/mainthread-touchpad-fling-latching.html [ Pass ]
 crbug.com/591099 virtual/mouseevent_fractional/fast/events/wheel/mouse-wheel-scroll-latching.html [ Pass ]
 crbug.com/591099 virtual/mouseevent_fractional/fast/events/wheel/wheel-scroll-latching-on-scrollbar.html [ Pass ]
-crbug.com/714962 virtual/mouseevent_fractional/fast/events/wheel/wheelevent-basic.html [ Failure ]
+crbug.com/714962 virtual/mouseevent_fractional/fast/events/wheel/wheelevent-basic.html [ Failure Pass ]
 crbug.com/591099 virtual/navigation-mojo-response/external/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/registration-attribute.https.html [ Failure Pass ]
 crbug.com/591099 virtual/navigation-mojo-response/http/tests/serviceworker/webexposed/global-interface-listing-service-worker.html [ Timeout ]
 crbug.com/591099 virtual/new-remote-playback-pipeline/ [ Skip ]
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-features=NetworkService b/third_party/WebKit/LayoutTests/FlagExpectations/enable-features=NetworkService
index efab7355..5b5cf3d 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-features=NetworkService
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-features=NetworkService
@@ -36,11 +36,6 @@
 
 Bug(none) external/wpt/streams/readable-byte-streams/properties.serviceworker.https.html [ Timeout Pass ]
 Bug(none) external/wpt/wasm/wasm_service_worker_test.https.html [ Crash Timeout ]
-Bug(none) external/wpt/websockets/cookies/001.html [ Failure ]
-Bug(none) external/wpt/websockets/cookies/002.html [ Failure ]
-Bug(none) external/wpt/websockets/cookies/003.html [ Failure ]
-Bug(none) external/wpt/websockets/cookies/006.html?wss [ Crash ]
-Bug(none) external/wpt/websockets/opening-handshake/003.html?wss [ Pass Timeout ]
 
 Bug(none) fast/files/xhr-response-blob.html [ Crash Failure ]
 Bug(none) fast/history/history-back-twice-with-subframes-assert.html [ Pass Timeout ]
@@ -76,9 +71,6 @@
 Bug(none) http/tests/security/offscreen-canvas-worker-read-blocked-by-setting.html [ Crash Pass Timeout ]
 Bug(none) http/tests/serviceworker/chromium.update-served-from-cache.html [ Failure ]
 Bug(none) http/tests/serviceworker/chromium/register-error-messages.html [ Failure ]
-Bug(none) http/tests/websocket/cookie-document-to-ws.html [ Failure ]
-Bug(none) http/tests/websocket/cookie-http-to-ws.pl [ Failure ]
-Bug(none) http/tests/websocket/httponly-cookie.pl [ Failure ]
 Bug(none) plugins/iframe-plugin-bgcolor.html [ Timeout ]
 
 # Plugin throttle is not implemented.
@@ -95,11 +87,20 @@
 # Started failing @ r529490
 Bug(none) virtual/layout_ng/fast/inline/positioned-object-between-replaced-elements.html [ Failure ]
 
+# http://crbug.com/721400 get WebSockets working with network service.
 # http://crbug.com/803958: Tests failing on bot but not in local checkout.
 crbug.com/803958 external/wpt/websockets/cookies/001.html?wss [ Failure ]
 crbug.com/803958 external/wpt/websockets/cookies/002.html?wss [ Failure ]
 crbug.com/803958 external/wpt/websockets/cookies/003.html?wss [ Failure ]
 crbug.com/803958 external/wpt/websockets/cookies/007.html [ Failure ]
 crbug.com/803958 external/wpt/websockets/cookies/007.html?wss [ Failure ]
+crbug.com/721400 external/wpt/websockets/cookies/001.html [ Failure ]
+crbug.com/721400 external/wpt/websockets/cookies/002.html [ Failure ]
+crbug.com/721400 external/wpt/websockets/cookies/003.html [ Failure ]
+crbug.com/721400 external/wpt/websockets/cookies/006.html?wss [ Crash ]
+crbug.com/721400 external/wpt/websockets/opening-handshake/003.html?wss [ Pass Timeout ]
+crbug.com/721400 http/tests/websocket/cookie-document-to-ws.html [ Failure ]
+crbug.com/721400 http/tests/websocket/cookie-http-to-ws.pl [ Failure ]
+crbug.com/721400 http/tests/websocket/httponly-cookie.pl [ Failure ]
 
 crbug.com/816556 external/wpt/html/semantics/text-level-semantics/the-a-element/a-download-click-404.html [ Failure ]
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index dba5fdb..662008c 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -2648,11 +2648,6 @@
 
 crbug.com/737959 http/tests/misc/video-poster-image-load-outlives-gc-without-crashing.html [ Failure Pass Crash ]
 
-# Awaiting rebaseline after skia roll.
-crbug.com/785931 virtual/gpu-rasterization/images/imagemap-focus-ring-outline-color-not-inherited-from-map.html [ NeedsManualRebaseline ]
-crbug.com/785931 virtual/gpu/fast/canvas/canvas-composite-video-shadow.html [ NeedsManualRebaseline ]
-crbug.com/785931 virtual/gpu/fast/canvas/canvas-composite-video.html [ NeedsManualRebaseline ]
-
 # crbug.com/736177: Failures likely related to different results on Mac with different GPUs
 crbug.com/736177 [ Mac10.12 ] fast/forms/form-element-geometry.html [ Failure Pass ]
 crbug.com/736177 [ Mac ] fast/forms/input-appearance-height.html [ Failure Pass ]
diff --git a/third_party/WebKit/LayoutTests/platform/win/css3/blending/svg-blend-color-expected.txt b/third_party/WebKit/LayoutTests/css3/blending/svg-blend-color-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/platform/win/css3/blending/svg-blend-color-expected.txt
rename to third_party/WebKit/LayoutTests/css3/blending/svg-blend-color-expected.txt
diff --git a/third_party/WebKit/LayoutTests/platform/win/css3/blending/svg-blend-hue-expected.txt b/third_party/WebKit/LayoutTests/css3/blending/svg-blend-hue-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/platform/win/css3/blending/svg-blend-hue-expected.txt
rename to third_party/WebKit/LayoutTests/css3/blending/svg-blend-hue-expected.txt
diff --git a/third_party/WebKit/LayoutTests/platform/win/css3/blending/svg-blend-luminosity-expected.txt b/third_party/WebKit/LayoutTests/css3/blending/svg-blend-luminosity-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/platform/win/css3/blending/svg-blend-luminosity-expected.txt
rename to third_party/WebKit/LayoutTests/css3/blending/svg-blend-luminosity-expected.txt
diff --git a/third_party/WebKit/LayoutTests/platform/win/css3/blending/svg-blend-multiply-alpha-expected.txt b/third_party/WebKit/LayoutTests/css3/blending/svg-blend-multiply-alpha-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/platform/win/css3/blending/svg-blend-multiply-alpha-expected.txt
rename to third_party/WebKit/LayoutTests/css3/blending/svg-blend-multiply-alpha-expected.txt
diff --git a/third_party/WebKit/LayoutTests/platform/win/css3/blending/svg-blend-saturation-expected.txt b/third_party/WebKit/LayoutTests/css3/blending/svg-blend-saturation-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/platform/win/css3/blending/svg-blend-saturation-expected.txt
rename to third_party/WebKit/LayoutTests/css3/blending/svg-blend-saturation-expected.txt
diff --git a/third_party/WebKit/LayoutTests/css3/blending/svg-isolation-foreign-no-isolation-expected.html b/third_party/WebKit/LayoutTests/css3/blending/svg-isolation-foreign-isolation-expected.html
similarity index 72%
rename from third_party/WebKit/LayoutTests/css3/blending/svg-isolation-foreign-no-isolation-expected.html
rename to third_party/WebKit/LayoutTests/css3/blending/svg-isolation-foreign-isolation-expected.html
index c910750..42cb49175 100644
--- a/third_party/WebKit/LayoutTests/css3/blending/svg-isolation-foreign-no-isolation-expected.html
+++ b/third_party/WebKit/LayoutTests/css3/blending/svg-isolation-foreign-isolation-expected.html
@@ -1,7 +1,7 @@
 <!DOCTYPE HTML>
 <html>
     <body>
-        <p>foreignObject should not isolate. The test passes if you see a lime square.</p>
+        <p>foreignObject should isolate. The test passes if you see a dark blue square.</p>
         <svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="200px" height="200px">
             <rect x="0" y="0" width="200" height="200" style="fill: lime"/>
         </svg>
diff --git a/third_party/WebKit/LayoutTests/css3/blending/svg-isolation-foreign-no-isolation.html b/third_party/WebKit/LayoutTests/css3/blending/svg-isolation-foreign-isolation.html
similarity index 85%
rename from third_party/WebKit/LayoutTests/css3/blending/svg-isolation-foreign-no-isolation.html
rename to third_party/WebKit/LayoutTests/css3/blending/svg-isolation-foreign-isolation.html
index e4b0a1d1..664473a 100644
--- a/third_party/WebKit/LayoutTests/css3/blending/svg-isolation-foreign-no-isolation.html
+++ b/third_party/WebKit/LayoutTests/css3/blending/svg-isolation-foreign-isolation.html
@@ -1,7 +1,7 @@
 <!DOCTYPE HTML>
 <html>
     <body>
-        <p>foreignObject should not isolate. The test passes if you see a lime square.</p>
+        <p>foreignObject should isolate. The test passes if you see a dark blue square.</p>
         <svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="200px" height="200px">
             <rect x="0" y="0" width="200" height="200" style="fill: yellow"/>
             <foreignObject width="200" height="200">
diff --git a/third_party/WebKit/LayoutTests/css3/filters/effect-reference-subregion-nested-expected.txt b/third_party/WebKit/LayoutTests/css3/filters/effect-reference-subregion-nested-expected.txt
index 33675f7..1661801 100644
--- a/third_party/WebKit/LayoutTests/css3/filters/effect-reference-subregion-nested-expected.txt
+++ b/third_party/WebKit/LayoutTests/css3/filters/effect-reference-subregion-nested-expected.txt
@@ -1,10 +1,10 @@
 layer at (0,0) size 800x600
   LayoutView at (0,0) size 800x600
-layer at (0,0) size 800x266
-  LayoutBlockFlow {HTML} at (0,0) size 800x266
-    LayoutBlockFlow {BODY} at (8,8) size 784x238
-      LayoutBlockFlow (anonymous) at (0,0) size 784x18
-        LayoutSVGRoot {svg} at (0,14) size 0x0
+layer at (0,0) size 800x268
+  LayoutBlockFlow {HTML} at (0,0) size 800x268
+    LayoutBlockFlow {BODY} at (8,8) size 784x240
+      LayoutBlockFlow (anonymous) at (0,0) size 784x20
+        LayoutSVGRoot {svg} at (0,15) size 0x0
           LayoutSVGHiddenContainer {defs} at (0,0) size 0x0
             LayoutSVGResourceFilter {filter} [id="merge"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
               [feMerge mergeNodes="2"]
@@ -15,5 +15,5 @@
                   [feColorMatrix type="MATRIX" values="1.00 0.00 0.00 0.00 0.00 0.00 1.00 0.00 0.00 0.00 0.00 0.00 1.00 0.00 0.00 0.00 0.00 0.00 0.30 0.00"]
                     [SourceGraphic]
         LayoutText {#text} at (0,0) size 0x0
-layer at (28,46) size 200x200
-  LayoutBlockFlow {DIV} at (20,38) size 200x200 [bgcolor=#008000]
+layer at (28,48) size 200x200
+  LayoutBlockFlow {DIV} at (20,40) size 200x200 [bgcolor=#008000]
diff --git a/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json b/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
index fcfbbfd1..413bbcf 100644
--- a/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
+++ b/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
@@ -152408,11 +152408,6 @@
      {}
     ]
    ],
-   "payment-request/interfaces.https-expected.txt": [
-    [
-     {}
-    ]
-   ],
    "payment-request/payment-request-abort-method.https-expected.txt": [
     [
      {}
@@ -286212,7 +286207,7 @@
    "support"
   ],
   "css/css-grid/grid-definition/support/testing-utils.js": [
-   "7d6dc5106777942ad83e6bc570368af113f32d5f",
+   "bda861857e383f7e77e2aded1d1c9af1340cc126",
    "support"
   ],
   "css/css-grid/grid-items/anonymous-grid-item-001.html": [
@@ -303408,7 +303403,7 @@
    "testharness"
   ],
   "css/css-typed-om/interfaces-expected.txt": [
-   "8aa50c5e87cc9c971cc486a5355bfd3d900bbdad",
+   "dca9bad99c0e48cc5c4624e090cae2e0da48f2b1",
    "support"
   ],
   "css/css-typed-om/interfaces.html": [
@@ -346824,7 +346819,7 @@
    "support"
   ],
   "interfaces/css-typed-om.idl": [
-   "3c918afebfb20266dd4003e71a008ed19c448fbc",
+   "59bd8e2c3c1bf8fded9a5523b5bd3b59761eacef",
    "support"
   ],
   "interfaces/cssom-view.idl": [
@@ -346904,7 +346899,7 @@
    "support"
   ],
   "interfaces/payment-request.idl": [
-   "b61ab0da4aa0f89f4af1b7d8c5f32f2bde90fd35",
+   "a7700006f4af50e069f6557bc7fc5affdd0c2d11",
    "support"
   ],
   "interfaces/proximity.idl": [
@@ -356523,10 +356518,6 @@
    "6695acdcd1647fdd37702a7f63658dcd50f25596",
    "testharness"
   ],
-  "payment-request/interfaces.https-expected.txt": [
-   "e5cae3299be102cc7e9722307bf9ac8f9dbebfdf",
-   "support"
-  ],
   "payment-request/interfaces.https.html": [
    "d269e8378f2a84ba96c981536667817e0db9e2d1",
    "testharness"
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-grid/grid-definition/support/testing-utils.js b/third_party/WebKit/LayoutTests/external/wpt/css/css-grid/grid-definition/support/testing-utils.js
index 202c865..217b620 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-grid/grid-definition/support/testing-utils.js
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-grid/grid-definition/support/testing-utils.js
@@ -1,10 +1,14 @@
 var TestingUtils = (function() {
 
     function checkGridTemplateColumns(element, value) {
+        if (!Array.isArray(value))
+            value = new Array(value);
         assert_in_array(getComputedStyle(element).gridTemplateColumns, value, "gridTemplateColumns");
     }
 
     function checkGridTemplateRows(element, value) {
+        if (!Array.isArray(value))
+            value = new Array(value);
         assert_in_array(getComputedStyle(element).gridTemplateRows, value, "gridTemplateRows");
     }
 
@@ -19,6 +23,8 @@
     }
 
     function checkGridTemplateAreas(element, value) {
+        if (!Array.isArray(value))
+            value = new Array(value);
         assert_in_array(getComputedStyle(element).gridTemplateAreas, value, "gridTemplateAreas");
     }
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-typed-om/interfaces-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/css/css-typed-om/interfaces-expected.txt
index f64d713..394df6ee 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-typed-om/interfaces-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-typed-om/interfaces-expected.txt
@@ -8,10 +8,10 @@
 PASS CSSStyleValue interface: existence and properties of interface prototype object's "constructor" property
 PASS CSSStyleValue interface: existence and properties of interface prototype object's @@unscopables property
 PASS CSSStyleValue interface: stringifier
-PASS CSSStyleValue interface: operation parse(DOMString, DOMString)
-PASS Unscopable handled correctly for parse(DOMString, DOMString) on CSSStyleValue
-PASS CSSStyleValue interface: operation parseAll(DOMString, DOMString)
-PASS Unscopable handled correctly for parseAll(DOMString, DOMString) on CSSStyleValue
+PASS CSSStyleValue interface: operation parse(USVString, USVString)
+PASS Unscopable handled correctly for parse(USVString, USVString) on CSSStyleValue
+PASS CSSStyleValue interface: operation parseAll(USVString, USVString)
+PASS Unscopable handled correctly for parseAll(USVString, USVString) on CSSStyleValue
 PASS StylePropertyMapReadOnly interface: existence and properties of interface object
 PASS StylePropertyMapReadOnly interface object length
 PASS StylePropertyMapReadOnly interface object name
@@ -20,12 +20,12 @@
 PASS StylePropertyMapReadOnly interface: existence and properties of interface prototype object's @@unscopables property
 PASS Testing Symbol.iterator property of iterable interface StylePropertyMapReadOnly
 PASS Testing pair iterable interface StylePropertyMapReadOnly
-PASS StylePropertyMapReadOnly interface: operation get(DOMString)
-PASS Unscopable handled correctly for get(DOMString) on StylePropertyMapReadOnly
-PASS StylePropertyMapReadOnly interface: operation getAll(DOMString)
-PASS Unscopable handled correctly for getAll(DOMString) on StylePropertyMapReadOnly
-PASS StylePropertyMapReadOnly interface: operation has(DOMString)
-PASS Unscopable handled correctly for has(DOMString) on StylePropertyMapReadOnly
+PASS StylePropertyMapReadOnly interface: operation get(USVString)
+PASS Unscopable handled correctly for get(USVString) on StylePropertyMapReadOnly
+PASS StylePropertyMapReadOnly interface: operation getAll(USVString)
+PASS Unscopable handled correctly for getAll(USVString) on StylePropertyMapReadOnly
+PASS StylePropertyMapReadOnly interface: operation has(USVString)
+PASS Unscopable handled correctly for has(USVString) on StylePropertyMapReadOnly
 PASS StylePropertyMapReadOnly interface: attribute size
 PASS Unscopable handled correctly for size property on StylePropertyMapReadOnly
 PASS StylePropertyMapReadOnly interface: operation entries()
@@ -42,12 +42,12 @@
 PASS StylePropertyMap interface: existence and properties of interface prototype object
 PASS StylePropertyMap interface: existence and properties of interface prototype object's "constructor" property
 PASS StylePropertyMap interface: existence and properties of interface prototype object's @@unscopables property
-PASS StylePropertyMap interface: operation set(DOMString, [object Object],[object Object])
-PASS Unscopable handled correctly for set(DOMString, [object Object],[object Object]) on StylePropertyMap
-PASS StylePropertyMap interface: operation append(DOMString, [object Object],[object Object])
-PASS Unscopable handled correctly for append(DOMString, [object Object],[object Object]) on StylePropertyMap
-PASS StylePropertyMap interface: operation delete(DOMString)
-PASS Unscopable handled correctly for delete(DOMString) on StylePropertyMap
+PASS StylePropertyMap interface: operation set(USVString, [object Object],[object Object])
+PASS Unscopable handled correctly for set(USVString, [object Object],[object Object]) on StylePropertyMap
+PASS StylePropertyMap interface: operation append(USVString, [object Object],[object Object])
+PASS Unscopable handled correctly for append(USVString, [object Object],[object Object]) on StylePropertyMap
+PASS StylePropertyMap interface: operation delete(USVString)
+PASS Unscopable handled correctly for delete(USVString) on StylePropertyMap
 PASS StylePropertyMap interface: operation clear()
 PASS Unscopable handled correctly for clear() on StylePropertyMap
 PASS CSSUnparsedValue interface: existence and properties of interface object
@@ -112,14 +112,14 @@
 PASS Unscopable handled correctly for max(CSSNumberish) on CSSNumericValue
 PASS CSSNumericValue interface: operation equals(CSSNumberish)
 PASS Unscopable handled correctly for equals(CSSNumberish) on CSSNumericValue
-PASS CSSNumericValue interface: operation to(DOMString)
-PASS Unscopable handled correctly for to(DOMString) on CSSNumericValue
-PASS CSSNumericValue interface: operation toSum(DOMString)
-PASS Unscopable handled correctly for toSum(DOMString) on CSSNumericValue
+PASS CSSNumericValue interface: operation to(USVString)
+PASS Unscopable handled correctly for to(USVString) on CSSNumericValue
+PASS CSSNumericValue interface: operation toSum(USVString)
+PASS Unscopable handled correctly for toSum(USVString) on CSSNumericValue
 PASS CSSNumericValue interface: operation type()
 PASS Unscopable handled correctly for type() on CSSNumericValue
-PASS CSSNumericValue interface: operation parse(DOMString)
-PASS Unscopable handled correctly for parse(DOMString) on CSSNumericValue
+PASS CSSNumericValue interface: operation parse(USVString)
+PASS Unscopable handled correctly for parse(USVString) on CSSNumericValue
 PASS CSSUnitValue interface: existence and properties of interface object
 PASS CSSUnitValue interface object length
 PASS CSSUnitValue interface object name
diff --git a/third_party/WebKit/LayoutTests/external/wpt/interfaces/css-typed-om.idl b/third_party/WebKit/LayoutTests/external/wpt/interfaces/css-typed-om.idl
index 6c33907a..39e53ce3 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/interfaces/css-typed-om.idl
+++ b/third_party/WebKit/LayoutTests/external/wpt/interfaces/css-typed-om.idl
@@ -1,31 +1,35 @@
+// GENERATED CONTENT - DO NOT EDIT
+// Content of this file was automatically extracted from the CSS Typed OM spec.
+// See https://drafts.css-houdini.org/css-typed-om/
+
 [Exposed=(Window, Worker, PaintWorklet, LayoutWorklet)]
 interface CSSStyleValue {
     stringifier;
-    [Exposed=Window] static CSSStyleValue parse(DOMString property, DOMString cssText);
-    [Exposed=Window] static sequence<CSSStyleValue> parseAll(DOMString property, DOMString cssText);
+    [Exposed=Window] static CSSStyleValue parse(USVString property, USVString cssText);
+    [Exposed=Window] static sequence<CSSStyleValue> parseAll(USVString property, USVString cssText);
 };
 
 [Exposed=(Window, Worker, PaintWorklet, LayoutWorklet)]
 interface StylePropertyMapReadOnly {
-    iterable<DOMString, sequence<CSSStyleValue>>;
-    any get(DOMString property);
+    iterable<USVString, sequence<CSSStyleValue>>;
+    any get(USVString property);
     /* 'any' means (undefined or CSSStyleValue) here,
        see https://github.com/heycam/webidl/issues/60 */
-    sequence<CSSStyleValue> getAll(DOMString property);
-    boolean has(DOMString property);
-    readonly attribute long size;
+    sequence<CSSStyleValue> getAll(USVString property);
+    boolean has(USVString property);
+    readonly attribute unsigned long size;
 };
 
 [Exposed=Window]
 interface StylePropertyMap : StylePropertyMapReadOnly {
-    void set(DOMString property, (CSSStyleValue or DOMString)... values);
-    void append(DOMString property, (CSSStyleValue or DOMString)... values);
-    void delete(DOMString property);
+    void set(USVString property, (CSSStyleValue or USVString)... values);
+    void append(USVString property, (CSSStyleValue or USVString)... values);
+    void delete(USVString property);
     void clear();
 };
 
 partial interface Element {
-    StylePropertyMapReadOnly computedStyleMap();
+    [SameObject] StylePropertyMapReadOnly computedStyleMap();
 };
 
 partial interface CSSStyleRule {
@@ -45,19 +49,19 @@
     setter CSSUnparsedSegment (unsigned long index, CSSUnparsedSegment val);
 };
 
-typedef (DOMString or CSSVariableReferenceValue) CSSUnparsedSegment;
+typedef (USVString or CSSVariableReferenceValue) CSSUnparsedSegment;
 
 [Exposed=(Window, Worker, PaintWorklet, LayoutWorklet),
- Constructor(DOMString variable, optional CSSUnparsedValue? fallback = null)]
+ Constructor(USVString variable, optional CSSUnparsedValue? fallback = null)]
 interface CSSVariableReferenceValue {
-    attribute DOMString variable;
+    attribute USVString variable;
     readonly attribute CSSUnparsedValue? fallback;
 };
 
 [Exposed=(Window, Worker, PaintWorklet, LayoutWorklet),
- Constructor(DOMString value)]
+ Constructor(USVString value)]
 interface CSSKeywordValue : CSSStyleValue {
-    attribute DOMString value;
+    attribute USVString value;
 };
 
 typedef (double or CSSNumericValue) CSSNumberish;
@@ -94,18 +98,18 @@
 
     boolean equals(CSSNumberish... value);
 
-    CSSUnitValue to(DOMString unit);
-    CSSMathSum toSum(DOMString... units);
+    CSSUnitValue to(USVString unit);
+    CSSMathSum toSum(USVString... units);
     CSSNumericType type();
 
-    [Exposed=Window] static CSSNumericValue parse(DOMString cssText);
+    [Exposed=Window] static CSSNumericValue parse(USVString cssText);
 };
 
 [Exposed=(Window, Worker, PaintWorklet, LayoutWorklet),
- Constructor(double value, DOMString unit)]
+ Constructor(double value, USVString unit)]
 interface CSSUnitValue : CSSNumericValue {
     attribute double value;
-    readonly attribute DOMString unit;
+    readonly attribute USVString unit;
 };
 
 [Exposed=(Window, Worker, PaintWorklet, LayoutWorklet)]
diff --git a/third_party/WebKit/LayoutTests/external/wpt/interfaces/payment-request.idl b/third_party/WebKit/LayoutTests/external/wpt/interfaces/payment-request.idl
index 4568fd8c..50a5dea6 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/interfaces/payment-request.idl
+++ b/third_party/WebKit/LayoutTests/external/wpt/interfaces/payment-request.idl
@@ -1,8 +1,11 @@
+// GENERATED CONTENT - DO NOT EDIT
+// Content of this file was automatically extracted from the Payment Request API spec.
+// See https://w3c.github.io/payment-request/
+
 [Constructor(sequence<PaymentMethodData> methodData, PaymentDetailsInit details, optional PaymentOptions options),
-  SecureContext,
-  Exposed=Window]
+SecureContext, Exposed=Window]
 interface PaymentRequest : EventTarget {
-  Promise<PaymentResponse> show();
+  Promise<PaymentResponse> show(optional Promise<PaymentDetailsUpdate> detailsPromise);
   Promise<void> abort();
   Promise<boolean> canMakePayment();
 
@@ -15,40 +18,48 @@
 
   attribute EventHandler onshippingoptionchange;
 };
+
 dictionary PaymentMethodData {
   required DOMString supportedMethods;
   object data;
 };
+
 dictionary PaymentCurrencyAmount {
   required DOMString currency;
   required DOMString value;
   // Note: currencySystem is "at risk" of being removed!
   DOMString currencySystem = "urn:iso:std:iso:4217";
 };
+
 dictionary PaymentDetailsBase {
   sequence<PaymentItem> displayItems;
   sequence<PaymentShippingOption> shippingOptions;
   sequence<PaymentDetailsModifier> modifiers;
 };
+
 dictionary PaymentDetailsInit : PaymentDetailsBase {
   DOMString id;
   required PaymentItem total;
 };
+
 dictionary PaymentDetailsUpdate : PaymentDetailsBase {
   DOMString error;
   PaymentItem total;
 };
+
 dictionary PaymentDetailsModifier {
   required DOMString supportedMethods;
   PaymentItem total;
   sequence<PaymentItem> additionalDisplayItems;
   object data;
 };
+
 enum PaymentShippingType {
   "shipping",
   "delivery",
   "pickup"
 };
+
 dictionary PaymentOptions {
   boolean requestPayerName = false;
   boolean requestPayerEmail = false;
@@ -56,19 +67,25 @@
   boolean requestShipping = false;
   PaymentShippingType shippingType = "shipping";
 };
+
 dictionary PaymentItem {
   required DOMString label;
   required PaymentCurrencyAmount amount;
   boolean pending = false;
+  // Note: type member is "at risk" of being removed!
+  PaymentItemType type;
 };
-[SecureContext,
-  Exposed=Window]
+
+enum PaymentItemType {
+  "tax"
+};
+
+[SecureContext, Exposed=Window]
 interface PaymentAddress {
   [Default] object toJSON();
   readonly attribute DOMString country;
   readonly attribute FrozenArray<DOMString> addressLine;
   readonly attribute DOMString region;
-  readonly attribute DOMString regionCode;
   readonly attribute DOMString city;
   readonly attribute DOMString dependentLocality;
   readonly attribute DOMString postalCode;
@@ -78,19 +95,21 @@
   readonly attribute DOMString recipient;
   readonly attribute DOMString phone;
 };
+
 dictionary PaymentShippingOption {
   required DOMString id;
   required DOMString label;
   required PaymentCurrencyAmount amount;
   boolean selected = false;
 };
+
 enum PaymentComplete {
   "fail",
   "success",
   "unknown"
 };
-[SecureContext,
-  Exposed=Window]
+
+[SecureContext, Exposed=Window]
 interface PaymentResponse {
   [Default] object toJSON();
 
@@ -105,11 +124,10 @@
 
   Promise<void> complete(optional PaymentComplete result = "unknown");
 };
-[Constructor(DOMString type, optional PaymentRequestUpdateEventInit eventInitDict),
-  SecureContext,
-  Exposed=Window]
+
+[Constructor(DOMString type, optional PaymentRequestUpdateEventInit eventInitDict), SecureContext, Exposed=Window]
 interface PaymentRequestUpdateEvent : Event {
   void updateWith(Promise<PaymentDetailsUpdate> detailsPromise);
 };
-dictionary PaymentRequestUpdateEventInit : EventInit {
-};
+
+dictionary PaymentRequestUpdateEventInit : EventInit {};
diff --git a/third_party/WebKit/LayoutTests/external/wpt/payment-request/interfaces.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/payment-request/interfaces.https-expected.txt
deleted file mode 100644
index 1ee2f49..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/payment-request/interfaces.https-expected.txt
+++ /dev/null
@@ -1,105 +0,0 @@
-This is a testharness.js-based test.
-PASS Setup for Payment Request API IDL tests.
-PASS PaymentRequest interface: existence and properties of interface object
-PASS PaymentRequest interface object length
-PASS PaymentRequest interface object name
-PASS PaymentRequest interface: existence and properties of interface prototype object
-PASS PaymentRequest interface: existence and properties of interface prototype object's "constructor" property
-PASS PaymentRequest interface: existence and properties of interface prototype object's @@unscopables property
-PASS PaymentRequest interface: operation show()
-PASS Unscopable handled correctly for show() on PaymentRequest
-PASS PaymentRequest interface: operation abort()
-PASS Unscopable handled correctly for abort() on PaymentRequest
-PASS PaymentRequest interface: operation canMakePayment()
-PASS Unscopable handled correctly for canMakePayment() on PaymentRequest
-PASS PaymentRequest interface: attribute id
-PASS Unscopable handled correctly for id property on PaymentRequest
-PASS PaymentRequest interface: attribute shippingAddress
-PASS Unscopable handled correctly for shippingAddress property on PaymentRequest
-PASS PaymentRequest interface: attribute shippingOption
-PASS Unscopable handled correctly for shippingOption property on PaymentRequest
-PASS PaymentRequest interface: attribute shippingType
-PASS Unscopable handled correctly for shippingType property on PaymentRequest
-PASS PaymentRequest interface: attribute onshippingaddresschange
-PASS Unscopable handled correctly for onshippingaddresschange property on PaymentRequest
-PASS PaymentRequest interface: attribute onshippingoptionchange
-PASS Unscopable handled correctly for onshippingoptionchange property on PaymentRequest
-PASS PaymentRequest must be primary interface of new PaymentRequest([{supportedMethods: 'foo'}], {total: {label: 'bar', amount: {currency: 'USD', value: '0'}} })
-PASS Stringification of new PaymentRequest([{supportedMethods: 'foo'}], {total: {label: 'bar', amount: {currency: 'USD', value: '0'}} })
-PASS PaymentRequest interface: new PaymentRequest([{supportedMethods: 'foo'}], {total: {label: 'bar', amount: {currency: 'USD', value: '0'}} }) must inherit property "show()" with the proper type
-PASS PaymentRequest interface: new PaymentRequest([{supportedMethods: 'foo'}], {total: {label: 'bar', amount: {currency: 'USD', value: '0'}} }) must inherit property "abort()" with the proper type
-PASS PaymentRequest interface: new PaymentRequest([{supportedMethods: 'foo'}], {total: {label: 'bar', amount: {currency: 'USD', value: '0'}} }) must inherit property "canMakePayment()" with the proper type
-PASS PaymentRequest interface: new PaymentRequest([{supportedMethods: 'foo'}], {total: {label: 'bar', amount: {currency: 'USD', value: '0'}} }) must inherit property "id" with the proper type
-PASS PaymentRequest interface: new PaymentRequest([{supportedMethods: 'foo'}], {total: {label: 'bar', amount: {currency: 'USD', value: '0'}} }) must inherit property "shippingAddress" with the proper type
-PASS PaymentRequest interface: new PaymentRequest([{supportedMethods: 'foo'}], {total: {label: 'bar', amount: {currency: 'USD', value: '0'}} }) must inherit property "shippingOption" with the proper type
-PASS PaymentRequest interface: new PaymentRequest([{supportedMethods: 'foo'}], {total: {label: 'bar', amount: {currency: 'USD', value: '0'}} }) must inherit property "shippingType" with the proper type
-PASS PaymentRequest interface: new PaymentRequest([{supportedMethods: 'foo'}], {total: {label: 'bar', amount: {currency: 'USD', value: '0'}} }) must inherit property "onshippingaddresschange" with the proper type
-PASS PaymentRequest interface: new PaymentRequest([{supportedMethods: 'foo'}], {total: {label: 'bar', amount: {currency: 'USD', value: '0'}} }) must inherit property "onshippingoptionchange" with the proper type
-PASS PaymentAddress interface: existence and properties of interface object
-PASS PaymentAddress interface object length
-PASS PaymentAddress interface object name
-PASS PaymentAddress interface: existence and properties of interface prototype object
-PASS PaymentAddress interface: existence and properties of interface prototype object's "constructor" property
-PASS PaymentAddress interface: existence and properties of interface prototype object's @@unscopables property
-PASS PaymentAddress interface: operation toJSON()
-PASS Unscopable handled correctly for toJSON() on PaymentAddress
-PASS PaymentAddress interface: attribute country
-PASS Unscopable handled correctly for country property on PaymentAddress
-PASS PaymentAddress interface: attribute addressLine
-PASS Unscopable handled correctly for addressLine property on PaymentAddress
-PASS PaymentAddress interface: attribute region
-PASS Unscopable handled correctly for region property on PaymentAddress
-FAIL PaymentAddress interface: attribute regionCode assert_true: The prototype object must have a property "regionCode" expected true got false
-PASS Unscopable handled correctly for regionCode property on PaymentAddress
-PASS PaymentAddress interface: attribute city
-PASS Unscopable handled correctly for city property on PaymentAddress
-PASS PaymentAddress interface: attribute dependentLocality
-PASS Unscopable handled correctly for dependentLocality property on PaymentAddress
-PASS PaymentAddress interface: attribute postalCode
-PASS Unscopable handled correctly for postalCode property on PaymentAddress
-PASS PaymentAddress interface: attribute sortingCode
-PASS Unscopable handled correctly for sortingCode property on PaymentAddress
-PASS PaymentAddress interface: attribute languageCode
-PASS Unscopable handled correctly for languageCode property on PaymentAddress
-PASS PaymentAddress interface: attribute organization
-PASS Unscopable handled correctly for organization property on PaymentAddress
-PASS PaymentAddress interface: attribute recipient
-PASS Unscopable handled correctly for recipient property on PaymentAddress
-PASS PaymentAddress interface: attribute phone
-PASS Unscopable handled correctly for phone property on PaymentAddress
-PASS PaymentResponse interface: existence and properties of interface object
-PASS PaymentResponse interface object length
-PASS PaymentResponse interface object name
-PASS PaymentResponse interface: existence and properties of interface prototype object
-PASS PaymentResponse interface: existence and properties of interface prototype object's "constructor" property
-PASS PaymentResponse interface: existence and properties of interface prototype object's @@unscopables property
-PASS PaymentResponse interface: operation toJSON()
-PASS Unscopable handled correctly for toJSON() on PaymentResponse
-PASS PaymentResponse interface: attribute requestId
-PASS Unscopable handled correctly for requestId property on PaymentResponse
-PASS PaymentResponse interface: attribute methodName
-PASS Unscopable handled correctly for methodName property on PaymentResponse
-PASS PaymentResponse interface: attribute details
-PASS Unscopable handled correctly for details property on PaymentResponse
-PASS PaymentResponse interface: attribute shippingAddress
-PASS Unscopable handled correctly for shippingAddress property on PaymentResponse
-PASS PaymentResponse interface: attribute shippingOption
-PASS Unscopable handled correctly for shippingOption property on PaymentResponse
-PASS PaymentResponse interface: attribute payerName
-PASS Unscopable handled correctly for payerName property on PaymentResponse
-PASS PaymentResponse interface: attribute payerEmail
-PASS Unscopable handled correctly for payerEmail property on PaymentResponse
-PASS PaymentResponse interface: attribute payerPhone
-PASS Unscopable handled correctly for payerPhone property on PaymentResponse
-PASS PaymentResponse interface: operation complete(PaymentComplete)
-PASS Unscopable handled correctly for complete(PaymentComplete) on PaymentResponse
-PASS PaymentRequestUpdateEvent interface: existence and properties of interface object
-PASS PaymentRequestUpdateEvent interface object length
-PASS PaymentRequestUpdateEvent interface object name
-PASS PaymentRequestUpdateEvent interface: existence and properties of interface prototype object
-PASS PaymentRequestUpdateEvent interface: existence and properties of interface prototype object's "constructor" property
-PASS PaymentRequestUpdateEvent interface: existence and properties of interface prototype object's @@unscopables property
-PASS PaymentRequestUpdateEvent interface: operation updateWith([object Object])
-PASS Unscopable handled correctly for updateWith([object Object]) on PaymentRequestUpdateEvent
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/external/wpt/svg/extensibility/foreignObject/containing-block.html b/third_party/WebKit/LayoutTests/external/wpt/svg/extensibility/foreignObject/containing-block.html
new file mode 100644
index 0000000..da0728c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/svg/extensibility/foreignObject/containing-block.html
@@ -0,0 +1,46 @@
+<!doctype HTML>
+<link rel="help" href="https://svgwg.org/svg2-draft/single-page.html#embedded-ForeignObjectElement"/>
+<style>
+  * {
+    margin: 5px;
+  }
+  .el {
+    background: lightblue;
+    width: 50px;
+    height: 60px;
+  }
+  .pos {
+    top: 5px;
+    left: 6px;
+  }
+</style>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<svg>
+  <foreignObject id="first" width=100 height=100>
+    <div id=contained class="el" style="width: 50px; height: 60px;"></div>
+    <div id=containedrel class="el pos" style="position: relative"></div>
+    <div id=containedabs class="el pos" style="position: absolute"></div>
+    <div id=containedfixed class="el pos" style="position: fixed"></div>
+  </foreignObject>
+</svg>
+<script>
+function checkPosition(el, offsetLeftVal, offsetTopVal, boundingRectLeft, boundingRectTop) {
+    assert_equals(el.offsetLeft, offsetLeftVal, "offsetLeft");
+    assert_equals(el.offsetTop, offsetTopVal, "offsetTop");
+    assert_equals(el.getBoundingClientRect().left, boundingRectLeft, "boundingRectLeft");
+    assert_equals(el.getBoundingClientRect().top, boundingRectTop, "boundingRectTop");
+}
+
+test(function() {
+  // Test that #first is a containing block for all descendants.
+  var contained = document.getElementById('contained');
+  var containedrel = document.getElementById('containedrel');
+  var containedabs = document.getElementById('containedabs');
+  var containedfixed = document.getElementById('containedfixed');
+  checkPosition(contained, 5, 5, 20, 20);
+  checkPosition(containedrel, 11, 75, 26, 90);
+  checkPosition(containedabs, 11, 10, 26, 25);
+  checkPosition(containedfixed, 11, 10, 26, 25);
+}, "position");
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/svg/extensibility/foreignObject/stacking-context-expected.html b/third_party/WebKit/LayoutTests/external/wpt/svg/extensibility/foreignObject/stacking-context-expected.html
new file mode 100644
index 0000000..28e7e310
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/svg/extensibility/foreignObject/stacking-context-expected.html
@@ -0,0 +1,18 @@
+<!doctype HTML>
+<style>
+  * {
+    margin: 0;
+  }
+  .el {
+    width: 50px;
+    height: 60px;
+  }
+
+</style>
+<div style="isolation: isolate">
+  <div class="el"
+      style="position: absolute; z-index: 1; top: 40px; left: 10px; border: 1px solid black; background: lightblue"></div>
+  <div class="el"
+      style="position: absolute; z-index: 2; top: 5px; left: 5px; border: 1px solid black; background: lightgreen"></div>
+</div>
+<div id=top class="el" style="position: relative; background: lightgray; top: 50px"></div>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/svg/extensibility/foreignObject/stacking-context.html b/third_party/WebKit/LayoutTests/external/wpt/svg/extensibility/foreignObject/stacking-context.html
new file mode 100644
index 0000000..c60a111
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/svg/extensibility/foreignObject/stacking-context.html
@@ -0,0 +1,26 @@
+<!doctype HTML>
+<title>Test that the foreignObject element is a stacking context</title>
+<link rel="match" href="stacking-context-expected.html">
+<link rel="help" href="https://svgwg.org/svg2-draft/single-page.html#embedded-ForeignObjectElement"/>
+<style>
+  * {
+    margin: 0;
+  }
+  .el {
+    width: 50px;
+    height: 60px;
+  }
+
+</style>
+  <!-- Test that the <foreignObject> root element is a stacking context, so z-index here
+    has no effect on order w.r.t. #top, but still does for stacking under
+    foreignObject -->
+<svg style="width: 50px; height: 50px; overflow: visible; display: block">
+  <foreignObject width=100 height=200>
+    <div  class="el"
+        style="position: absolute; z-index: 1; top: 40px; left: 10px; border: 1px solid black; background: lightblue"></div>
+    <div  class="el"
+        style="position: absolute; z-index: 2; top: 5px; left: 5px; border: 1px solid black; background: lightgreen"></div>
+  </foreignObject>
+</svg>
+<div id=top class="el" style="position: relative; background: lightgray"></div>
diff --git a/third_party/WebKit/LayoutTests/fast/backgrounds/size/contain-and-cover-expected.png b/third_party/WebKit/LayoutTests/fast/backgrounds/size/contain-and-cover-expected.png
index 0c71921a..9836c510 100644
--- a/third_party/WebKit/LayoutTests/fast/backgrounds/size/contain-and-cover-expected.png
+++ b/third_party/WebKit/LayoutTests/fast/backgrounds/size/contain-and-cover-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/fast/css3-text/css3-text-decoration/text-decoration-skip-ink-expected.png b/third_party/WebKit/LayoutTests/fast/css3-text/css3-text-decoration/text-decoration-skip-ink-expected.png
index d9bfa81..24b9247 100644
--- a/third_party/WebKit/LayoutTests/fast/css3-text/css3-text-decoration/text-decoration-skip-ink-expected.png
+++ b/third_party/WebKit/LayoutTests/fast/css3-text/css3-text-decoration/text-decoration-skip-ink-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/compositing/layer-creation/fixed-position-nonscrollable-iframes-in-scrollable-page-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/compositing/layer-creation/fixed-position-nonscrollable-iframes-in-scrollable-page-expected.txt
new file mode 100644
index 0000000..46614a2d
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/compositing/layer-creation/fixed-position-nonscrollable-iframes-in-scrollable-page-expected.txt
@@ -0,0 +1,60 @@
+In all iframes, the green fixed-position element should not be composited.
+{
+  "layers": [
+    {
+      "name": "LayoutView #document",
+      "bounds": [800, 600],
+      "drawsContent": false,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "Scrolling Layer",
+      "bounds": [785, 600],
+      "drawsContent": false
+    },
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [785, 4016],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "LayoutNGBlockFlow (positioned) DIV class='composited box'",
+      "bounds": [300, 100],
+      "contentsOpaque": true,
+      "backgroundColor": "#00FFFF",
+      "transform": 1
+    },
+    {
+      "name": "LayoutIFrame (positioned) IFRAME id='iframe2' class='composited'",
+      "bounds": [154, 154],
+      "transform": 2
+    },
+    {
+      "name": "LayoutIFrame (positioned) IFRAME id='iframe3'",
+      "position": [10, 380],
+      "bounds": [154, 154]
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [50, 360, 0, 1]
+      ]
+    },
+    {
+      "id": 2,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [10, 200, 0, 1]
+      ]
+    }
+  ]
+}
+Composited box underneath iframe.
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/css2.1/t051201-c23-first-line-00-b-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/css2.1/t051201-c23-first-line-00-b-expected.txt
new file mode 100644
index 0000000..c2ab811
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/css2.1/t051201-c23-first-line-00-b-expected.txt
@@ -0,0 +1,69 @@
+layer at (0,0) size 800x600
+  LayoutView at (0,0) size 800x600
+layer at (0,0) size 800x442
+  LayoutNGBlockFlow {HTML} at (0,0) size 800x442
+    LayoutNGBlockFlow {BODY} at (8,16) size 784x410 [color=#0000FF]
+      LayoutNGBlockFlow {P} at (0,0) size 784x120
+        LayoutText {#text} at (0,0) size 29x19
+          text run at (0,0) width 29: "The "
+        LayoutInline {STRONG} at (0,0) size 55x19
+          LayoutText {#text} at (29,0) size 55x19
+            text run at (29,0) width 55: "first line"
+        LayoutText {#text} at (84,0) size 300x19
+          text run at (84,0) width 300: " of this paragraph, and only that one, should be "
+        LayoutInline {STRONG} at (0,0) size 38x19
+          LayoutText {#text} at (384,0) size 38x19
+            text run at (384,0) width 38: "green"
+        LayoutText {#text} at (422,0) size 780x119
+          text run at (422,0) width 358: ". If this precise combination does not occur, then the user"
+          text run at (0,20) width 762: "agent has failed this test. Remember that in order to ensure a complete test, the paragraph must be displayed on more than"
+          text run at (0,40) width 750: "one line. Dummy text. Dummy text. Dummy text. Dummy text. Dummy text. Dummy text. Dummy text. Dummy text."
+          text run at (0,60) width 779: "Dummy text. Dummy text. Dummy text. Dummy text. Dummy text. Dummy text. Dummy text. Dummy text. Dummy text."
+          text run at (0,80) width 779: "Dummy text. Dummy text. Dummy text. Dummy text. Dummy text. Dummy text. Dummy text. Dummy text. Dummy text."
+          text run at (0,100) width 170: "Dummy text. Dummy text."
+      LayoutNGBlockFlow {P} at (0,136) size 784x138
+        LayoutText {#text} at (0,1) size 58x36
+          text run at (0,1) width 58: "The "
+        LayoutInline {STRONG} at (0,0) size 115x36
+          LayoutText {#text} at (58,0) size 115x36
+            text run at (58,0) width 115: "first line"
+        LayoutText {#text} at (173,1) size 774x56
+          text run at (173,1) width 601: " of this paragraph, and only that one, should be"
+          text run at (0,38) width 11: "a "
+        LayoutInline {STRONG} at (0,0) size 41x19
+          LayoutText {#text} at (11,38) size 41x19
+            text run at (11,38) width 41: "larger"
+        LayoutText {#text} at (52,38) size 126x19
+          text run at (52,38) width 126: " font size as well as "
+        LayoutInline {STRONG} at (0,0) size 38x19
+          LayoutText {#text} at (178,38) size 38x19
+            text run at (178,38) width 38: "green"
+        LayoutText {#text} at (216,38) size 779x99
+          text run at (216,38) width 515: ". If this precise combination does not occur, then the user agent has failed this test."
+          text run at (0,58) width 750: "Remember that in order to ensure a complete test, the paragraph must be displayed on more than one line. Dummy text."
+          text run at (0,78) width 779: "Dummy text. Dummy text. Dummy text. Dummy text. Dummy text. Dummy text. Dummy text. Dummy text. Dummy text."
+          text run at (0,98) width 779: "Dummy text. Dummy text. Dummy text. Dummy text. Dummy text. Dummy text. Dummy text. Dummy text. Dummy text."
+          text run at (0,118) width 779: "Dummy text. Dummy text. Dummy text. Dummy text. Dummy text. Dummy text. Dummy text. Dummy text. Dummy text."
+      LayoutNGBlockFlow {P} at (0,290) size 784x120
+        LayoutText {#text} at (0,0) size 29x19
+          text run at (0,0) width 29: "The "
+        LayoutInline {STRONG} at (0,0) size 62x19
+          LayoutText {#text} at (29,0) size 62x19
+            text run at (29,0) width 62: "first line"
+        LayoutText {#text} at (91,0) size 394x19
+          text run at (91,0) width 394: " of this paragraph, and only that one, should be displayed in "
+        LayoutInline {STRONG} at (0,0) size 72x19
+          LayoutText {#text} at (485,0) size 72x19
+            text run at (485,0) width 72: "small-caps"
+        LayoutText {#text} at (557,0) size 114x19
+          text run at (557,0) width 114: " style as well as "
+        LayoutInline {STRONG} at (0,0) size 39x19
+          LayoutText {#text} at (671,0) size 39x19
+            text run at (671,0) width 39: "green"
+        LayoutText {#text} at (710,0) size 784x119
+          text run at (710,0) width 58: ". Thus, if"
+          text run at (0,20) width 784: "the first line is not in small-caps style, or if the entire paragraph turns out in small-caps, then the user agent has failed this test."
+          text run at (0,40) width 779: "Dummy text. Dummy text. Dummy text. Dummy text. Dummy text. Dummy text. Dummy text. Dummy text. Dummy text."
+          text run at (0,60) width 779: "Dummy text. Dummy text. Dummy text. Dummy text. Dummy text. Dummy text. Dummy text. Dummy text. Dummy text."
+          text run at (0,80) width 779: "Dummy text. Dummy text. Dummy text. Dummy text. Dummy text. Dummy text. Dummy text. Dummy text. Dummy text."
+          text run at (0,100) width 83: "Dummy text."
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/css2.1/t051202-c26-psudo-nest-00-c-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/css2.1/t051202-c26-psudo-nest-00-c-expected.txt
new file mode 100644
index 0000000..8157232
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/css2.1/t051202-c26-psudo-nest-00-c-expected.txt
@@ -0,0 +1,122 @@
+layer at (0,0) size 800x600
+  LayoutView at (0,0) size 800x600
+layer at (0,0) size 800x479
+  LayoutNGBlockFlow {HTML} at (0,0) size 800x479
+    LayoutNGBlockFlow {BODY} at (8,16) size 784x455 [color=#0000FF]
+      LayoutNGBlockFlow {P} at (0,0) size 784x250
+        LayoutInline {<pseudo:first-letter>} at (0,0) size 88x164 [color=#00FFFF]
+          LayoutTextFragment (anonymous) at (0,3) size 88x164
+            text run at (0,3) width 88: "T"
+        LayoutTextFragment {#text} at (88,89) size 57x55
+          text run at (88,89) width 57: "he "
+        LayoutInline {STRONG} at (0,0) size 205x55
+          LayoutText {#text} at (145,88) size 205x55
+            text run at (145,88) width 205: "first letter"
+        LayoutText {#text} at (350,89) size 779x100
+          text run at (350,89) width 429: " of this paragraph, and"
+          text run at (0,170) width 155: "only that one, should be "
+        LayoutInline {STRONG} at (0,0) size 87x19
+          LayoutText {#text} at (155,170) size 87x19
+            text run at (155,170) width 87: "600% bigger"
+        LayoutText {#text} at (242,170) size 513x19
+          text run at (242,170) width 513: " than the normal text (300% bigger than the rest of first line of this paragraph) and"
+        LayoutInline {STRONG} at (0,0) size 34x19
+          LayoutText {#text} at (0,190) size 34x19
+            text run at (0,190) width 34: "aqua"
+        LayoutText {#text} at (34,190) size 109x19
+          text run at (34,190) width 109: ", while the entire "
+        LayoutInline {STRONG} at (0,0) size 55x19
+          LayoutText {#text} at (143,190) size 55x19
+            text run at (143,190) width 55: "first line"
+        LayoutText {#text} at (198,190) size 69x19
+          text run at (198,190) width 69: " should be "
+        LayoutInline {STRONG} at (0,0) size 87x19
+          LayoutText {#text} at (267,190) size 87x19
+            text run at (267,190) width 87: "300% bigger"
+        LayoutText {#text} at (354,190) size 110x19
+          text run at (354,190) width 110: " than normal and "
+        LayoutInline {STRONG} at (0,0) size 24x19
+          LayoutText {#text} at (464,190) size 24x19
+            text run at (464,190) width 24: "teal"
+        LayoutText {#text} at (488,190) size 779x59
+          text run at (488,190) width 274: ". If this precise combination does not occur,"
+          text run at (0,210) width 779: "then the user agent has failed this test. Remember that in order to ensure a complete test, the paragraph must be displayed on"
+          text run at (0,230) width 182: "more than one line. (TEST1)"
+      LayoutNGBlockFlow {P} at (0,266) size 784x77
+        LayoutInline {<pseudo:first-letter>} at (0,0) size 33x36 [color=#00FFFF]
+          LayoutTextFragment (anonymous) at (0,0) size 33x36
+            text run at (0,0) width 33: "\"T"
+        LayoutTextFragment {#text} at (33,13) size 98x19
+          text run at (33,13) width 98: "est\": The first "
+        LayoutInline {STRONG} at (0,0) size 108x19
+          LayoutText {#text} at (131,13) size 108x19
+            text run at (131,13) width 108: "two characters"
+        LayoutText {#text} at (239,13) size 446x19
+          text run at (239,13) width 446: " in this paragraph (a double-quote mark and a capital 'T') should be "
+        LayoutInline {STRONG} at (0,0) size 88x19
+          LayoutText {#text} at (685,13) size 88x19
+            text run at (685,13) width 88: "200% bigger"
+        LayoutText {#text} at (0,37) size 218x19
+          text run at (0,37) width 218: "than the rest of the paragraph, and "
+        LayoutInline {STRONG} at (0,0) size 34x19
+          LayoutText {#text} at (218,37) size 34x19
+            text run at (218,37) width 34: "aqua"
+        LayoutText {#text} at (252,37) size 146x19
+          text run at (252,37) width 146: ". In addition, the entire "
+        LayoutInline {STRONG} at (0,0) size 55x19
+          LayoutText {#text} at (398,37) size 55x19
+            text run at (398,37) width 55: "first line"
+        LayoutText {#text} at (453,37) size 96x19
+          text run at (453,37) width 96: " should be in a "
+        LayoutInline {STRONG} at (0,0) size 159x19
+          LayoutText {#text} at (549,37) size 159x19
+            text run at (549,37) width 159: "small-caps font and teal"
+        LayoutText {#text} at (708,37) size 724x39
+          text run at (708,37) width 4: "."
+          text run at (0,57) width 724: "Remember that in order to ensure a complete test, the paragraph must be displayed on more than one line. (TEST2)"
+      LayoutNGBlockFlow {P} at (0,359) size 784x60
+        LayoutInline {<pseudo:first-letter>} at (0,0) size 10x19 [color=#00FFFF]
+          LayoutTextFragment (anonymous) at (0,0) size 10x19
+            text run at (0,0) width 10: "T"
+        LayoutTextFragment {#text} at (10,0) size 19x19
+          text run at (10,0) width 19: "he "
+        LayoutInline {STRONG} at (0,0) size 66x19
+          LayoutText {#text} at (29,0) size 66x19
+            text run at (29,0) width 66: "first letter"
+        LayoutText {#text} at (95,0) size 300x19
+          text run at (95,0) width 300: " of this paragraph, and only that one, should be "
+        LayoutInline {STRONG} at (0,0) size 34x19
+          LayoutText {#text} at (395,0) size 34x19
+            text run at (395,0) width 34: "aqua"
+        LayoutText {#text} at (429,0) size 109x19
+          text run at (429,0) width 109: ", while the entire "
+        LayoutInline {STRONG} at (0,0) size 55x19
+          LayoutText {#text} at (538,0) size 55x19
+            text run at (538,0) width 55: "first line"
+        LayoutText {#text} at (593,0) size 69x19
+          text run at (593,0) width 69: " should be "
+        LayoutInline {STRONG} at (0,0) size 24x19
+          LayoutText {#text} at (662,0) size 24x19
+            text run at (662,0) width 24: "teal"
+        LayoutText {#text} at (686,0) size 778x59
+          text run at (686,0) width 92: ". If this precise"
+          text run at (0,20) width 757: "combination does not occur, then the user agent has failed this test. Remember that in order to ensure a complete test, the"
+          text run at (0,40) width 386: "paragraph must be displayed on more than one line. (TEST3)"
+      LayoutNGBlockFlow {DIV} at (0,435) size 784x20
+        LayoutText {#text} at (0,0) size 166x19
+          text run at (0,0) width 166: "You should see the words "
+        LayoutInline {STRONG} at (0,0) size 68x19
+          LayoutText {#text} at (166,0) size 68x19
+            text run at (166,0) width 68: "\"TEST1\""
+        LayoutText {#text} at (234,0) size 8x19
+          text run at (234,0) width 8: ", "
+        LayoutInline {STRONG} at (0,0) size 68x19
+          LayoutText {#text} at (242,0) size 68x19
+            text run at (242,0) width 68: "\"TEST2\""
+        LayoutText {#text} at (310,0) size 35x19
+          text run at (310,0) width 35: ", and "
+        LayoutInline {STRONG} at (0,0) size 68x19
+          LayoutText {#text} at (345,0) size 68x19
+            text run at (345,0) width 68: "\"TEST3\""
+        LayoutText {#text} at (413,0) size 236x19
+          text run at (413,0) width 236: " at the end of three paragraphs above."
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/css/pseudo-first-line-border-width-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/css/pseudo-first-line-border-width-expected.txt
new file mode 100644
index 0000000..97de6379
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/css/pseudo-first-line-border-width-expected.txt
@@ -0,0 +1,22 @@
+layer at (0,0) size 800x600
+  LayoutView at (0,0) size 800x600
+layer at (0,0) size 800x450
+  LayoutNGBlockFlow {HTML} at (0,0) size 800x450
+    LayoutNGBlockFlow {BODY} at (8,8) size 784x342
+      LayoutNGBlockFlow {DIV} at (0,0) size 784x32
+        LayoutText {#text} at (0,0) size 144x16
+          text run at (0,0) width 144: "Test for "
+        LayoutInline {A} at (0,0) size 736x32 [color=#0000EE]
+          LayoutText {#text} at (144,0) size 736x32
+            text run at (144,0) width 592: "https://bugs.webkit.org/show_bug.cgi?"
+            text run at (0,16) width 128: "id=79526"
+      LayoutNGBlockFlow {P} at (0,132) size 784x210
+        LayoutText {#text} at (0,0) size 350x10
+          text run at (0,0) width 350: "A green 10px border on the left of "
+        LayoutInline {SPAN} at (0,0) size 500x210 [border: none (100px solid #008000)]
+          LayoutText {#text} at (360,0) size 50x10
+            text run at (360,0) width 50: "this,"
+          LayoutBR {BR} at (410,0) size 0x0
+          LayoutText {#text} at (0,10) size 500x200
+            text run at (0,10) width 400: "is a"
+            text run at (0,110) width 500: "pass."
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/layers/overflow-scroll-auto-switch-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/layers/overflow-scroll-auto-switch-expected.txt
new file mode 100644
index 0000000..c62bf35c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/layers/overflow-scroll-auto-switch-expected.txt
@@ -0,0 +1,40 @@
+layer at (0,0) size 800x600
+  LayoutView at (0,0) size 800x600
+layer at (0,0) size 800x600
+  LayoutNGBlockFlow {HTML} at (0,0) size 800x600
+    LayoutNGBlockFlow {BODY} at (8,8) size 784x584
+      LayoutNGBlockFlow (anonymous) at (0,0) size 784x20
+        LayoutText {#text} at (0,0) size 146x19
+          text run at (0,0) width 146: "Scrollbars should work"
+layer at (8,28) size 100x100 clip at (8,28) size 85x85 scrollWidth 238 scrollHeight 200
+  LayoutNGBlockFlow (relative positioned) {DIV} at (0,20) size 100x100
+    LayoutText {#text} at (0,0) size 238x19
+      text run at (0,0) width 238: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+    LayoutBR {BR} at (238,0) size 0x0
+    LayoutText {#text} at (0,20) size 7x19
+      text run at (0,20) width 7: "a"
+    LayoutBR {BR} at (7,20) size 0x0
+    LayoutText {#text} at (0,40) size 7x19
+      text run at (0,40) width 7: "a"
+    LayoutBR {BR} at (7,40) size 0x0
+    LayoutText {#text} at (0,60) size 7x19
+      text run at (0,60) width 7: "a"
+    LayoutBR {BR} at (7,60) size 0x0
+    LayoutText {#text} at (0,80) size 7x19
+      text run at (0,80) width 7: "a"
+    LayoutBR {BR} at (7,80) size 0x0
+    LayoutText {#text} at (0,100) size 7x19
+      text run at (0,100) width 7: "a"
+    LayoutBR {BR} at (7,100) size 0x0
+    LayoutText {#text} at (0,120) size 7x19
+      text run at (0,120) width 7: "a"
+    LayoutBR {BR} at (7,120) size 0x0
+    LayoutText {#text} at (0,140) size 7x19
+      text run at (0,140) width 7: "a"
+    LayoutBR {BR} at (7,140) size 0x0
+    LayoutText {#text} at (0,160) size 7x19
+      text run at (0,160) width 7: "a"
+    LayoutBR {BR} at (7,160) size 0x0
+    LayoutText {#text} at (0,180) size 7x19
+      text run at (0,180) width 7: "a"
+    LayoutBR {BR} at (7,180) size 0x0
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/multicol/composited-layer-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/multicol/composited-layer-expected.txt
new file mode 100644
index 0000000..15ae8c55
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/multicol/composited-layer-expected.txt
@@ -0,0 +1,38 @@
+{
+"layers": [
+{
+"name": "LayoutView #document",
+"bounds": [800, 600],
+"drawsContent": false,
+"backgroundColor": "#FFFFFF"
+},
+{
+"name": "Scrolling Layer",
+"bounds": [800, 600],
+"drawsContent": false
+},
+{
+"name": "Scrolling Contents Layer",
+"bounds": [800, 600],
+"contentsOpaque": true,
+"backgroundColor": "#FFFFFF"
+},
+{
+"name": "LayoutNGBlockFlow DIV id='multicol'",
+"bounds": [200, 100],
+"transform": 1
+}
+],
+"transforms": [
+{
+"id": 1,
+"transform": [
+[1, 0, 0, 0],
+[0, 1, 0, 0],
+[0, 0, 1, 0],
+[8, 8, 0, 1]
+]
+}
+]
+}
+
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/scroll/scrolled-iframe-scrollbar-change-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/scroll/scrolled-iframe-scrollbar-change-expected.txt
new file mode 100644
index 0000000..d397e324
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/scroll/scrolled-iframe-scrollbar-change-expected.txt
@@ -0,0 +1,29 @@
+{
+  "objectPaintInvalidations": [
+    {
+      "object": "VerticalScrollbar",
+      "reason": "scroll control"
+    },
+    {
+      "object": "LayoutView #document",
+      "reason": "style change"
+    },
+    {
+      "object": "LayoutView #document",
+      "reason": "geometry"
+    },
+    {
+      "object": "LayoutNGBlockFlow BODY class='noScroll'",
+      "reason": "style change"
+    },
+    {
+      "object": "LayoutNGBlockFlow DIV id='container'",
+      "reason": "incremental"
+    },
+    {
+      "object": "LayoutNGBlockFlow (positioned) DIV id='overlay'",
+      "reason": "appeared"
+    }
+  ]
+}
+
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/table/border-collapse-change-collapse-to-separate-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/table/border-collapse-change-collapse-to-separate-expected.txt
new file mode 100644
index 0000000..34e15353
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/table/border-collapse-change-collapse-to-separate-expected.txt
@@ -0,0 +1,61 @@
+{
+  "layers": [
+    {
+      "name": "LayoutView #document",
+      "bounds": [800, 600],
+      "drawsContent": false,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "Scrolling Layer",
+      "bounds": [800, 600],
+      "drawsContent": false
+    },
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "paintInvalidations": [
+        {
+          "object": "LayoutTableRow TR",
+          "rect": [8, 8, 212, 108],
+          "reason": "disappeared"
+        },
+        {
+          "object": "LayoutNGTableCell TD",
+          "rect": [118, 10, 108, 108],
+          "reason": "appeared"
+        },
+        {
+          "object": "LayoutNGTableCell TD",
+          "rect": [10, 10, 106, 108],
+          "reason": "appeared"
+        }
+      ]
+    }
+  ],
+  "objectPaintInvalidations": [
+    {
+      "object": "LayoutTable TABLE id='table'",
+      "reason": "style change"
+    },
+    {
+      "object": "LayoutTableSection TBODY",
+      "reason": "style change"
+    },
+    {
+      "object": "LayoutTableRow TR",
+      "reason": "style change"
+    },
+    {
+      "object": "LayoutNGTableCell TD",
+      "reason": "style change"
+    },
+    {
+      "object": "LayoutNGTableCell TD",
+      "reason": "style change"
+    }
+  ]
+}
+
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/table/border-collapse-change-separate-to-collapse-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/table/border-collapse-change-separate-to-collapse-expected.txt
new file mode 100644
index 0000000..162f2c1
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/table/border-collapse-change-separate-to-collapse-expected.txt
@@ -0,0 +1,61 @@
+{
+  "layers": [
+    {
+      "name": "LayoutView #document",
+      "bounds": [800, 600],
+      "drawsContent": false,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "Scrolling Layer",
+      "bounds": [800, 600],
+      "drawsContent": false
+    },
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "paintInvalidations": [
+        {
+          "object": "LayoutTableRow TR",
+          "rect": [8, 8, 212, 108],
+          "reason": "appeared"
+        },
+        {
+          "object": "LayoutNGTableCell TD",
+          "rect": [118, 10, 108, 108],
+          "reason": "disappeared"
+        },
+        {
+          "object": "LayoutNGTableCell TD",
+          "rect": [10, 10, 106, 108],
+          "reason": "disappeared"
+        }
+      ]
+    }
+  ],
+  "objectPaintInvalidations": [
+    {
+      "object": "LayoutTable TABLE id='table'",
+      "reason": "style change"
+    },
+    {
+      "object": "LayoutTableSection TBODY",
+      "reason": "style change"
+    },
+    {
+      "object": "LayoutTableRow TR",
+      "reason": "style change"
+    },
+    {
+      "object": "LayoutNGTableCell TD",
+      "reason": "style change"
+    },
+    {
+      "object": "LayoutNGTableCell TD",
+      "reason": "style change"
+    }
+  ]
+}
+
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/table/composited-table-background-col-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/table/composited-table-background-col-expected.txt
new file mode 100644
index 0000000..c248188
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/table/composited-table-background-col-expected.txt
@@ -0,0 +1,44 @@
+{
+  "layers": [
+    {
+      "name": "LayoutView #document",
+      "bounds": [800, 600],
+      "drawsContent": false,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "Scrolling Layer",
+      "bounds": [800, 600],
+      "drawsContent": false
+    },
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "paintInvalidations": [
+        {
+          "object": "LayoutTableSection TBODY",
+          "rect": [8, 28, 186, 134],
+          "reason": "style change"
+        }
+      ]
+    },
+    {
+      "name": "LayoutNGTableCell TD",
+      "position": [72, 96],
+      "bounds": [59, 64]
+    }
+  ],
+  "objectPaintInvalidations": [
+    {
+      "object": "LayoutTableSection TBODY",
+      "reason": "style change"
+    },
+    {
+      "object": "LayoutTableCol COL id='target'",
+      "reason": "style change"
+    }
+  ]
+}
+
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/table/composited-table-background-col-initial-empty-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/table/composited-table-background-col-initial-empty-expected.txt
new file mode 100644
index 0000000..14f2346
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/table/composited-table-background-col-initial-empty-expected.txt
@@ -0,0 +1,44 @@
+{
+  "layers": [
+    {
+      "name": "LayoutView #document",
+      "bounds": [800, 600],
+      "drawsContent": false,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "Scrolling Layer",
+      "bounds": [800, 600],
+      "drawsContent": false
+    },
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "paintInvalidations": [
+        {
+          "object": "LayoutTableSection TBODY",
+          "rect": [8, 28, 186, 134],
+          "reason": "appeared"
+        }
+      ]
+    },
+    {
+      "name": "LayoutNGTableCell TD",
+      "position": [72, 96],
+      "bounds": [59, 64]
+    }
+  ],
+  "objectPaintInvalidations": [
+    {
+      "object": "LayoutTableSection TBODY",
+      "reason": "style change"
+    },
+    {
+      "object": "LayoutTableCol COL id='target'",
+      "reason": "style change"
+    }
+  ]
+}
+
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/table/composited-table-background-col-span-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/table/composited-table-background-col-span-expected.txt
new file mode 100644
index 0000000..c928082
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/table/composited-table-background-col-span-expected.txt
@@ -0,0 +1,49 @@
+{
+  "layers": [
+    {
+      "name": "LayoutView #document",
+      "bounds": [800, 600],
+      "drawsContent": false,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "Scrolling Layer",
+      "bounds": [800, 600],
+      "drawsContent": false
+    },
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "paintInvalidations": [
+        {
+          "object": "LayoutTableSection TBODY",
+          "rect": [8, 28, 186, 134],
+          "reason": "style change"
+        }
+      ]
+    },
+    {
+      "name": "LayoutNGTableCell TD",
+      "position": [72, 96],
+      "bounds": [59, 64]
+    },
+    {
+      "name": "LayoutNGTableCell TD",
+      "position": [133, 96],
+      "bounds": [59, 64]
+    }
+  ],
+  "objectPaintInvalidations": [
+    {
+      "object": "LayoutTableSection TBODY",
+      "reason": "style change"
+    },
+    {
+      "object": "LayoutTableCol COL id='target'",
+      "reason": "style change"
+    }
+  ]
+}
+
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/table/composited-table-background-col-span-initial-empty-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/table/composited-table-background-col-span-initial-empty-expected.txt
new file mode 100644
index 0000000..5af5f13
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/table/composited-table-background-col-span-initial-empty-expected.txt
@@ -0,0 +1,49 @@
+{
+  "layers": [
+    {
+      "name": "LayoutView #document",
+      "bounds": [800, 600],
+      "drawsContent": false,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "Scrolling Layer",
+      "bounds": [800, 600],
+      "drawsContent": false
+    },
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "paintInvalidations": [
+        {
+          "object": "LayoutTableSection TBODY",
+          "rect": [8, 28, 186, 134],
+          "reason": "appeared"
+        }
+      ]
+    },
+    {
+      "name": "LayoutNGTableCell TD",
+      "position": [72, 96],
+      "bounds": [59, 64]
+    },
+    {
+      "name": "LayoutNGTableCell TD",
+      "position": [133, 96],
+      "bounds": [59, 64]
+    }
+  ],
+  "objectPaintInvalidations": [
+    {
+      "object": "LayoutTableSection TBODY",
+      "reason": "style change"
+    },
+    {
+      "object": "LayoutTableCol COL id='target'",
+      "reason": "style change"
+    }
+  ]
+}
+
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/table/composited-table-background-colgroup-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/table/composited-table-background-colgroup-expected.txt
new file mode 100644
index 0000000..4c0c5aa
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/table/composited-table-background-colgroup-expected.txt
@@ -0,0 +1,44 @@
+{
+  "layers": [
+    {
+      "name": "LayoutView #document",
+      "bounds": [800, 600],
+      "drawsContent": false,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "Scrolling Layer",
+      "bounds": [800, 600],
+      "drawsContent": false
+    },
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "paintInvalidations": [
+        {
+          "object": "LayoutTableSection TBODY",
+          "rect": [8, 28, 186, 134],
+          "reason": "style change"
+        }
+      ]
+    },
+    {
+      "name": "LayoutNGTableCell TD id='target'",
+      "position": [72, 96],
+      "bounds": [59, 64]
+    }
+  ],
+  "objectPaintInvalidations": [
+    {
+      "object": "LayoutTableSection TBODY",
+      "reason": "style change"
+    },
+    {
+      "object": "LayoutTableCol COLGROUP id='target'",
+      "reason": "style change"
+    }
+  ]
+}
+
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/table/composited-table-background-colgroup-initial-empty-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/table/composited-table-background-colgroup-initial-empty-expected.txt
new file mode 100644
index 0000000..eaad2eaa
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/table/composited-table-background-colgroup-initial-empty-expected.txt
@@ -0,0 +1,44 @@
+{
+  "layers": [
+    {
+      "name": "LayoutView #document",
+      "bounds": [800, 600],
+      "drawsContent": false,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "Scrolling Layer",
+      "bounds": [800, 600],
+      "drawsContent": false
+    },
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "paintInvalidations": [
+        {
+          "object": "LayoutTableSection TBODY",
+          "rect": [8, 28, 186, 134],
+          "reason": "appeared"
+        }
+      ]
+    },
+    {
+      "name": "LayoutNGTableCell TD id='target'",
+      "position": [72, 96],
+      "bounds": [59, 64]
+    }
+  ],
+  "objectPaintInvalidations": [
+    {
+      "object": "LayoutTableSection TBODY",
+      "reason": "style change"
+    },
+    {
+      "object": "LayoutTableCol COLGROUP id='target'",
+      "reason": "style change"
+    }
+  ]
+}
+
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/table/composited-table-background-composited-row-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/table/composited-table-background-composited-row-expected.txt
new file mode 100644
index 0000000..77e48e4
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/table/composited-table-background-composited-row-expected.txt
@@ -0,0 +1,46 @@
+{
+  "layers": [
+    {
+      "name": "LayoutView #document",
+      "bounds": [800, 600],
+      "drawsContent": false,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "Scrolling Layer",
+      "bounds": [800, 600],
+      "drawsContent": false
+    },
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "LayoutTableRow TR id='target'",
+      "position": [8, 96],
+      "bounds": [186, 64],
+      "backgroundColor": "#ADD8E6",
+      "paintInvalidations": [
+        {
+          "object": "LayoutTableRow TR id='target'",
+          "rect": [0, 0, 186, 64],
+          "reason": "style change"
+        }
+      ]
+    },
+    {
+      "name": "LayoutNGTableCell TD",
+      "position": [72, 96],
+      "bounds": [59, 64]
+    }
+  ],
+  "objectPaintInvalidations": [
+    {
+      "object": "LayoutTableRow TR id='target'",
+      "reason": "style change"
+    }
+  ]
+}
+
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/table/composited-table-background-composited-row-initial-empty-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/table/composited-table-background-composited-row-initial-empty-expected.txt
new file mode 100644
index 0000000..6e2264e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/table/composited-table-background-composited-row-initial-empty-expected.txt
@@ -0,0 +1,46 @@
+{
+  "layers": [
+    {
+      "name": "LayoutView #document",
+      "bounds": [800, 600],
+      "drawsContent": false,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "Scrolling Layer",
+      "bounds": [800, 600],
+      "drawsContent": false
+    },
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "LayoutTableRow TR id='target'",
+      "position": [8, 96],
+      "bounds": [186, 64],
+      "backgroundColor": "#ADD8E6",
+      "paintInvalidations": [
+        {
+          "object": "LayoutTableRow TR id='target'",
+          "rect": [0, 0, 186, 64],
+          "reason": "appeared"
+        }
+      ]
+    },
+    {
+      "name": "LayoutNGTableCell TD",
+      "position": [72, 96],
+      "bounds": [59, 64]
+    }
+  ],
+  "objectPaintInvalidations": [
+    {
+      "object": "LayoutTableRow TR id='target'",
+      "reason": "style change"
+    }
+  ]
+}
+
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/table/composited-table-background-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/table/composited-table-background-expected.txt
new file mode 100644
index 0000000..27e4e62
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/table/composited-table-background-expected.txt
@@ -0,0 +1,40 @@
+{
+  "layers": [
+    {
+      "name": "LayoutView #document",
+      "bounds": [800, 600],
+      "drawsContent": false,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "Scrolling Layer",
+      "bounds": [800, 600],
+      "drawsContent": false
+    },
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "paintInvalidations": [
+        {
+          "object": "LayoutTableRow TR id='target'",
+          "rect": [8, 96, 186, 64],
+          "reason": "style change"
+        }
+      ]
+    },
+    {
+      "name": "LayoutNGTableCell TD",
+      "position": [72, 96],
+      "bounds": [59, 64]
+    }
+  ],
+  "objectPaintInvalidations": [
+    {
+      "object": "LayoutTableRow TR id='target'",
+      "reason": "style change"
+    }
+  ]
+}
+
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/table/composited-table-background-section-composited-row-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/table/composited-table-background-section-composited-row-expected.txt
new file mode 100644
index 0000000..2680307
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/table/composited-table-background-section-composited-row-expected.txt
@@ -0,0 +1,51 @@
+{
+  "layers": [
+    {
+      "name": "LayoutView #document",
+      "bounds": [800, 600],
+      "drawsContent": false,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "Scrolling Layer",
+      "bounds": [800, 600],
+      "drawsContent": false
+    },
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "LayoutTableSection TBODY id='target'",
+      "position": [8, 28],
+      "bounds": [186, 134],
+      "backgroundColor": "#ADD8E6",
+      "paintInvalidations": [
+        {
+          "object": "LayoutTableSection TBODY id='target'",
+          "rect": [0, 0, 186, 134],
+          "reason": "style change"
+        }
+      ]
+    },
+    {
+      "name": "LayoutTableRow TR",
+      "position": [8, 96],
+      "bounds": [186, 64]
+    },
+    {
+      "name": "LayoutNGTableCell TD",
+      "position": [72, 96],
+      "bounds": [59, 64]
+    }
+  ],
+  "objectPaintInvalidations": [
+    {
+      "object": "LayoutTableSection TBODY id='target'",
+      "reason": "style change"
+    }
+  ]
+}
+
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/table/composited-table-background-section-composited-row-initial-empty-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/table/composited-table-background-section-composited-row-initial-empty-expected.txt
new file mode 100644
index 0000000..501a148
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/table/composited-table-background-section-composited-row-initial-empty-expected.txt
@@ -0,0 +1,51 @@
+{
+  "layers": [
+    {
+      "name": "LayoutView #document",
+      "bounds": [800, 600],
+      "drawsContent": false,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "Scrolling Layer",
+      "bounds": [800, 600],
+      "drawsContent": false
+    },
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "LayoutTableSection TBODY id='target'",
+      "position": [8, 28],
+      "bounds": [186, 134],
+      "backgroundColor": "#ADD8E6",
+      "paintInvalidations": [
+        {
+          "object": "LayoutTableSection TBODY id='target'",
+          "rect": [0, 0, 186, 134],
+          "reason": "appeared"
+        }
+      ]
+    },
+    {
+      "name": "LayoutTableRow TR",
+      "position": [8, 96],
+      "bounds": [186, 64]
+    },
+    {
+      "name": "LayoutNGTableCell TD",
+      "position": [72, 96],
+      "bounds": [59, 64]
+    }
+  ],
+  "objectPaintInvalidations": [
+    {
+      "object": "LayoutTableSection TBODY id='target'",
+      "reason": "style change"
+    }
+  ]
+}
+
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/table/composited-table-background-section-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/table/composited-table-background-section-expected.txt
new file mode 100644
index 0000000..8df78fd7f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/table/composited-table-background-section-expected.txt
@@ -0,0 +1,46 @@
+{
+  "layers": [
+    {
+      "name": "LayoutView #document",
+      "bounds": [800, 600],
+      "drawsContent": false,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "Scrolling Layer",
+      "bounds": [800, 600],
+      "drawsContent": false
+    },
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "LayoutTableSection TBODY id='target'",
+      "position": [8, 28],
+      "bounds": [186, 134],
+      "backgroundColor": "#ADD8E6",
+      "paintInvalidations": [
+        {
+          "object": "LayoutTableSection TBODY id='target'",
+          "rect": [0, 0, 186, 134],
+          "reason": "style change"
+        }
+      ]
+    },
+    {
+      "name": "LayoutNGTableCell TD",
+      "position": [72, 96],
+      "bounds": [59, 64]
+    }
+  ],
+  "objectPaintInvalidations": [
+    {
+      "object": "LayoutTableSection TBODY id='target'",
+      "reason": "style change"
+    }
+  ]
+}
+
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/table/composited-table-background-section-initial-empty-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/table/composited-table-background-section-initial-empty-expected.txt
new file mode 100644
index 0000000..40d9017
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/table/composited-table-background-section-initial-empty-expected.txt
@@ -0,0 +1,46 @@
+{
+  "layers": [
+    {
+      "name": "LayoutView #document",
+      "bounds": [800, 600],
+      "drawsContent": false,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "Scrolling Layer",
+      "bounds": [800, 600],
+      "drawsContent": false
+    },
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "LayoutTableSection TBODY id='target'",
+      "position": [8, 28],
+      "bounds": [186, 134],
+      "backgroundColor": "#ADD8E6",
+      "paintInvalidations": [
+        {
+          "object": "LayoutTableSection TBODY id='target'",
+          "rect": [0, 0, 186, 134],
+          "reason": "appeared"
+        }
+      ]
+    },
+    {
+      "name": "LayoutNGTableCell TD",
+      "position": [72, 96],
+      "bounds": [59, 64]
+    }
+  ],
+  "objectPaintInvalidations": [
+    {
+      "object": "LayoutTableSection TBODY id='target'",
+      "reason": "style change"
+    }
+  ]
+}
+
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/table/invalidate-cell-in-row-with-offset-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/table/invalidate-cell-in-row-with-offset-expected.txt
new file mode 100644
index 0000000..06fd34f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/table/invalidate-cell-in-row-with-offset-expected.txt
@@ -0,0 +1,52 @@
+{
+  "layers": [
+    {
+      "name": "LayoutView #document",
+      "bounds": [800, 600],
+      "drawsContent": false,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "Scrolling Layer",
+      "bounds": [800, 600],
+      "drawsContent": false
+    },
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "LayoutTableRow TR",
+      "position": [8, 18],
+      "backgroundColor": "#0000FF"
+    },
+    {
+      "name": "LayoutTableRow TR",
+      "position": [8, 28],
+      "bounds": [234, 102],
+      "backgroundColor": "#0000FF"
+    },
+    {
+      "name": "LayoutTableRow TR class='shadow-inset'",
+      "position": [8, 140],
+      "bounds": [234, 102],
+      "backgroundColor": "#0000FF",
+      "paintInvalidations": [
+        {
+          "object": "LayoutNGTableCell TD id='target'",
+          "rect": [10, 0, 102, 102],
+          "reason": "style change"
+        }
+      ]
+    }
+  ],
+  "objectPaintInvalidations": [
+    {
+      "object": "LayoutNGTableCell TD id='target'",
+      "reason": "style change"
+    }
+  ]
+}
+
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/virtual/gpu-rasterization/images/imagemap-focus-ring-outline-color-not-inherited-from-map-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/virtual/gpu-rasterization/images/imagemap-focus-ring-outline-color-not-inherited-from-map-expected.txt
index b12b951..8a11621 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/virtual/gpu-rasterization/images/imagemap-focus-ring-outline-color-not-inherited-from-map-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/virtual/gpu-rasterization/images/imagemap-focus-ring-outline-color-not-inherited-from-map-expected.txt
@@ -12,7 +12,7 @@
             text run at (207,20) width 467: "section 18.4 \"Dynamic outlines: the 'outline' property\" of the CSS2.1 spec"
         LayoutText {#text} at (674,20) size 735x39
           text run at (674,20) width 61: ". This test"
-          text run at (0,40) width 566: "FAILED if a red-colored focus ring is drawn around the <area> in the imagemap (below)."
+          text run at (0,40) width 565: "FAILED if a red-colored focus ring is drawn around the <area> in the imagemap (below)."
       LayoutNGBlockFlow (anonymous) at (0,76) size 784x133
         LayoutInline {MAP} at (0,0) size 0x0
           LayoutText {#text} at (0,0) size 0x0
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/svg/transform-foreign-object-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/svg/transform-foreign-object-expected.txt
index 9f4690d..027be07 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/svg/transform-foreign-object-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/svg/transform-foreign-object-expected.txt
@@ -12,7 +12,7 @@
           "reason": "appeared"
         },
         {
-          "object": "LayoutSVGRoot svg",
+          "object": "LayoutSVGForeignObject foreignObject",
           "rect": [8, 8, 100, 100],
           "reason": "disappeared"
         }
diff --git a/third_party/WebKit/LayoutTests/http/tests/credentialmanager/credentialscontainer-create-from-nested-frame-expected.txt b/third_party/WebKit/LayoutTests/http/tests/credentialmanager/credentialscontainer-create-from-nested-frame-expected.txt
index e58e3453..1303d62 100644
--- a/third_party/WebKit/LayoutTests/http/tests/credentialmanager/credentialscontainer-create-from-nested-frame-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/credentialmanager/credentialscontainer-create-from-nested-frame-expected.txt
@@ -1,6 +1,10 @@
+CONSOLE WARNING: line 10: The following mojom is loaded multiple times: mojo/public/mojom/base/string16.mojom
+CONSOLE WARNING: line 10: The following mojom is loaded multiple times: mojo/public/mojom/base/big_buffer.mojom
 CONSOLE WARNING: line 10: The following mojom is loaded multiple times: url/mojom/origin.mojom
 CONSOLE WARNING: line 10: The following mojom is loaded multiple times: url/mojom/url.mojom
 CONSOLE WARNING: line 10: The following mojom is loaded multiple times: mojo/public/mojom/base/time.mojom
+CONSOLE WARNING: line 10: The following mojom is loaded multiple times: mojo/public/mojom/base/string16.mojom
+CONSOLE WARNING: line 10: The following mojom is loaded multiple times: mojo/public/mojom/base/big_buffer.mojom
 CONSOLE WARNING: line 10: The following mojom is loaded multiple times: url/mojom/origin.mojom
 CONSOLE WARNING: line 10: The following mojom is loaded multiple times: url/mojom/url.mojom
 CONSOLE WARNING: line 10: The following mojom is loaded multiple times: mojo/public/mojom/base/time.mojom
diff --git a/third_party/WebKit/LayoutTests/http/tests/credentialmanager/credentialscontainer-get-from-nested-frame-expected.txt b/third_party/WebKit/LayoutTests/http/tests/credentialmanager/credentialscontainer-get-from-nested-frame-expected.txt
index 3f782f4..a41df896 100644
--- a/third_party/WebKit/LayoutTests/http/tests/credentialmanager/credentialscontainer-get-from-nested-frame-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/credentialmanager/credentialscontainer-get-from-nested-frame-expected.txt
@@ -1,6 +1,10 @@
+CONSOLE WARNING: line 10: The following mojom is loaded multiple times: mojo/public/mojom/base/string16.mojom
+CONSOLE WARNING: line 10: The following mojom is loaded multiple times: mojo/public/mojom/base/big_buffer.mojom
 CONSOLE WARNING: line 10: The following mojom is loaded multiple times: url/mojom/origin.mojom
 CONSOLE WARNING: line 10: The following mojom is loaded multiple times: url/mojom/url.mojom
 CONSOLE WARNING: line 10: The following mojom is loaded multiple times: mojo/public/mojom/base/time.mojom
+CONSOLE WARNING: line 10: The following mojom is loaded multiple times: mojo/public/mojom/base/string16.mojom
+CONSOLE WARNING: line 10: The following mojom is loaded multiple times: mojo/public/mojom/base/big_buffer.mojom
 CONSOLE WARNING: line 10: The following mojom is loaded multiple times: url/mojom/origin.mojom
 CONSOLE WARNING: line 10: The following mojom is loaded multiple times: url/mojom/url.mojom
 CONSOLE WARNING: line 10: The following mojom is loaded multiple times: mojo/public/mojom/base/time.mojom
diff --git a/third_party/WebKit/LayoutTests/http/tests/credentialmanager/resources/credential-helpers.js b/third_party/WebKit/LayoutTests/http/tests/credentialmanager/resources/credential-helpers.js
index aa8bfd1..7865ab3 100644
--- a/third_party/WebKit/LayoutTests/http/tests/credentialmanager/resources/credential-helpers.js
+++ b/third_party/WebKit/LayoutTests/http/tests/credentialmanager/resources/credential-helpers.js
@@ -1,5 +1,15 @@
 'use strict';
 
+// Converts an ECMAScript String object to an instance of
+// mojo_base.mojom.String16.
+function stringToMojoString16(string) {
+  let array = new Array(string.length);
+  for (var i = 0; i < string.length; ++i) {
+    array[i] = string.charCodeAt(i);
+  }
+  return { data: array }
+}
+
 // Mocks the CredentialManager interface defined in credential_manager.mojom.
 class MockCredentialManager {
   constructor() {
@@ -17,10 +27,10 @@
   constructCredentialInfo_(type, id, password, name, icon) {
   return new passwordManager.mojom.CredentialInfo({
       type: type,
-      id: id,
-      name: name,
+      id: stringToMojoString16(id),
+      name: stringToMojoString16(name),
       icon: new url.mojom.Url({url: icon}),
-    password: password,
+      password: stringToMojoString16(password),
       federation: new url.mojom.Origin(
           {scheme: '', host: '', port: 0, unique: true})
     });
diff --git a/third_party/WebKit/LayoutTests/http/tests/media/controls/video-controls-overflow-menu-correct-ordering.html b/third_party/WebKit/LayoutTests/http/tests/media/controls/video-controls-overflow-menu-correct-ordering.html
index 332cbe6f..8a22933 100644
--- a/third_party/WebKit/LayoutTests/http/tests/media/controls/video-controls-overflow-menu-correct-ordering.html
+++ b/third_party/WebKit/LayoutTests/http/tests/media/controls/video-controls-overflow-menu-correct-ordering.html
@@ -35,8 +35,8 @@
       assert_equals(internals.shadowPseudoId(innerButton), overflowButtonsCSS[i]);
       // Items should be visible
       assert_not_equals(getComputedStyle(child).display, "none");
-      // Buttons shouldn't be visible
-      assert_equals(getComputedStyle(innerButton).display, "none");
+      // Buttons should be visible
+      assert_equals(getComputedStyle(innerButton).display, "flex");
     }
   });
 });
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/svg/repaint-svg-after-style-change-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/svg/repaint-svg-after-style-change-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/platform/win/paint/invalidation/svg/repaint-svg-after-style-change-expected.txt
rename to third_party/WebKit/LayoutTests/paint/invalidation/svg/repaint-svg-after-style-change-expected.txt
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/svg/transform-foreign-object-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/svg/transform-foreign-object-expected.txt
index b4bd747..4cc12b4 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/svg/transform-foreign-object-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/svg/transform-foreign-object-expected.txt
@@ -23,22 +23,12 @@
           "reason": "appeared"
         },
         {
-          "object": "LayoutSVGRoot svg",
+          "object": "LayoutSVGForeignObject foreignObject",
           "rect": [8, 8, 100, 100],
           "reason": "disappeared"
         }
       ]
     }
-  ],
-  "objectPaintInvalidations": [
-    {
-      "object": "LayoutSVGForeignObject foreignObject",
-      "reason": "style change"
-    },
-    {
-      "object": "LayoutBlockFlow DIV",
-      "reason": "style change"
-    }
   ]
 }
 
diff --git a/third_party/WebKit/LayoutTests/platform/android/fast/css/line-height-font-order-expected.txt b/third_party/WebKit/LayoutTests/platform/android/fast/css/line-height-font-order-expected.txt
new file mode 100644
index 0000000..7e0704f8
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/android/fast/css/line-height-font-order-expected.txt
@@ -0,0 +1,21 @@
+layer at (0,0) size 800x600
+  LayoutView at (0,0) size 800x600
+layer at (0,0) size 800x196
+  LayoutBlockFlow {HTML} at (0,0) size 800x196
+    LayoutBlockFlow {BODY} at (8,15) size 784x166
+      LayoutBlockFlow {P} at (0,0) size 784x75
+        LayoutText {#text} at (0,28) size 94x18
+          text run at (0,28) width 94: "This tests bug "
+        LayoutInline {A} at (0,0) size 651x18 [color=#0000EE]
+          LayoutText {#text} at (94,28) size 651x18
+            text run at (94,28) width 651: "Bug 13174: line-height in font shorthand does not override a previously stated line-height property"
+        LayoutText {#text} at (745,28) size 4x18
+          text run at (745,28) width 4: "."
+      LayoutBlockFlow {P} at (0,90) size 784x76
+        LayoutText {#text} at (0,28) size 129x18
+          text run at (0,28) width 129: "This text should be "
+        LayoutInline {CODE} at (0,0) size 189x17
+          LayoutText {#text} at (129,30) size 189x17
+            text run at (129,30) width 189: "font:15px/5em Georgia"
+        LayoutText {#text} at (318,28) size 4x18
+          text run at (318,28) width 4: "."
diff --git a/third_party/WebKit/LayoutTests/platform/android/fast/css/line-thickness-underline-strikethrough-overline-expected.txt b/third_party/WebKit/LayoutTests/platform/android/fast/css/line-thickness-underline-strikethrough-overline-expected.txt
new file mode 100644
index 0000000..c8b1eb0
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/android/fast/css/line-thickness-underline-strikethrough-overline-expected.txt
@@ -0,0 +1,25 @@
+layer at (0,0) size 800x600 scrollWidth 1031
+  LayoutView at (0,0) size 800x600
+layer at (0,0) size 800x251
+  LayoutBlockFlow {HTML} at (0,0) size 800x251
+    LayoutBlockFlow {BODY} at (8,8) size 784x235
+      LayoutBlockFlow {DIV} at (0,0) size 784x24
+        LayoutBlockFlow {P} at (5,0) size 774x24 [color=#FF000066]
+          LayoutText {#text} at (0,0) size 483x24
+            text run at (0,0) width 483: "Check if the underline is thick enough for 20px"
+      LayoutBlockFlow {DIV} at (0,29) size 784x46
+        LayoutBlockFlow {P} at (5,0) size 774x46 [color=#FF000066]
+          LayoutText {#text} at (0,0) size 963x46
+            text run at (0,0) width 963: "Check if the underline is thick enough for 40px"
+      LayoutBlockFlow {P} at (5,80) size 774x24 [color=#FF000066]
+        LayoutText {#text} at (0,0) size 514x24
+          text run at (0,0) width 514: "Check if the line-through is thick enough for 20px"
+      LayoutBlockFlow {P} at (5,109) size 774x46 [color=#FF000066]
+        LayoutText {#text} at (0,0) size 1018x46
+          text run at (0,0) width 1018: "Check if the line-through is thick enough for 40px"
+      LayoutBlockFlow {P} at (5,160) size 774x24 [color=#FF000066]
+        LayoutText {#text} at (0,0) size 466x24
+          text run at (0,0) width 466: "Check if the overline is thick enough for 20px"
+      LayoutBlockFlow {P} at (5,189) size 774x46 [color=#FF000066]
+        LayoutText {#text} at (0,0) size 929x46
+          text run at (0,0) width 929: "Check if the overline is thick enough for 40px"
diff --git a/third_party/WebKit/LayoutTests/platform/fuchsia/fast/css/line-height-font-order-expected.png b/third_party/WebKit/LayoutTests/platform/fuchsia/fast/css/line-height-font-order-expected.png
new file mode 100644
index 0000000..94e6e17
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/fuchsia/fast/css/line-height-font-order-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/fuchsia/fast/css/line-height-font-order-expected.txt b/third_party/WebKit/LayoutTests/platform/fuchsia/fast/css/line-height-font-order-expected.txt
new file mode 100644
index 0000000..7e0704f8
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/fuchsia/fast/css/line-height-font-order-expected.txt
@@ -0,0 +1,21 @@
+layer at (0,0) size 800x600
+  LayoutView at (0,0) size 800x600
+layer at (0,0) size 800x196
+  LayoutBlockFlow {HTML} at (0,0) size 800x196
+    LayoutBlockFlow {BODY} at (8,15) size 784x166
+      LayoutBlockFlow {P} at (0,0) size 784x75
+        LayoutText {#text} at (0,28) size 94x18
+          text run at (0,28) width 94: "This tests bug "
+        LayoutInline {A} at (0,0) size 651x18 [color=#0000EE]
+          LayoutText {#text} at (94,28) size 651x18
+            text run at (94,28) width 651: "Bug 13174: line-height in font shorthand does not override a previously stated line-height property"
+        LayoutText {#text} at (745,28) size 4x18
+          text run at (745,28) width 4: "."
+      LayoutBlockFlow {P} at (0,90) size 784x76
+        LayoutText {#text} at (0,28) size 129x18
+          text run at (0,28) width 129: "This text should be "
+        LayoutInline {CODE} at (0,0) size 189x17
+          LayoutText {#text} at (129,30) size 189x17
+            text run at (129,30) width 189: "font:15px/5em Georgia"
+        LayoutText {#text} at (318,28) size 4x18
+          text run at (318,28) width 4: "."
diff --git a/third_party/WebKit/LayoutTests/platform/fuchsia/fast/css/line-thickness-underline-strikethrough-overline-expected.png b/third_party/WebKit/LayoutTests/platform/fuchsia/fast/css/line-thickness-underline-strikethrough-overline-expected.png
new file mode 100644
index 0000000..01f7e93
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/fuchsia/fast/css/line-thickness-underline-strikethrough-overline-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/fuchsia/fast/css/line-thickness-underline-strikethrough-overline-expected.txt b/third_party/WebKit/LayoutTests/platform/fuchsia/fast/css/line-thickness-underline-strikethrough-overline-expected.txt
new file mode 100644
index 0000000..c8b1eb0
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/fuchsia/fast/css/line-thickness-underline-strikethrough-overline-expected.txt
@@ -0,0 +1,25 @@
+layer at (0,0) size 800x600 scrollWidth 1031
+  LayoutView at (0,0) size 800x600
+layer at (0,0) size 800x251
+  LayoutBlockFlow {HTML} at (0,0) size 800x251
+    LayoutBlockFlow {BODY} at (8,8) size 784x235
+      LayoutBlockFlow {DIV} at (0,0) size 784x24
+        LayoutBlockFlow {P} at (5,0) size 774x24 [color=#FF000066]
+          LayoutText {#text} at (0,0) size 483x24
+            text run at (0,0) width 483: "Check if the underline is thick enough for 20px"
+      LayoutBlockFlow {DIV} at (0,29) size 784x46
+        LayoutBlockFlow {P} at (5,0) size 774x46 [color=#FF000066]
+          LayoutText {#text} at (0,0) size 963x46
+            text run at (0,0) width 963: "Check if the underline is thick enough for 40px"
+      LayoutBlockFlow {P} at (5,80) size 774x24 [color=#FF000066]
+        LayoutText {#text} at (0,0) size 514x24
+          text run at (0,0) width 514: "Check if the line-through is thick enough for 20px"
+      LayoutBlockFlow {P} at (5,109) size 774x46 [color=#FF000066]
+        LayoutText {#text} at (0,0) size 1018x46
+          text run at (0,0) width 1018: "Check if the line-through is thick enough for 40px"
+      LayoutBlockFlow {P} at (5,160) size 774x24 [color=#FF000066]
+        LayoutText {#text} at (0,0) size 466x24
+          text run at (0,0) width 466: "Check if the overline is thick enough for 20px"
+      LayoutBlockFlow {P} at (5,189) size 774x46 [color=#FF000066]
+        LayoutText {#text} at (0,0) size 929x46
+          text run at (0,0) width 929: "Check if the overline is thick enough for 40px"
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/block/margin-collapse/103-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/block/margin-collapse/103-expected.png
index 5269f8a..7736f52 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/block/margin-collapse/103-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/block/margin-collapse/103-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/block/positioning/047-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/block/positioning/047-expected.png
index 182168f4..3f83129 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/block/positioning/047-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/block/positioning/047-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/css/line-height-font-order-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/css/line-height-font-order-expected.png
index 94e6e17..b22c3ea 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/css/line-height-font-order-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/css/line-height-font-order-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/css/line-height-font-order-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/fast/css/line-height-font-order-expected.txt
index 7e0704f8..32ec97c 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/css/line-height-font-order-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/css/line-height-font-order-expected.txt
@@ -1,21 +1,21 @@
 layer at (0,0) size 800x600
   LayoutView at (0,0) size 800x600
-layer at (0,0) size 800x196
-  LayoutBlockFlow {HTML} at (0,0) size 800x196
-    LayoutBlockFlow {BODY} at (8,15) size 784x166
+layer at (0,0) size 800x195
+  LayoutBlockFlow {HTML} at (0,0) size 800x195
+    LayoutBlockFlow {BODY} at (8,15) size 784x165
       LayoutBlockFlow {P} at (0,0) size 784x75
-        LayoutText {#text} at (0,28) size 94x18
+        LayoutText {#text} at (0,28) size 94x19
           text run at (0,28) width 94: "This tests bug "
-        LayoutInline {A} at (0,0) size 651x18 [color=#0000EE]
-          LayoutText {#text} at (94,28) size 651x18
+        LayoutInline {A} at (0,0) size 651x19 [color=#0000EE]
+          LayoutText {#text} at (94,28) size 651x19
             text run at (94,28) width 651: "Bug 13174: line-height in font shorthand does not override a previously stated line-height property"
-        LayoutText {#text} at (745,28) size 4x18
+        LayoutText {#text} at (745,28) size 4x19
           text run at (745,28) width 4: "."
-      LayoutBlockFlow {P} at (0,90) size 784x76
-        LayoutText {#text} at (0,28) size 129x18
+      LayoutBlockFlow {P} at (0,90) size 784x75
+        LayoutText {#text} at (0,28) size 129x19
           text run at (0,28) width 129: "This text should be "
         LayoutInline {CODE} at (0,0) size 189x17
-          LayoutText {#text} at (129,30) size 189x17
-            text run at (129,30) width 189: "font:15px/5em Georgia"
-        LayoutText {#text} at (318,28) size 4x18
+          LayoutText {#text} at (129,29) size 189x17
+            text run at (129,29) width 189: "font:15px/5em Georgia"
+        LayoutText {#text} at (318,28) size 4x19
           text run at (318,28) width 4: "."
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/css/line-thickness-underline-strikethrough-overline-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/css/line-thickness-underline-strikethrough-overline-expected.png
index 01f7e93..fad9e0c 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/css/line-thickness-underline-strikethrough-overline-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/css/line-thickness-underline-strikethrough-overline-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/css/line-thickness-underline-strikethrough-overline-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/fast/css/line-thickness-underline-strikethrough-overline-expected.txt
new file mode 100644
index 0000000..3777e174
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/css/line-thickness-underline-strikethrough-overline-expected.txt
@@ -0,0 +1,25 @@
+layer at (0,0) size 800x600 scrollWidth 1031
+  LayoutView at (0,0) size 800x600
+layer at (0,0) size 800x266
+  LayoutBlockFlow {HTML} at (0,0) size 800x266
+    LayoutBlockFlow {BODY} at (8,8) size 784x250
+      LayoutBlockFlow {DIV} at (0,0) size 784x25
+        LayoutBlockFlow {P} at (5,0) size 774x25 [color=#FF000066]
+          LayoutText {#text} at (0,0) size 483x25
+            text run at (0,0) width 483: "Check if the underline is thick enough for 20px"
+      LayoutBlockFlow {DIV} at (0,30) size 784x50
+        LayoutBlockFlow {P} at (5,0) size 774x50 [color=#FF000066]
+          LayoutText {#text} at (0,0) size 963x50
+            text run at (0,0) width 963: "Check if the underline is thick enough for 40px"
+      LayoutBlockFlow {P} at (5,85) size 774x25 [color=#FF000066]
+        LayoutText {#text} at (0,0) size 514x25
+          text run at (0,0) width 514: "Check if the line-through is thick enough for 20px"
+      LayoutBlockFlow {P} at (5,115) size 774x50 [color=#FF000066]
+        LayoutText {#text} at (0,0) size 1018x50
+          text run at (0,0) width 1018: "Check if the line-through is thick enough for 40px"
+      LayoutBlockFlow {P} at (5,170) size 774x25 [color=#FF000066]
+        LayoutText {#text} at (0,0) size 466x25
+          text run at (0,0) width 466: "Check if the overline is thick enough for 20px"
+      LayoutBlockFlow {P} at (5,200) size 774x50 [color=#FF000066]
+        LayoutText {#text} at (0,0) size 929x50
+          text run at (0,0) width 929: "Check if the overline is thick enough for 40px"
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/text-control-intrinsic-widths-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/text-control-intrinsic-widths-expected.txt
index 951cef4..9617817f 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/text-control-intrinsic-widths-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/text-control-intrinsic-widths-expected.txt
@@ -249,29 +249,29 @@
 Georgia
 input
 size=1 clientWidth=18
-size=2 clientWidth=24
-size=3 clientWidth=30
-size=4 clientWidth=36
-size=5 clientWidth=42
-size=10 clientWidth=72
-size=20 clientWidth=132
-size=50 clientWidth=312
-size=100 clientWidth=612
-size=500 clientWidth=3012
-size=1000 clientWidth=6012
+size=2 clientWidth=26
+size=3 clientWidth=34
+size=4 clientWidth=42
+size=5 clientWidth=50
+size=10 clientWidth=90
+size=20 clientWidth=170
+size=50 clientWidth=410
+size=100 clientWidth=810
+size=500 clientWidth=4010
+size=1000 clientWidth=8010
 
 textarea
-cols=1 clientWidth=23
-cols=2 clientWidth=29
-cols=3 clientWidth=35
-cols=4 clientWidth=41
-cols=5 clientWidth=47
-cols=10 clientWidth=77
-cols=20 clientWidth=137
-cols=50 clientWidth=317
-cols=100 clientWidth=617
-cols=500 clientWidth=3017
-cols=1000 clientWidth=6017
+cols=1 clientWidth=25
+cols=2 clientWidth=33
+cols=3 clientWidth=41
+cols=4 clientWidth=49
+cols=5 clientWidth=57
+cols=10 clientWidth=97
+cols=20 clientWidth=177
+cols=50 clientWidth=417
+cols=100 clientWidth=817
+cols=500 clientWidth=4017
+cols=1000 clientWidth=8017
 
 Times New Roman
 input
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/table/backgr_border-table-cell-collapsed-border-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/table/backgr_border-table-cell-collapsed-border-expected.png
index bd40c47..621c1215 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/table/backgr_border-table-cell-collapsed-border-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/table/backgr_border-table-cell-collapsed-border-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/table/backgr_border-table-column-group-collapsed-border-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/table/backgr_border-table-column-group-collapsed-border-expected.png
index 8fad905..a52248a 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/table/backgr_border-table-column-group-collapsed-border-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/table/backgr_border-table-column-group-collapsed-border-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/text/chromium-linux-fontconfig-renderstyle-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/text/chromium-linux-fontconfig-renderstyle-expected.png
index ff7cf59c..4efc9b5 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/text/chromium-linux-fontconfig-renderstyle-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/text/chromium-linux-fontconfig-renderstyle-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/svg/text-rescale-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/svg/text-rescale-expected.txt
index 970512f..d397a39 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/svg/text-rescale-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/svg/text-rescale-expected.txt
@@ -19,12 +19,12 @@
       "paintInvalidations": [
         {
           "object": "InlineTextBox 'PASS '",
-          "rect": [0, 114, 301, 46],
+          "rect": [0, 114, 192, 46],
           "reason": "appeared"
         },
         {
           "object": "LayoutSVGRoot (positioned) svg",
-          "rect": [0, 14, 301, 46],
+          "rect": [0, 14, 192, 46],
           "reason": "appeared"
         },
         {
@@ -38,8 +38,18 @@
           "reason": "appeared"
         },
         {
+          "object": "LayoutSVGForeignObject foreignObject",
+          "rect": [210, 114, 91, 46],
+          "reason": "paint property change"
+        },
+        {
+          "object": "LayoutSVGForeignObject foreignObject",
+          "rect": [210, 14, 91, 46],
+          "reason": "paint property change"
+        },
+        {
           "object": "LayoutSVGContainer g id='text3g'",
-          "rect": [0, 3, 10, 3],
+          "rect": [0, 3, 8, 3],
           "reason": "disappeared"
         },
         {
@@ -48,9 +58,14 @@
           "reason": "paint property change"
         },
         {
-          "object": "LayoutSVGContainer g id='text1g'",
+          "object": "LayoutSVGForeignObject foreignObject",
+          "rect": [6, 3, 4, 2],
+          "reason": "paint property change"
+        },
+        {
+          "object": "LayoutSVGForeignObject foreignObject",
           "rect": [0, 0, 1, 1],
-          "reason": "disappeared"
+          "reason": "paint property change"
         }
       ]
     }
diff --git a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/svg/zoom-foreignObject-expected.png b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/svg/zoom-foreignObject-expected.png
index d17fdcd..f78a118 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/svg/zoom-foreignObject-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/svg/zoom-foreignObject-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/animate-elem-82-t-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/animate-elem-82-t-expected.png
index 4731e39..28cc24a9 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/animate-elem-82-t-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/animate-elem-82-t-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/text-fonts-01-t-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/text-fonts-01-t-expected.png
index de833fda..4dbf01c 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/text-fonts-01-t-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/text-fonts-01-t-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/text-fonts-01-t-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/text-fonts-01-t-expected.txt
index 925b71b2..3f864df 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/text-fonts-01-t-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/text-fonts-01-t-expected.txt
@@ -4,8 +4,8 @@
   LayoutSVGRoot {svg} at (0,0) size 800x600
     LayoutSVGContainer {g} at (19.39,28.39) size 313.41x267.59
       LayoutSVGContainer {g} at (19.39,28.39) size 313.41x267.59
-        LayoutSVGText {text} at (19.39,57.80) size 196.19x27.59 contains 1 chunk(s)
-          LayoutSVGInlineText {#text} at (19.39,57.80) size 196.19x27.59
+        LayoutSVGText {text} at (19.39,57.80) size 196.19x30 contains 1 chunk(s)
+          LayoutSVGInlineText {#text} at (19.39,57.80) size 196.19x30
             chunk 1 text run 1 at (20.00,80.00) startOffset 0 endOffset 17 width 195.60: "A serifed face \x{753B}\x{50CF}"
         LayoutSVGText {text} at (19.39,138.39) size 232.80x27 contains 1 chunk(s)
           LayoutSVGInlineText {#text} at (19.39,138.39) size 232.80x27
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/text-fonts-02-t-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/text-fonts-02-t-expected.png
index 8153ebfd..ba37ee4 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/text-fonts-02-t-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/text-fonts-02-t-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/text-fonts-02-t-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/text-fonts-02-t-expected.txt
index ebc67c0..5b83253 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/text-fonts-02-t-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/text-fonts-02-t-expected.txt
@@ -2,47 +2,47 @@
   LayoutView at (0,0) size 800x600
 layer at (0,0) size 800x600
   LayoutSVGRoot {svg} at (0,0) size 800x600
-    LayoutSVGContainer {g} at (60,22.39) size 362.39x314.80
-      LayoutSVGText {text} at (360,22.39) size 49.80x34.80 contains 1 chunk(s)
-        LayoutSVGInlineText {#text} at (360,22.39) size 49.80x34.80
+    LayoutSVGContainer {g} at (60,22.39) size 362.39x317.19
+      LayoutSVGText {text} at (360,22.39) size 49.80x37.19 contains 1 chunk(s)
+        LayoutSVGInlineText {#text} at (360,22.39) size 49.80x37.19
           chunk 1 text run 1 at (360.00,50.00) startOffset 0 endOffset 3 width 49.80: "100"
-      LayoutSVGText {text} at (360,57.39) size 54x34.80 contains 1 chunk(s)
-        LayoutSVGInlineText {#text} at (360,57.39) size 54x34.80
+      LayoutSVGText {text} at (360,57.39) size 54x37.19 contains 1 chunk(s)
+        LayoutSVGInlineText {#text} at (360,57.39) size 54x37.19
           chunk 1 text run 1 at (360.00,85.00) startOffset 0 endOffset 3 width 54.00: "200"
-      LayoutSVGText {text} at (360,92.39) size 54x34.80 contains 1 chunk(s)
-        LayoutSVGInlineText {#text} at (360,92.39) size 54x34.80
+      LayoutSVGText {text} at (360,92.39) size 54x37.19 contains 1 chunk(s)
+        LayoutSVGInlineText {#text} at (360,92.39) size 54x37.19
           chunk 1 text run 1 at (360.00,120.00) startOffset 0 endOffset 3 width 54.00: "300"
-      LayoutSVGText {text} at (360,127.39) size 54x34.80 contains 1 chunk(s)
-        LayoutSVGInlineText {#text} at (360,127.39) size 54x34.80
+      LayoutSVGText {text} at (360,127.39) size 54x37.19 contains 1 chunk(s)
+        LayoutSVGInlineText {#text} at (360,127.39) size 54x37.19
           chunk 1 text run 1 at (360.00,155.00) startOffset 0 endOffset 3 width 54.00: "400"
-      LayoutSVGText {text} at (360,162.39) size 52.80x34.80 contains 1 chunk(s)
-        LayoutSVGInlineText {#text} at (360,162.39) size 52.80x34.80
+      LayoutSVGText {text} at (360,162.39) size 52.80x37.19 contains 1 chunk(s)
+        LayoutSVGInlineText {#text} at (360,162.39) size 52.80x37.19
           chunk 1 text run 1 at (360.00,190.00) startOffset 0 endOffset 3 width 52.80: "500"
-      LayoutSVGText {text} at (360,197.39) size 61.19x34.80 contains 1 chunk(s)
-        LayoutSVGInlineText {#text} at (360,197.39) size 61.19x34.80
+      LayoutSVGText {text} at (360,197.39) size 61.19x37.19 contains 1 chunk(s)
+        LayoutSVGInlineText {#text} at (360,197.39) size 61.19x37.19
           chunk 1 text run 1 at (360.00,225.00) startOffset 0 endOffset 3 width 61.20: "600"
-      LayoutSVGText {text} at (360,232.39) size 58.80x34.80 contains 1 chunk(s)
-        LayoutSVGInlineText {#text} at (360,232.39) size 58.80x34.80
+      LayoutSVGText {text} at (360,232.39) size 58.80x37.19 contains 1 chunk(s)
+        LayoutSVGInlineText {#text} at (360,232.39) size 58.80x37.19
           chunk 1 text run 1 at (360.00,260.00) startOffset 0 endOffset 3 width 58.80: "700"
-      LayoutSVGText {text} at (360,267.39) size 62.39x34.80 contains 1 chunk(s)
-        LayoutSVGInlineText {#text} at (360,267.39) size 62.39x34.80
+      LayoutSVGText {text} at (360,267.39) size 62.39x37.19 contains 1 chunk(s)
+        LayoutSVGInlineText {#text} at (360,267.39) size 62.39x37.19
           chunk 1 text run 1 at (360.00,295.00) startOffset 0 endOffset 3 width 62.40: "800"
-      LayoutSVGText {text} at (360,302.39) size 61.19x34.80 contains 1 chunk(s)
-        LayoutSVGInlineText {#text} at (360,302.39) size 61.19x34.80
+      LayoutSVGText {text} at (360,302.39) size 61.19x37.19 contains 1 chunk(s)
+        LayoutSVGInlineText {#text} at (360,302.39) size 61.19x37.19
           chunk 1 text run 1 at (360.00,330.00) startOffset 0 endOffset 3 width 61.20: "900"
-      LayoutSVGText {text} at (60,52.39) size 177.59x34.80 contains 1 chunk(s)
-        LayoutSVGInlineText {#text} at (60,52.39) size 177.59x34.80
+      LayoutSVGText {text} at (60,52.39) size 177.59x37.19 contains 1 chunk(s)
+        LayoutSVGInlineText {#text} at (60,52.39) size 177.59x37.19
           chunk 1 text run 1 at (60.00,80.00) startOffset 0 endOffset 12 width 177.60: "This is bold"
-      LayoutSVGText {text} at (60,102.39) size 190.80x34.80 contains 1 chunk(s)
-        LayoutSVGInlineText {#text} at (60,102.39) size 190.80x34.80
+      LayoutSVGText {text} at (60,102.39) size 190.80x37.19 contains 1 chunk(s)
+        LayoutSVGInlineText {#text} at (60,102.39) size 190.80x37.19
           chunk 1 text run 1 at (60.00,130.00) startOffset 0 endOffset 14 width 190.80: "This is normal"
-      LayoutSVGContainer {g} at (60,152.39) size 214.19x34.80
-        LayoutSVGText {text} at (60,152.39) size 214.19x34.80 contains 1 chunk(s)
-          LayoutSVGInlineText {#text} at (60,152.39) size 214.19x34.80
+      LayoutSVGContainer {g} at (60,152.39) size 214.19x37.19
+        LayoutSVGText {text} at (60,152.39) size 214.19x37.19 contains 1 chunk(s)
+          LayoutSVGInlineText {#text} at (60,152.39) size 214.19x37.19
             chunk 1 text run 1 at (60.00,180.00) startOffset 0 endOffset 14 width 214.20: "Blue is bolder"
-      LayoutSVGContainer {g} at (60,202.39) size 183.59x34.80
-        LayoutSVGText {text} at (60,202.39) size 183.59x34.80 contains 1 chunk(s)
-          LayoutSVGInlineText {#text} at (60,202.39) size 183.59x34.80
+      LayoutSVGContainer {g} at (60,202.39) size 183x37.19
+        LayoutSVGText {text} at (60,202.39) size 183x37.19 contains 1 chunk(s)
+          LayoutSVGInlineText {#text} at (60,202.39) size 183x37.19
             chunk 1 text run 1 at (60.00,230.00) startOffset 0 endOffset 15 width 183.00: "Blue is lighter"
     LayoutSVGText {text} at (10,304) size 268.19x45.59 contains 1 chunk(s)
       LayoutSVGInlineText {#text} at (10,304) size 268.19x45.59
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/text-path-01-b-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/text-path-01-b-expected.png
index f4fca86..5ebc48a 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/text-path-01-b-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/text-path-01-b-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/text-path-01-b-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/text-path-01-b-expected.txt
index 8b56fad..f18a462 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/text-path-01-b-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/text-path-01-b-expected.txt
@@ -2,17 +2,17 @@
   LayoutView at (0,0) size 800x600
 layer at (0,0) size 800x600
   LayoutSVGRoot {svg} at (0,0) size 800x600
-    LayoutSVGContainer {g} at (-8.64,-6.94) size 426.64x298.13
+    LayoutSVGContainer {g} at (-8.09,-6.33) size 426.09x297.52
       LayoutSVGHiddenContainer {defs} at (33.50,26.98) size 384.50x206.02
         LayoutSVGPath {path} at (199,26.98) size 219x78.02 [stroke={[type=SOLID] [color=#0000FF]}] [data="M 199 89.3 C 206.6 66.6 235.8 13.2 270 30.3 C 286.6 38.6 298.9 59.4 310 73.3 C 321.7 87.9 338.6 99 356 103.3 C 387.3 111.1 396.6 90.4 418 74.3"]
         LayoutSVGPath {path} at (33.50,83.48) size 219x78.02 [stroke={[type=SOLID] [color=#0000FF]}] [data="M 33.5 145.8 C 41 123 70.3 69.7 104.5 86.8 C 121 95 133 116 144.5 129.8 C 156.2 144.4 173 155.5 190.5 159.8 C 221.8 167.6 231 146.9 252.5 130.8"]
         LayoutSVGPath {path} at (113,233) size 300x0 [stroke={[type=SOLID] [color=#0000FF] [stroke width=4.00]}] [data="M 113 233 L 413 233"]
-      LayoutSVGContainer {g} at (167.86,-6.94) size 250.14x119.86
+      LayoutSVGContainer {g} at (168.41,-6.33) size 249.59x123.30
         LayoutSVGContainer {use} at (199,26.98) size 219x78.02
           LayoutSVGPath {path} at (199,26.98) size 219x78.02 [stroke={[type=SOLID] [color=#0000FF]}] [data="M 199 89.3 C 206.6 66.6 235.8 13.2 270 30.3 C 286.6 38.6 298.9 59.4 310 73.3 C 321.7 87.9 338.6 99 356 103.3 C 387.3 111.1 396.6 90.4 418 74.3"]
-        LayoutSVGText {text} at (167.86,-6.94) size 204.66x119.86 contains 1 chunk(s)
-          LayoutSVGTextPath {textPath} at (167.86,-6.94) size 204.66x119.86
-            LayoutSVGInlineText {#text} at (167.86,-6.94) size 204.66x119.86
+        LayoutSVGText {text} at (168.41,-6.33) size 203.94x123.30 contains 1 chunk(s)
+          LayoutSVGTextPath {textPath} at (168.41,-6.33) size 203.94x123.30
+            LayoutSVGInlineText {#text} at (168.41,-6.33) size 203.94x123.30
               chunk 1 text run 1 at (203.06,79.02) startOffset 0 endOffset 1 width 22.20: "T"
               chunk 1 text run 2 at (212.29,61.56) startOffset 1 endOffset 2 width 17.40: "e"
               chunk 1 text run 3 at (222.63,47.07) startOffset 2 endOffset 3 width 18.00: "x"
@@ -28,19 +28,19 @@
               chunk 1 text run 13 at (337.49,96.10) startOffset 12 endOffset 13 width 12.60: "t"
               chunk 1 text run 14 at (353.02,102.49) startOffset 13 endOffset 14 width 21.00: "h"
           LayoutSVGInlineText {#text} at (0,0) size 0x0
-      LayoutSVGContainer {g} at (-8.64,49.55) size 299.64x161.64
+      LayoutSVGContainer {g} at (-8.09,50.14) size 299.09x161.05
         LayoutSVGContainer {use} at (33.50,83.48) size 219x78.02
           LayoutSVGPath {path} at (33.50,83.48) size 219x78.02 [stroke={[type=SOLID] [color=#0000FF]}] [data="M 33.5 145.8 C 41 123 70.3 69.7 104.5 86.8 C 121 95 133 116 144.5 129.8 C 156.2 144.4 173 155.5 190.5 159.8 C 221.8 167.6 231 146.9 252.5 130.8"]
-        LayoutSVGText {text} at (-8.64,49.55) size 215.61x119.86 contains 1 chunk(s)
-          LayoutSVGTextPath {textPath} at (-8.64,49.55) size 215.61x119.86
-            LayoutSVGTSpan {tspan} at (-8.64,49.55) size 215.61x119.86
-              LayoutSVGInlineText {#text} at (-8.64,86.73) size 56.34x57.19
+        LayoutSVGText {text} at (-8.09,50.14) size 214.89x123.28 contains 1 chunk(s)
+          LayoutSVGTextPath {textPath} at (-8.09,50.14) size 214.89x123.28
+            LayoutSVGTSpan {tspan} at (-8.09,50.14) size 214.89x123.28
+              LayoutSVGInlineText {#text} at (-8.09,87.05) size 59.38x58.58
                 chunk 1 text run 1 at (37.53,135.50) startOffset 0 endOffset 1 width 22.20: "T"
                 chunk 1 text run 2 at (46.73,118.03) startOffset 1 endOffset 2 width 17.40: "e"
-            LayoutSVGTSpan {tspan} at (-8.64,49.55) size 215.61x119.86
-              LayoutSVGInlineText {#text} at (25.55,75.03) size 43.27x40.39
+            LayoutSVGTSpan {tspan} at (-8.09,50.14) size 214.89x123.28
+              LayoutSVGInlineText {#text} at (26.02,74.97) size 46.42x43.17
                 chunk 1 text run 1 at (57.08,103.54) startOffset 0 endOffset 1 width 18.00: "x"
-            LayoutSVGInlineText {#text} at (42.03,49.55) size 164.92x119.86
+            LayoutSVGInlineText {#text} at (42.41,50.14) size 164.38x123.28
               chunk 1 text run 1 at (67.95,92.75) startOffset 0 endOffset 1 width 12.60: "t"
               chunk 1 text run 2 at (76.74,87.05) startOffset 1 endOffset 2 width 8.40: " "
               chunk 1 text run 3 at (89.94,83.50) startOffset 2 endOffset 3 width 19.20: "o"
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/as-background-image/svg-as-background-5-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/as-background-image/svg-as-background-5-expected.png
index 0cce6be..476671ea 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/as-background-image/svg-as-background-5-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/as-background-image/svg-as-background-5-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/custom/dominant-baseline-hanging-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/svg/custom/dominant-baseline-hanging-expected.txt
index 0ab20b8..807382a2 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/custom/dominant-baseline-hanging-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/custom/dominant-baseline-hanging-expected.txt
@@ -54,3 +54,43 @@
                 text run at (0,0) width 91: "Antoine Quint"
             LayoutText {#text} at (91,0) size 89x19
               text run at (91,0) width 89: ", January 27th"
+layer at (10,45) size 380x150 scrollHeight 168
+  LayoutSVGForeignObject {foreignObject} at (10,45) size 380x150
+    LayoutBlockFlow {html} at (0,16) size 380x136
+      LayoutBlockFlow {body} at (8,0) size 364x136
+        LayoutBlockFlow {p} at (0,0) size 364x100
+          LayoutText {#text} at (0,0) size 347x39
+            text run at (0,0) width 347: "The piece of text above should be aligned with the top-"
+            text run at (0,20) width 286: "left corner of the rectangle below it. Both the "
+          LayoutInline {code} at (0,0) size 48x16
+            LayoutText {#text} at (286,23) size 48x16
+              text run at (286,23) width 48: "<text>"
+          LayoutText {#text} at (334,20) size 361x39
+            text run at (334,20) width 27: " and"
+            text run at (0,40) width 23: "the "
+          LayoutInline {code} at (0,0) size 48x16
+            LayoutText {#text} at (23,43) size 48x16
+              text run at (23,43) width 48: "<rect>"
+          LayoutText {#text} at (71,40) size 272x19
+            text run at (71,40) width 272: " are located at the same coordinates and the"
+          LayoutInline {code} at (0,0) size 48x16
+            LayoutText {#text} at (0,63) size 48x16
+              text run at (0,63) width 48: "<text>"
+          LayoutText {#text} at (48,60) size 111x19
+            text run at (48,60) width 111: " element uses the "
+          LayoutInline {code} at (0,0) size 56x16
+            LayoutText {#text} at (159,63) size 56x16
+              text run at (159,63) width 56: "hanging"
+          LayoutText {#text} at (215,60) size 78x19
+            text run at (215,60) width 78: " value for its"
+          LayoutInline {code} at (0,0) size 136x16
+            LayoutText {#text} at (0,83) size 136x16
+              text run at (0,83) width 136: "dominant-baseline"
+          LayoutText {#text} at (136,80) size 59x19
+            text run at (136,80) width 59: " attribute."
+        LayoutBlockFlow {p} at (0,116) size 364x20
+          LayoutInline {a} at (0,0) size 91x19 [color=#800000]
+            LayoutText {#text} at (0,0) size 91x19
+              text run at (0,0) width 91: "Antoine Quint"
+          LayoutText {#text} at (91,0) size 89x19
+            text run at (91,0) width 89: ", January 27th"
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/custom/foreign-object-skew-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/svg/custom/foreign-object-skew-expected.txt
index dbb43c87..4fcdb10b 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/custom/foreign-object-skew-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/custom/foreign-object-skew-expected.txt
@@ -14,3 +14,15 @@
         LayoutButton {xhtml:input} at (0,20) size 16x22 [bgcolor=#C0C0C0] [border: (2px outset #C0C0C0)]
         LayoutText {#text} at (0,0) size 0x0
     LayoutSVGRect {rect} at (10,10) size 580x380 [stroke={[type=SOLID] [color=#008000]}] [x=10.00] [y=10.00] [width=580.00] [height=380.00]
+layer at (10,10) size 580x380 backgroundClip at (54,55) size 746x545 clip at (54,55) size 536x335
+  LayoutSVGForeignObject {foreignObject} at (10,10) size 580x380
+    LayoutBlockFlow {xhtml:div} at (0,0) size 580x20
+      LayoutText {#text} at (0,0) size 78x19
+        text run at (0,0) width 78: "This is a test"
+    LayoutBlockFlow (anonymous) at (0,20) size 580x44
+      LayoutInline {xhtml:a} at (0,0) size 66x19 [color=#0000EE]
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "and a link."
+      LayoutBR {xhtml:br} at (66,0) size 0x19
+      LayoutButton {xhtml:input} at (0,20) size 16x22 [bgcolor=#C0C0C0] [border: (2px outset #C0C0C0)]
+      LayoutText {#text} at (0,0) size 0x0
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/custom/use-on-disallowed-foreign-object-1-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/svg/custom/use-on-disallowed-foreign-object-1-expected.txt
index ecb4d4e6..18440fa 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/custom/use-on-disallowed-foreign-object-1-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/custom/use-on-disallowed-foreign-object-1-expected.txt
@@ -7,3 +7,8 @@
         LayoutText {#text} at (0,0) size 242x19
           text run at (0,0) width 242: "You should only see this string ONCE"
     LayoutSVGContainer {use} at (0,0) size 0x0 [transform={m=((0.71,0.71)(-0.71,0.71)) t=(250.00,-35.86)}]
+layer at (10,10) size 480x360 backgroundClip at (54,55) size 746x545 clip at (54,55) size 436x315
+  LayoutSVGForeignObject {foreignObject} at (10,10) size 480x360
+    LayoutBlockFlow {xhtml:div} at (0,0) size 480x20
+      LayoutText {#text} at (0,0) size 242x19
+        text run at (0,0) width 242: "You should only see this string ONCE"
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/custom/use-on-disallowed-foreign-object-2-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/svg/custom/use-on-disallowed-foreign-object-2-expected.txt
index 857e1e8..b108752 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/custom/use-on-disallowed-foreign-object-2-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/custom/use-on-disallowed-foreign-object-2-expected.txt
@@ -11,3 +11,8 @@
     LayoutSVGContainer {use} at (0,0) size 0x0 [transform={m=((0.71,0.71)(-0.71,0.71)) t=(250.00,-35.86)}]
       LayoutSVGContainer {g} at (0,0) size 0x0
         LayoutSVGContainer {g} at (0,0) size 0x0
+layer at (10,10) size 580x380 backgroundClip at (54,55) size 746x545 clip at (54,55) size 536x335
+  LayoutSVGForeignObject {foreignObject} at (10,10) size 580x380
+    LayoutBlockFlow {xhtml:div} at (0,0) size 580x20
+      LayoutText {#text} at (0,0) size 242x19
+        text run at (0,0) width 242: "You should only see this string ONCE"
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/custom/use-on-disallowed-foreign-object-3-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/svg/custom/use-on-disallowed-foreign-object-3-expected.txt
index ffec4451..afca863 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/custom/use-on-disallowed-foreign-object-3-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/custom/use-on-disallowed-foreign-object-3-expected.txt
@@ -8,3 +8,8 @@
           text run at (0,0) width 242: "You should only see this string ONCE"
     LayoutSVGContainer {use} at (0,0) size 0x0 [transform={m=((0.71,0.71)(-0.71,0.71)) t=(250.00,-35.86)}]
     LayoutSVGContainer {use} at (0,0) size 0x0 [transform={m=((0.71,0.71)(-0.71,0.71)) t=(250.00,-35.86)}]
+layer at (10,10) size 580x380 backgroundClip at (54,55) size 746x545 clip at (54,55) size 536x335
+  LayoutSVGForeignObject {foreignObject} at (10,10) size 580x380
+    LayoutBlockFlow {xhtml:div} at (0,0) size 580x20
+      LayoutText {#text} at (0,0) size 242x19
+        text run at (0,0) width 242: "You should only see this string ONCE"
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/custom/use-on-disallowed-foreign-object-4-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/svg/custom/use-on-disallowed-foreign-object-4-expected.txt
index 5c90719..013505c 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/custom/use-on-disallowed-foreign-object-4-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/custom/use-on-disallowed-foreign-object-4-expected.txt
@@ -15,3 +15,8 @@
       LayoutSVGContainer {g} at (0,0) size 0x0 [transform={m=((0.71,0.71)(-0.71,0.71)) t=(250.00,-35.86)}]
         LayoutSVGContainer {g} at (0,0) size 0x0
           LayoutSVGContainer {g} at (0,0) size 0x0
+layer at (10,10) size 580x380 backgroundClip at (54,55) size 746x545 clip at (54,55) size 536x335
+  LayoutSVGForeignObject {foreignObject} at (10,10) size 580x380
+    LayoutBlockFlow {xhtml:div} at (0,0) size 580x20
+      LayoutText {#text} at (0,0) size 242x19
+        text run at (0,0) width 242: "You should only see this string ONCE"
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/custom/use-on-disallowed-foreign-object-5-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/svg/custom/use-on-disallowed-foreign-object-5-expected.txt
index f2a7c47..7f6b95e 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/custom/use-on-disallowed-foreign-object-5-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/custom/use-on-disallowed-foreign-object-5-expected.txt
@@ -13,3 +13,8 @@
     LayoutSVGContainer {use} at (0,0) size 0x0 [transform={m=((1.00,0.00)(0.00,1.00)) t=(10.00,10.00)}]
       LayoutSVGContainer {g} at (0,0) size 0x0 [transform={m=((1.00,0.00)(0.00,1.00)) t=(25.00,25.00)}]
         LayoutSVGViewportContainer {svg} at (0,0) size 0x0
+layer at (10,10) size 580x380 backgroundClip at (54,55) size 746x545 clip at (54,55) size 536x335
+  LayoutSVGForeignObject {foreignObject} at (10,10) size 580x380
+    LayoutBlockFlow {xhtml:div} at (0,0) size 580x20
+      LayoutText {#text} at (0,0) size 242x19
+        text run at (0,0) width 242: "You should only see this string ONCE"
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/custom/use-on-disallowed-foreign-object-6-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/svg/custom/use-on-disallowed-foreign-object-6-expected.txt
index c475ba0..9c303f64 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/custom/use-on-disallowed-foreign-object-6-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/custom/use-on-disallowed-foreign-object-6-expected.txt
@@ -13,3 +13,8 @@
     LayoutSVGContainer {use} at (0,0) size 0x0 [transform={m=((1.00,0.00)(0.00,1.00)) t=(10.00,10.00)}]
       LayoutSVGContainer {g} at (0,0) size 0x0 [transform={m=((1.00,0.00)(0.00,1.00)) t=(25.00,25.00)}]
         LayoutSVGViewportContainer {svg} at (0,0) size 0x0
+layer at (10,10) size 580x380 backgroundClip at (54,55) size 746x545 clip at (54,55) size 536x335
+  LayoutSVGForeignObject {foreignObject} at (10,10) size 580x380
+    LayoutBlockFlow {xhtml:div} at (0,0) size 580x20
+      LayoutText {#text} at (0,0) size 242x19
+        text run at (0,0) width 242: "You should only see this string ONCE"
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/custom/use-on-non-svg-namespaced-element-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/svg/custom/use-on-non-svg-namespaced-element-expected.txt
index ecb4d4e6..18440fa 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/custom/use-on-non-svg-namespaced-element-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/custom/use-on-non-svg-namespaced-element-expected.txt
@@ -7,3 +7,8 @@
         LayoutText {#text} at (0,0) size 242x19
           text run at (0,0) width 242: "You should only see this string ONCE"
     LayoutSVGContainer {use} at (0,0) size 0x0 [transform={m=((0.71,0.71)(-0.71,0.71)) t=(250.00,-35.86)}]
+layer at (10,10) size 480x360 backgroundClip at (54,55) size 746x545 clip at (54,55) size 436x315
+  LayoutSVGForeignObject {foreignObject} at (10,10) size 480x360
+    LayoutBlockFlow {xhtml:div} at (0,0) size 480x20
+      LayoutText {#text} at (0,0) size 242x19
+        text run at (0,0) width 242: "You should only see this string ONCE"
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/foreignObject/no-crash-with-svg-content-in-html-document-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/svg/foreignObject/no-crash-with-svg-content-in-html-document-expected.txt
index a8164c85..ffd038e 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/foreignObject/no-crash-with-svg-content-in-html-document-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/foreignObject/no-crash-with-svg-content-in-html-document-expected.txt
@@ -10,3 +10,12 @@
         LayoutBlockFlow (anonymous) at (0,20) size 300x0
           LayoutInline {g} at (0,0) size 0x0
           LayoutText {#text} at (0,0) size 0x0
+layer at (0,0) size 300x100
+  LayoutSVGForeignObject {foreignObject} at (0,0) size 300x100
+    LayoutBlockFlow {html} at (0,0) size 300x20
+      LayoutBlockFlow {p} at (0,0) size 300x20
+        LayoutText {#text} at (0,0) size 135x19
+          text run at (0,0) width 135: "This should not crash"
+      LayoutBlockFlow (anonymous) at (0,20) size 300x0
+        LayoutInline {g} at (0,0) size 0x0
+        LayoutText {#text} at (0,0) size 0x0
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/foreignObject/svg-document-as-direct-child-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/svg/foreignObject/svg-document-as-direct-child-expected.txt
index 4b49a306..3f40fdf 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/foreignObject/svg-document-as-direct-child-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/foreignObject/svg-document-as-direct-child-expected.txt
@@ -17,3 +17,21 @@
       LayoutSVGRoot {svg} at (0,0) size 300x150
         LayoutSVGRect {rect} at (0,0) size 100x100 [fill={[type=SOLID] [color=#008000]}] [x=0.00] [y=0.00] [width=100.00] [height=100.00]
       LayoutText {#text} at (0,0) size 0x0
+layer at (0,0) size 300x100 scrollHeight 155
+  LayoutSVGForeignObject {foreignObject} at (0,0) size 300x100
+    LayoutSVGRoot {svg} at (0,0) size 300x150
+      LayoutSVGContainer {g} at (0,5) size 33x19
+        LayoutSVGText {text} at (0,5) size 33x19 contains 1 chunk(s)
+          LayoutSVGInlineText {#text} at (0,5) size 33x19
+            chunk 1 text run 1 at (0.00,20.00) startOffset 0 endOffset 5 width 33.00: "crash"
+    LayoutText {#text} at (0,0) size 0x0
+layer at (0,50) size 300x100 scrollHeight 155
+  LayoutSVGForeignObject {foreignObject} at (0,50) size 300x100
+    LayoutSVGRoot {svg} at (0,0) size 300x150
+      LayoutSVGRect {rect} at (0,0) size 100x100 [fill={[type=SOLID] [color=#008000]}] [x=0.00] [y=0.00] [width=100.00] [height=100.00]
+    LayoutText {#text} at (0,0) size 0x0
+layer at (0,150) size 300x100 scrollHeight 155
+  LayoutSVGForeignObject {foreignObject} at (0,150) size 300x100
+    LayoutSVGRoot {svg} at (0,0) size 300x150
+      LayoutSVGRect {rect} at (0,0) size 100x100 [fill={[type=SOLID] [color=#008000]}] [x=0.00] [y=0.00] [width=100.00] [height=100.00]
+    LayoutText {#text} at (0,0) size 0x0
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/foreignObject/svg-document-in-html-document-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/svg/foreignObject/svg-document-in-html-document-expected.txt
index 89e27551..5ced1a2 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/foreignObject/svg-document-in-html-document-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/foreignObject/svg-document-in-html-document-expected.txt
@@ -14,3 +14,16 @@
               LayoutSVGInlineText {#text} at (0,35) size 270x19
                 chunk 1 text run 1 at (0.00,50.00) startOffset 0 endOffset 38 width 269.00: "Test from SVG in HTML in foreignObject"
           LayoutText {#text} at (0,0) size 0x0
+layer at (0,0) size 300x100 scrollHeight 191
+  LayoutSVGForeignObject {foreignObject} at (0,0) size 300x100
+    LayoutBlockFlow {html} at (0,0) size 300x191
+      LayoutBlockFlow {p} at (0,0) size 300x20
+        LayoutText {#text} at (0,0) size 216x19
+          text run at (0,0) width 216: "Test from HTML in foreignObject"
+      LayoutBlockFlow (anonymous) at (0,36) size 300x155
+        LayoutSVGRoot {svg} at (0,0) size 300x150
+          LayoutSVGRect {rect} at (0,0) size 20x20 [fill={[type=SOLID] [color=#008000]}] [x=0.00] [y=0.00] [width=20.00] [height=20.00]
+          LayoutSVGText {text} at (0,35) size 270x19 contains 1 chunk(s)
+            LayoutSVGInlineText {#text} at (0,35) size 270x19
+              chunk 1 text run 1 at (0.00,50.00) startOffset 0 endOffset 38 width 269.00: "Test from SVG in HTML in foreignObject"
+        LayoutText {#text} at (0,0) size 0x0
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/hixie/mixed/005-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/svg/hixie/mixed/005-expected.txt
deleted file mode 100644
index 6892ace..0000000
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/hixie/mixed/005-expected.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-layer at (0,0) size 800x600
-  LayoutView at (0,0) size 800x600
-layer at (0,0) size 800x221
-  LayoutBlockFlow {html} at (0,0) size 800x221
-    LayoutBlockFlow {body} at (8,8) size 784x205
-      LayoutSVGRoot {svg} at (0,0) size 200x200
-        LayoutSVGEllipse {circle} at (0,0) size 100x100 [fill={[type=SOLID] [color=#FF0000]}] [cx=50.00] [cy=50.00] [r=50.00]
-        LayoutSVGEllipse {circle} at (0,0) size 100x100 [fill={[type=SOLID] [color=#008000]}] [cx=50.00] [cy=50.00] [r=50.00]
-      LayoutText {#text} at (0,0) size 0x0
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/hixie/mixed/006-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/svg/hixie/mixed/006-expected.txt
index ac1626a..fcfbbc04 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/hixie/mixed/006-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/hixie/mixed/006-expected.txt
@@ -12,6 +12,8 @@
     LayoutText {#text} at (0,0) size 199x39
       text run at (0,0) width 190: "There should be a green circle"
       text run at (0,20) width 199: "below with no red on this page."
+layer at (8,208) size 200x200
+  LayoutSVGForeignObject {foreignObject} at (0,0) size 200x200
 layer at (8,8) size 200x200 backgroundClip at (8,208) size 200x200 clip at (8,208) size 200x200
   LayoutBlockFlow (positioned) {div} at (0,-200) size 200x200 [color=#FFFF00] [bgcolor=#FF0000]
     LayoutText {#text} at (0,0) size 34x19
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/hixie/mixed/008-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/svg/hixie/mixed/008-expected.txt
index 1f09f139..92275d6c 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/hixie/mixed/008-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/hixie/mixed/008-expected.txt
@@ -15,3 +15,8 @@
               LayoutText {#text} at (139,1) size 122x57
                 text run at (139,1) width 122: "TEST"
         LayoutText {#text} at (0,0) size 0x0
+layer at (8,227) size 400x50 scrollHeight 59
+  LayoutSVGForeignObject {foreignObject} at (0,175) size 400x50 [color=#FFFFFF]
+    LayoutBlockFlow {div} at (0,0) size 400x59
+      LayoutText {#text} at (139,1) size 122x57
+        text run at (139,1) width 122: "TEST"
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/hixie/mixed/009-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/svg/hixie/mixed/009-expected.txt
index 2eea96b6..18afee5 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/hixie/mixed/009-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/hixie/mixed/009-expected.txt
@@ -17,3 +17,8 @@
       LayoutBlockFlow {div} at (0,145) size 400x120 [color=#000080] [bgcolor=#EEEEEE]
         LayoutText {#text} at (0,2) size 239x114
           text run at (0,2) width 239: "TEST"
+layer at (8,28) size 60x10 scrollHeight 12
+  LayoutSVGForeignObject {foreignObject} at (0,0) size 60x10
+    LayoutBlockFlow {div} at (0,0) size 60x12 [color=#000080]
+      LayoutText {#text} at (0,0) size 24x12
+        text run at (0,0) width 24: "TEST"
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/hixie/mixed/011-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/svg/hixie/mixed/011-expected.txt
index d2b5ef2..6cfbcfc 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/hixie/mixed/011-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/hixie/mixed/011-expected.txt
@@ -7,7 +7,9 @@
         LayoutSVGEllipse {circle} at (50,50) size 100x100 [fill={[type=SOLID] [color=#008000]}] [cx=100.00] [cy=100.00] [r=50.00]
         LayoutSVGForeignObject {foreignObject} at (0,0) size 200x200
       LayoutText {#text} at (0,0) size 0x0
-layer at (50,0) size 150x200 backgroundClip at (0,8) size 149x283 clip at (0,8) size 149x283
+layer at (8,8) size 200x200 backgroundClip at (0,8) size 149x283 clip at (8,8) size 141x200
+  LayoutSVGForeignObject {foreignObject} at (0,0) size 200x200
+layer at (58,8) size 150x200 backgroundClip at (0,8) size 149x283 clip at (0,8) size 149x283
   LayoutBlockFlow (positioned) {div} at (50,0) size 150x200
     LayoutText {#text} at (0,0) size 135x79
       text run at (0,0) width 113: "There should be a"
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/hixie/perf/007-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/hixie/perf/007-expected.png
index 42a5e1c7..7216f3e 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/hixie/perf/007-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/hixie/perf/007-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/overflow/overflow-on-outermost-svg-element-in-xhtml-auto-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/svg/overflow/overflow-on-outermost-svg-element-in-xhtml-auto-expected.txt
deleted file mode 100644
index e4fb01e0..0000000
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/overflow/overflow-on-outermost-svg-element-in-xhtml-auto-expected.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-layer at (0,0) size 800x600
-  LayoutView at (0,0) size 800x600
-layer at (0,0) size 800x405
-  LayoutBlockFlow {html} at (0,0) size 800x405
-    LayoutInline {body} at (0,0) size 400x19
-      LayoutText {#text} at (0,0) size 0x0
-      LayoutSVGRoot {svg} at (0,0) size 400x400
-        LayoutSVGRect {rect} at (0,0) size 4000x4000 [fill={[type=SOLID] [color=#008000]}] [x=0.00] [y=0.00] [width=4000.00] [height=4000.00]
-      LayoutText {#text} at (0,0) size 0x0
-    LayoutText {#text} at (0,0) size 0x0
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/overflow/overflow-on-outermost-svg-element-in-xhtml-defaults-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/svg/overflow/overflow-on-outermost-svg-element-in-xhtml-defaults-expected.txt
deleted file mode 100644
index 41b0e180..0000000
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/overflow/overflow-on-outermost-svg-element-in-xhtml-defaults-expected.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-layer at (0,0) size 800x600 clip at (0,0) size 785x585 scrollWidth 800 scrollHeight 605
-  LayoutView at (0,0) size 800x600
-layer at (0,0) size 785x605 backgroundClip at (0,0) size 785x585 clip at (0,0) size 785x585
-  LayoutBlockFlow {html} at (0,0) size 785x605
-    LayoutInline {body} at (0,0) size 800x19
-      LayoutText {#text} at (0,0) size 0x0
-      LayoutSVGRoot {svg} at (0,0) size 800x600
-        LayoutSVGRect {rect} at (0,0) size 4000x4000 [fill={[type=SOLID] [color=#008000]}] [x=0.00] [y=0.00] [width=4000.00] [height=4000.00]
-      LayoutText {#text} at (0,0) size 0x0
-    LayoutText {#text} at (0,0) size 0x0
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/overflow/overflow-on-outermost-svg-element-in-xhtml-hidden-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/svg/overflow/overflow-on-outermost-svg-element-in-xhtml-hidden-expected.txt
deleted file mode 100644
index e4fb01e0..0000000
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/overflow/overflow-on-outermost-svg-element-in-xhtml-hidden-expected.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-layer at (0,0) size 800x600
-  LayoutView at (0,0) size 800x600
-layer at (0,0) size 800x405
-  LayoutBlockFlow {html} at (0,0) size 800x405
-    LayoutInline {body} at (0,0) size 400x19
-      LayoutText {#text} at (0,0) size 0x0
-      LayoutSVGRoot {svg} at (0,0) size 400x400
-        LayoutSVGRect {rect} at (0,0) size 4000x4000 [fill={[type=SOLID] [color=#008000]}] [x=0.00] [y=0.00] [width=4000.00] [height=4000.00]
-      LayoutText {#text} at (0,0) size 0x0
-    LayoutText {#text} at (0,0) size 0x0
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/overflow/overflow-on-outermost-svg-element-in-xhtml-scroll-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/svg/overflow/overflow-on-outermost-svg-element-in-xhtml-scroll-expected.txt
deleted file mode 100644
index e4fb01e0..0000000
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/overflow/overflow-on-outermost-svg-element-in-xhtml-scroll-expected.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-layer at (0,0) size 800x600
-  LayoutView at (0,0) size 800x600
-layer at (0,0) size 800x405
-  LayoutBlockFlow {html} at (0,0) size 800x405
-    LayoutInline {body} at (0,0) size 400x19
-      LayoutText {#text} at (0,0) size 0x0
-      LayoutSVGRoot {svg} at (0,0) size 400x400
-        LayoutSVGRect {rect} at (0,0) size 4000x4000 [fill={[type=SOLID] [color=#008000]}] [x=0.00] [y=0.00] [width=4000.00] [height=4000.00]
-      LayoutText {#text} at (0,0) size 0x0
-    LayoutText {#text} at (0,0) size 0x0
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/overflow/overflow-on-outermost-svg-element-in-xhtml-visible-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/svg/overflow/overflow-on-outermost-svg-element-in-xhtml-visible-expected.txt
deleted file mode 100644
index e4fb01e0..0000000
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/overflow/overflow-on-outermost-svg-element-in-xhtml-visible-expected.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-layer at (0,0) size 800x600
-  LayoutView at (0,0) size 800x600
-layer at (0,0) size 800x405
-  LayoutBlockFlow {html} at (0,0) size 800x405
-    LayoutInline {body} at (0,0) size 400x19
-      LayoutText {#text} at (0,0) size 0x0
-      LayoutSVGRoot {svg} at (0,0) size 400x400
-        LayoutSVGRect {rect} at (0,0) size 4000x4000 [fill={[type=SOLID] [color=#008000]}] [x=0.00] [y=0.00] [width=4000.00] [height=4000.00]
-      LayoutText {#text} at (0,0) size 0x0
-    LayoutText {#text} at (0,0) size 0x0
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/text/foreignObject-repaint-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/svg/text/foreignObject-repaint-expected.txt
index f8d11fc..860651a 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/text/foreignObject-repaint-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/text/foreignObject-repaint-expected.txt
@@ -8,3 +8,10 @@
           text run at (0,1) width 487: "Select this text using"
           text run at (0,63) width 473: "the mouse, it should"
           text run at (0,125) width 334: "not disappear!"
+layer at (100,100) size 500x300
+  LayoutSVGForeignObject {foreignObject} at (100,100) size 500x300
+    LayoutBlockFlow {div} at (0,0) size 500x186
+      LayoutText {#text} at (0,1) size 487x184
+        text run at (0,1) width 487: "Select this text using"
+        text run at (0,63) width 473: "the mouse, it should"
+        text run at (0,125) width 334: "not disappear!"
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/text/foreignObject-text-clipping-bug-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/svg/text/foreignObject-text-clipping-bug-expected.txt
index ae9a4540..aab6d262 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/text/foreignObject-text-clipping-bug-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/text/foreignObject-text-clipping-bug-expected.txt
@@ -14,6 +14,11 @@
               LayoutText {#text} at (0,0) size 24x12
                 text run at (0,0) width 24: "TEST"
         LayoutText {#text} at (0,0) size 0x0
+layer at (9,29) size 60x10 backgroundClip at (18,38) size 390x100 clip at (18,38) size 51x1 scrollHeight 12
+  LayoutSVGForeignObject {foreignObject} at (1,1) size 60x10
+    LayoutBlockFlow {div} at (0,0) size 60x12 [color=#000080]
+      LayoutText {#text} at (0,0) size 24x12
+        text run at (0,0) width 24: "TEST"
 layer at (18,163) size 390x110
   LayoutBlockFlow (relative positioned) {div} at (0,145) size 390x110 [color=#000080] [bgcolor=#D3D3D3]
     LayoutBlockFlow {div} at (0,0) size 390x118
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/text/text-selection-fonts-01-t-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/text/text-selection-fonts-01-t-expected.png
index 60d09da0..5b4802e 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/text/text-selection-fonts-01-t-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/text/text-selection-fonts-01-t-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/text/text-selection-fonts-01-t-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/svg/text/text-selection-fonts-01-t-expected.txt
index 32d9f73..ec464ae 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/text/text-selection-fonts-01-t-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/text/text-selection-fonts-01-t-expected.txt
@@ -4,8 +4,8 @@
   LayoutSVGRoot {svg} at (0,0) size 800x600
     LayoutSVGContainer {g} at (19.39,28.39) size 313.41x267.59
       LayoutSVGContainer {g} at (19.39,28.39) size 313.41x267.59
-        LayoutSVGText {text} at (19.39,57.80) size 196.19x27.59 contains 1 chunk(s)
-          LayoutSVGInlineText {#text} at (19.39,57.80) size 196.19x27.59
+        LayoutSVGText {text} at (19.39,57.80) size 196.19x30 contains 1 chunk(s)
+          LayoutSVGInlineText {#text} at (19.39,57.80) size 196.19x30
             chunk 1 text run 1 at (20.00,80.00) startOffset 0 endOffset 17 width 195.60: "A serifed face \x{753B}\x{50CF}"
         LayoutSVGText {text} at (19.39,138.39) size 232.80x27 contains 1 chunk(s)
           LayoutSVGInlineText {#text} at (19.39,138.39) size 232.80x27
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/text/text-selection-fonts-02-t-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/text/text-selection-fonts-02-t-expected.png
index 01973d6..fae8e37 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/text/text-selection-fonts-02-t-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/text/text-selection-fonts-02-t-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/text/text-selection-fonts-02-t-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/svg/text/text-selection-fonts-02-t-expected.txt
index d235a1e..d08e38f 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/text/text-selection-fonts-02-t-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/text/text-selection-fonts-02-t-expected.txt
@@ -2,47 +2,47 @@
   LayoutView at (0,0) size 800x600
 layer at (0,0) size 800x600
   LayoutSVGRoot {svg} at (0,0) size 800x600
-    LayoutSVGContainer {g} at (60,22.39) size 362.39x314.80
-      LayoutSVGText {text} at (360,22.39) size 49.80x34.80 contains 1 chunk(s)
-        LayoutSVGInlineText {#text} at (360,22.39) size 49.80x34.80
+    LayoutSVGContainer {g} at (60,22.39) size 362.39x317.19
+      LayoutSVGText {text} at (360,22.39) size 49.80x37.19 contains 1 chunk(s)
+        LayoutSVGInlineText {#text} at (360,22.39) size 49.80x37.19
           chunk 1 text run 1 at (360.00,50.00) startOffset 0 endOffset 3 width 49.80: "100"
-      LayoutSVGText {text} at (360,57.39) size 54x34.80 contains 1 chunk(s)
-        LayoutSVGInlineText {#text} at (360,57.39) size 54x34.80
+      LayoutSVGText {text} at (360,57.39) size 54x37.19 contains 1 chunk(s)
+        LayoutSVGInlineText {#text} at (360,57.39) size 54x37.19
           chunk 1 text run 1 at (360.00,85.00) startOffset 0 endOffset 3 width 54.00: "200"
-      LayoutSVGText {text} at (360,92.39) size 54x34.80 contains 1 chunk(s)
-        LayoutSVGInlineText {#text} at (360,92.39) size 54x34.80
+      LayoutSVGText {text} at (360,92.39) size 54x37.19 contains 1 chunk(s)
+        LayoutSVGInlineText {#text} at (360,92.39) size 54x37.19
           chunk 1 text run 1 at (360.00,120.00) startOffset 0 endOffset 3 width 54.00: "300"
-      LayoutSVGText {text} at (360,127.39) size 54x34.80 contains 1 chunk(s)
-        LayoutSVGInlineText {#text} at (360,127.39) size 54x34.80
+      LayoutSVGText {text} at (360,127.39) size 54x37.19 contains 1 chunk(s)
+        LayoutSVGInlineText {#text} at (360,127.39) size 54x37.19
           chunk 1 text run 1 at (360.00,155.00) startOffset 0 endOffset 3 width 54.00: "400"
-      LayoutSVGText {text} at (360,162.39) size 52.80x34.80 contains 1 chunk(s)
-        LayoutSVGInlineText {#text} at (360,162.39) size 52.80x34.80
+      LayoutSVGText {text} at (360,162.39) size 52.80x37.19 contains 1 chunk(s)
+        LayoutSVGInlineText {#text} at (360,162.39) size 52.80x37.19
           chunk 1 text run 1 at (360.00,190.00) startOffset 0 endOffset 3 width 52.80: "500"
-      LayoutSVGText {text} at (360,197.39) size 61.19x34.80 contains 1 chunk(s)
-        LayoutSVGInlineText {#text} at (360,197.39) size 61.19x34.80
+      LayoutSVGText {text} at (360,197.39) size 61.19x37.19 contains 1 chunk(s)
+        LayoutSVGInlineText {#text} at (360,197.39) size 61.19x37.19
           chunk 1 text run 1 at (360.00,225.00) startOffset 0 endOffset 3 width 61.20: "600"
-      LayoutSVGText {text} at (360,232.39) size 58.80x34.80 contains 1 chunk(s)
-        LayoutSVGInlineText {#text} at (360,232.39) size 58.80x34.80
+      LayoutSVGText {text} at (360,232.39) size 58.80x37.19 contains 1 chunk(s)
+        LayoutSVGInlineText {#text} at (360,232.39) size 58.80x37.19
           chunk 1 text run 1 at (360.00,260.00) startOffset 0 endOffset 3 width 58.80: "700"
-      LayoutSVGText {text} at (360,267.39) size 62.39x34.80 contains 1 chunk(s)
-        LayoutSVGInlineText {#text} at (360,267.39) size 62.39x34.80
+      LayoutSVGText {text} at (360,267.39) size 62.39x37.19 contains 1 chunk(s)
+        LayoutSVGInlineText {#text} at (360,267.39) size 62.39x37.19
           chunk 1 text run 1 at (360.00,295.00) startOffset 0 endOffset 3 width 62.40: "800"
-      LayoutSVGText {text} at (360,302.39) size 61.19x34.80 contains 1 chunk(s)
-        LayoutSVGInlineText {#text} at (360,302.39) size 61.19x34.80
+      LayoutSVGText {text} at (360,302.39) size 61.19x37.19 contains 1 chunk(s)
+        LayoutSVGInlineText {#text} at (360,302.39) size 61.19x37.19
           chunk 1 text run 1 at (360.00,330.00) startOffset 0 endOffset 3 width 61.20: "900"
-      LayoutSVGText {text} at (60,52.39) size 177.59x34.80 contains 1 chunk(s)
-        LayoutSVGInlineText {#text} at (60,52.39) size 177.59x34.80
+      LayoutSVGText {text} at (60,52.39) size 177.59x37.19 contains 1 chunk(s)
+        LayoutSVGInlineText {#text} at (60,52.39) size 177.59x37.19
           chunk 1 text run 1 at (60.00,80.00) startOffset 0 endOffset 12 width 177.60: "This is bold"
-      LayoutSVGText {text} at (60,102.39) size 190.80x34.80 contains 1 chunk(s)
-        LayoutSVGInlineText {#text} at (60,102.39) size 190.80x34.80
+      LayoutSVGText {text} at (60,102.39) size 190.80x37.19 contains 1 chunk(s)
+        LayoutSVGInlineText {#text} at (60,102.39) size 190.80x37.19
           chunk 1 text run 1 at (60.00,130.00) startOffset 0 endOffset 14 width 190.80: "This is normal"
-      LayoutSVGContainer {g} at (60,152.39) size 214.19x34.80
-        LayoutSVGText {text} at (60,152.39) size 214.19x34.80 contains 1 chunk(s)
-          LayoutSVGInlineText {#text} at (60,152.39) size 214.19x34.80
+      LayoutSVGContainer {g} at (60,152.39) size 214.19x37.19
+        LayoutSVGText {text} at (60,152.39) size 214.19x37.19 contains 1 chunk(s)
+          LayoutSVGInlineText {#text} at (60,152.39) size 214.19x37.19
             chunk 1 text run 1 at (60.00,180.00) startOffset 0 endOffset 14 width 214.20: "Blue is bolder"
-      LayoutSVGContainer {g} at (60,202.39) size 183.59x34.80
-        LayoutSVGText {text} at (60,202.39) size 183.59x34.80 contains 1 chunk(s)
-          LayoutSVGInlineText {#text} at (60,202.39) size 183.59x34.80
+      LayoutSVGContainer {g} at (60,202.39) size 183x37.19
+        LayoutSVGText {text} at (60,202.39) size 183x37.19 contains 1 chunk(s)
+          LayoutSVGInlineText {#text} at (60,202.39) size 183x37.19
             chunk 1 text run 1 at (60.00,230.00) startOffset 0 endOffset 15 width 183.00: "Blue is lighter"
     LayoutSVGText {text} at (10,304) size 268.19x45.59 contains 1 chunk(s)
       LayoutSVGInlineText {#text} at (10,304) size 268.19x45.59
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/text/text-selection-path-01-b-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/text/text-selection-path-01-b-expected.png
index 91ade57d..f317fca 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/text/text-selection-path-01-b-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/text/text-selection-path-01-b-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/text/text-selection-path-01-b-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/svg/text/text-selection-path-01-b-expected.txt
index 8edef54..9ca229e 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/text/text-selection-path-01-b-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/text/text-selection-path-01-b-expected.txt
@@ -2,17 +2,17 @@
   LayoutView at (0,0) size 800x600
 layer at (0,0) size 800x600
   LayoutSVGRoot {svg} at (0,0) size 800x600
-    LayoutSVGContainer {g} at (-8.64,-6.94) size 426.64x298.13
+    LayoutSVGContainer {g} at (-8.09,-6.33) size 426.09x297.52
       LayoutSVGHiddenContainer {defs} at (33.50,26.98) size 384.50x206.02
         LayoutSVGPath {path} at (199,26.98) size 219x78.02 [stroke={[type=SOLID] [color=#0000FF]}] [data="M 199 89.3 C 206.6 66.6 235.8 13.2 270 30.3 C 286.6 38.6 298.9 59.4 310 73.3 C 321.7 87.9 338.6 99 356 103.3 C 387.3 111.1 396.6 90.4 418 74.3"]
         LayoutSVGPath {path} at (33.50,83.48) size 219x78.02 [stroke={[type=SOLID] [color=#0000FF]}] [data="M 33.5 145.8 C 41 123 70.3 69.7 104.5 86.8 C 121 95 133 116 144.5 129.8 C 156.2 144.4 173 155.5 190.5 159.8 C 221.8 167.6 231 146.9 252.5 130.8"]
         LayoutSVGPath {path} at (113,233) size 300x0 [stroke={[type=SOLID] [color=#0000FF] [stroke width=4.00]}] [data="M 113 233 L 413 233"]
-      LayoutSVGContainer {g} at (167.86,-6.94) size 250.14x119.86
+      LayoutSVGContainer {g} at (168.41,-6.33) size 249.59x123.30
         LayoutSVGContainer {use} at (199,26.98) size 219x78.02
           LayoutSVGPath {path} at (199,26.98) size 219x78.02 [stroke={[type=SOLID] [color=#0000FF]}] [data="M 199 89.3 C 206.6 66.6 235.8 13.2 270 30.3 C 286.6 38.6 298.9 59.4 310 73.3 C 321.7 87.9 338.6 99 356 103.3 C 387.3 111.1 396.6 90.4 418 74.3"]
-        LayoutSVGText {text} at (167.86,-6.94) size 204.66x119.86 contains 1 chunk(s)
-          LayoutSVGTextPath {textPath} at (167.86,-6.94) size 204.66x119.86
-            LayoutSVGInlineText {#text} at (167.86,-6.94) size 204.66x119.86
+        LayoutSVGText {text} at (168.41,-6.33) size 203.94x123.30 contains 1 chunk(s)
+          LayoutSVGTextPath {textPath} at (168.41,-6.33) size 203.94x123.30
+            LayoutSVGInlineText {#text} at (168.41,-6.33) size 203.94x123.30
               chunk 1 text run 1 at (203.06,79.02) startOffset 0 endOffset 1 width 22.20: "T"
               chunk 1 text run 2 at (212.29,61.56) startOffset 1 endOffset 2 width 17.40: "e"
               chunk 1 text run 3 at (222.63,47.07) startOffset 2 endOffset 3 width 18.00: "x"
@@ -28,19 +28,19 @@
               chunk 1 text run 13 at (337.49,96.10) startOffset 12 endOffset 13 width 12.60: "t"
               chunk 1 text run 14 at (353.02,102.49) startOffset 13 endOffset 14 width 21.00: "h"
           LayoutSVGInlineText {#text} at (0,0) size 0x0
-      LayoutSVGContainer {g} at (-8.64,49.55) size 299.64x161.64
+      LayoutSVGContainer {g} at (-8.09,50.14) size 299.09x161.05
         LayoutSVGContainer {use} at (33.50,83.48) size 219x78.02
           LayoutSVGPath {path} at (33.50,83.48) size 219x78.02 [stroke={[type=SOLID] [color=#0000FF]}] [data="M 33.5 145.8 C 41 123 70.3 69.7 104.5 86.8 C 121 95 133 116 144.5 129.8 C 156.2 144.4 173 155.5 190.5 159.8 C 221.8 167.6 231 146.9 252.5 130.8"]
-        LayoutSVGText {text} at (-8.64,49.55) size 215.61x119.86 contains 1 chunk(s)
-          LayoutSVGTextPath {textPath} at (-8.64,49.55) size 215.61x119.86
-            LayoutSVGTSpan {tspan} at (-8.64,49.55) size 215.61x119.86
-              LayoutSVGInlineText {#text} at (-8.64,86.73) size 56.34x57.19
+        LayoutSVGText {text} at (-8.09,50.14) size 214.89x123.28 contains 1 chunk(s)
+          LayoutSVGTextPath {textPath} at (-8.09,50.14) size 214.89x123.28
+            LayoutSVGTSpan {tspan} at (-8.09,50.14) size 214.89x123.28
+              LayoutSVGInlineText {#text} at (-8.09,87.05) size 59.38x58.58
                 chunk 1 text run 1 at (37.53,135.50) startOffset 0 endOffset 1 width 22.20: "T"
                 chunk 1 text run 2 at (46.73,118.03) startOffset 1 endOffset 2 width 17.40: "e"
-            LayoutSVGTSpan {tspan} at (-8.64,49.55) size 215.61x119.86
-              LayoutSVGInlineText {#text} at (25.55,75.03) size 43.27x40.39
+            LayoutSVGTSpan {tspan} at (-8.09,50.14) size 214.89x123.28
+              LayoutSVGInlineText {#text} at (26.02,74.97) size 46.42x43.17
                 chunk 1 text run 1 at (57.08,103.54) startOffset 0 endOffset 1 width 18.00: "x"
-            LayoutSVGInlineText {#text} at (42.03,49.55) size 164.92x119.86
+            LayoutSVGInlineText {#text} at (42.41,50.14) size 164.38x123.28
               chunk 1 text run 1 at (67.95,92.75) startOffset 0 endOffset 1 width 12.60: "t"
               chunk 1 text run 2 at (76.74,87.05) startOffset 1 endOffset 2 width 8.40: " "
               chunk 1 text run 3 at (89.94,83.50) startOffset 2 endOffset 3 width 19.20: "o"
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/wicd/test-rightsizing-a-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/wicd/test-rightsizing-a-expected.png
index d2c2970..b854fecf 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/wicd/test-rightsizing-a-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/wicd/test-rightsizing-a-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/wicd/test-rightsizing-a-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/svg/wicd/test-rightsizing-a-expected.txt
index 734f0659..fae14dcb 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/wicd/test-rightsizing-a-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/wicd/test-rightsizing-a-expected.txt
@@ -1,9 +1,9 @@
 layer at (0,0) size 800x600
   LayoutView at (0,0) size 800x600
-layer at (0,0) size 800x550
-  LayoutBlockFlow {html} at (0,0) size 800x549.86
-    LayoutBlockFlow {body} at (48,30.72) size 752x511.14
-      LayoutBlockFlow {div} at (0,0) size 752x511.14
+layer at (0,0) size 800x558
+  LayoutBlockFlow {html} at (0,0) size 800x557.86
+    LayoutBlockFlow {body} at (48,30.72) size 752x519.14
+      LayoutBlockFlow {div} at (0,0) size 752x519.14
         LayoutBlockFlow {h1} at (0,0) size 691.83x31
           LayoutText {#text} at (0,0) size 216x30
             text run at (0,0) width 216: "rightsizing to box"
@@ -17,30 +17,30 @@
           LayoutBR {br} at (0,0) size 0x18
         LayoutBlockFlow {div} at (0,147.14) size 176x62 [bgcolor=#FF0000]
           LayoutText {#text} at (0,0) size 0x0
-        LayoutBlockFlow {p} at (0,212.02) size 691.83x34
-          LayoutText {#text} at (0,0) size 684x34
+        LayoutBlockFlow {p} at (0,212.02) size 691.83x36
+          LayoutText {#text} at (0,0) size 684x36
             text run at (0,0) width 684: "Above there must be a GIF- and a SVG-image visible. Both are referenced by an object element (width:100%, no"
-            text run at (0,17) width 481: "defined height) and each nested into a div element (width:176px, height:62px)."
-        LayoutBlockFlow {div} at (0,251.77) size 176x62 [bgcolor=#FF0000]
+            text run at (0,18) width 480: "defined height) and each nested into a div element (width:176px, height:62px)."
+        LayoutBlockFlow {div} at (0,253.77) size 176x62 [bgcolor=#FF0000]
           LayoutImage {object} at (0,0) size 176x62
           LayoutText {#text} at (0,0) size 0x0
-        LayoutBlockFlow (anonymous) at (0,313.77) size 752x19
+        LayoutBlockFlow (anonymous) at (0,315.77) size 752x19
           LayoutBR {br} at (0,0) size 0x18
-        LayoutBlockFlow {div} at (0,332.77) size 176x62 [bgcolor=#FF0000]
+        LayoutBlockFlow {div} at (0,334.77) size 176x62 [bgcolor=#FF0000]
           LayoutText {#text} at (0,0) size 0x0
-        LayoutBlockFlow {p} at (0,397.64) size 691.83x34
-          LayoutText {#text} at (0,0) size 653x34
-            text run at (0,0) width 653: "Above there must be a GIF- and a SVG-image visible. Both are referenced by an object element (no defined"
-            text run at (0,17) width 512: "width, height:100%) and each nested into a div element (width:176px, height:62px)."
-        LayoutBlockFlow {p} at (0,437.39) size 691.83x34
-          LayoutText {#text} at (0,0) size 668x34
+        LayoutBlockFlow {p} at (0,399.64) size 691.83x36
+          LayoutText {#text} at (0,0) size 652x36
+            text run at (0,0) width 652: "Above there must be a GIF- and a SVG-image visible. Both are referenced by an object element (no defined"
+            text run at (0,18) width 512: "width, height:100%) and each nested into a div element (width:176px, height:62px)."
+        LayoutBlockFlow {p} at (0,441.39) size 691.83x36
+          LayoutText {#text} at (0,0) size 668x36
             text run at (0,0) width 668: "This tests have succeeded, if in both cases, the look (dimensions) of the SVG and the GIF are exactly the same"
-            text run at (0,17) width 411: "(except the text apparently) and no red background color is visible."
-        LayoutBlockFlow {p} at (0,477.14) size 691.83x34
-          LayoutBR {br} at (0,0) size 0x17
-          LayoutInline {a} at (0,0) size 30x17 [color=#000066]
-            LayoutText {#text} at (0,17) size 30x17
-              text run at (0,17) width 30: "Back"
+            text run at (0,18) width 411: "(except the text apparently) and no red background color is visible."
+        LayoutBlockFlow {p} at (0,483.14) size 691.83x36
+          LayoutBR {br} at (0,0) size 0x18
+          LayoutInline {a} at (0,0) size 30x18 [color=#000066]
+            LayoutText {#text} at (0,18) size 30x18
+              text run at (0,18) width 30: "Back"
 layer at (48,178) size 176x62
   LayoutEmbeddedObject {object} at (0,0) size 176x62
     layer at (0,0) size 176x62
@@ -54,7 +54,7 @@
         LayoutSVGText {text} at (46,10) size 80x46 contains 1 chunk(s)
           LayoutSVGInlineText {#text} at (46,10) size 80x46
             chunk 1 (middle anchor) text run 1 at (46.00,46.00) startOffset 0 endOffset 3 width 80.00: "SVG"
-layer at (48,363) size 176x62
+layer at (48,365) size 176x62
   LayoutEmbeddedObject {object} at (0,0) size 176x62
     layer at (0,0) size 176x62
       LayoutView at (0,0) size 176x62
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/wicd/test-scalable-background-image1-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/wicd/test-scalable-background-image1-expected.png
index b486db2b2..1b1a794 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/wicd/test-scalable-background-image1-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/wicd/test-scalable-background-image1-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/wicd/test-scalable-background-image1-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/svg/wicd/test-scalable-background-image1-expected.txt
index 9f0087f..993bee4 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/wicd/test-scalable-background-image1-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/wicd/test-scalable-background-image1-expected.txt
@@ -1,25 +1,25 @@
 layer at (0,0) size 800x600 clip at (0,0) size 800x585 scrollWidth 820
   LayoutView at (0,0) size 800x600
-layer at (0,0) size 800x321
-  LayoutBlockFlow {html} at (0,0) size 800x320.86
-    LayoutBlockFlow {body} at (48,8) size 772x304.86
+layer at (0,0) size 800x326
+  LayoutBlockFlow {html} at (0,0) size 800x325.86
+    LayoutBlockFlow {body} at (48,8) size 772x309.86
       LayoutBlockFlow {h1} at (10,40.72) size 691.83x31
         LayoutText {#text} at (0,0) size 315x30
           text run at (0,0) width 315: "scalable CSS background"
       LayoutBlockFlow {h4} at (10,71.72) size 752x16
         LayoutText {#text} at (0,0) size 123x16
           text run at (0,0) width 123: "WICD Core 1.0 #11"
-      LayoutBlockFlow {p} at (10,106.86) size 711.83x37
-        LayoutText {#text} at (10,10) size 495x17
+      LayoutBlockFlow {p} at (10,106.86) size 711.83x38
+        LayoutText {#text} at (10,10) size 495x18
           text run at (10,10) width 495: "This text paragraph, as well as all following, must have a SVG background image."
-      LayoutBlockFlow {p} at (10,149.61) size 711.83x37
-        LayoutText {#text} at (10,10) size 670x17
-          text run at (10,10) width 670: "This background image (grey color-gradient and rounded corners) must always exactly fit the text paragraph."
-      LayoutBlockFlow {p} at (10,192.36) size 711.83x54
-        LayoutText {#text} at (10,10) size 676x34
+      LayoutBlockFlow {p} at (10,150.61) size 711.83x38
+        LayoutText {#text} at (10,10) size 669x18
+          text run at (10,10) width 669: "This background image (grey color-gradient and rounded corners) must always exactly fit the text paragraph."
+      LayoutBlockFlow {p} at (10,194.36) size 711.83x56
+        LayoutText {#text} at (10,10) size 676x36
           text run at (10,10) width 676: "This test has failed, if you don't see any graphics on the background. (your user agent does not support SVG as"
-          text run at (10,27) width 123: "background image)."
-      LayoutBlockFlow {p} at (10,252.11) size 711.83x37
-        LayoutInline {a} at (0,0) size 30x17 [color=#000066]
-          LayoutText {#text} at (10,10) size 30x17
+          text run at (10,28) width 123: "background image)."
+      LayoutBlockFlow {p} at (10,256.11) size 711.83x38
+        LayoutInline {a} at (0,0) size 30x18 [color=#000066]
+          LayoutText {#text} at (10,10) size 30x18
             text run at (10,10) width 30: "Back"
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/wicd/test-scalable-background-image2-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/wicd/test-scalable-background-image2-expected.png
index e593efa..91d5a467 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/wicd/test-scalable-background-image2-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/wicd/test-scalable-background-image2-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/wicd/test-scalable-background-image2-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/svg/wicd/test-scalable-background-image2-expected.txt
index 0200b17e..3ba34c92 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/wicd/test-scalable-background-image2-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/wicd/test-scalable-background-image2-expected.txt
@@ -2,23 +2,23 @@
   LayoutView at (0,0) size 800x600
 layer at (0,0) size 800x600
   LayoutBlockFlow {html} at (0,0) size 800x600
-    LayoutBlockFlow {body} at (48,30.72) size 752x162.64
+    LayoutBlockFlow {body} at (48,30.72) size 752x167.64
       LayoutBlockFlow {h1} at (0,0) size 691.83x31
         LayoutText {#text} at (0,0) size 383x30
           text run at (0,0) width 383: "scalable fullscreen background"
       LayoutBlockFlow {h4} at (0,31) size 752x16
         LayoutText {#text} at (0,0) size 125x16
           text run at (0,0) width 125: "WICD Core 1.0 #12"
-      LayoutBlockFlow {p} at (0,66.14) size 691.83x34
-        LayoutText {#text} at (0,0) size 677x34
+      LayoutBlockFlow {p} at (0,66.14) size 691.83x36
+        LayoutText {#text} at (0,0) size 677x36
           text run at (0,0) width 615: "This text is XHTML main layer content, which must overlay a lightblue SVG-background image with "
           text run at (615,0) width 62: "text ('SVG"
-          text run at (0,17) width 621: "background image'). The SVG background image must cover the complete XHTML-background area."
-      LayoutBlockFlow {p} at (0,105.89) size 691.83x34
-        LayoutText {#text} at (0,0) size 676x34
+          text run at (0,18) width 621: "background image'). The SVG background image must cover the complete XHTML-background area."
+      LayoutBlockFlow {p} at (0,107.89) size 691.83x36
+        LayoutText {#text} at (0,0) size 676x36
           text run at (0,0) width 676: "This test has failed, if you don't see any graphics on the background. (your user agent does not support SVG as"
-          text run at (0,17) width 123: "background image)."
-      LayoutBlockFlow {p} at (0,145.64) size 691.83x17
-        LayoutInline {a} at (0,0) size 30x17 [color=#000066]
-          LayoutText {#text} at (0,0) size 30x17
+          text run at (0,18) width 123: "background image)."
+      LayoutBlockFlow {p} at (0,149.64) size 691.83x18
+        LayoutInline {a} at (0,0) size 30x18 [color=#000066]
+          LayoutText {#text} at (0,0) size 30x18
             text run at (0,0) width 30: "Back"
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/zoom/page/zoom-foreignObject-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/svg/zoom/page/zoom-foreignObject-expected.txt
index 300959b..3893cf8 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/zoom/page/zoom-foreignObject-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/zoom/page/zoom-foreignObject-expected.txt
@@ -31,3 +31,31 @@
       LayoutText {#text} at (0,0) size 0x0
     LayoutSVGRect {rect} at (260,0) size 250x200 [stroke={[type=SOLID] [color=#008000]}] [x=260.00] [y=0.00] [width=250.00] [height=200.00]
     LayoutSVGHiddenContainer {defs} at (0,0) size 0x0
+layer at (0,0) size 250x200
+  LayoutSVGForeignObject {foreignObject} at (0,0) size 250x200
+    LayoutBlockFlow {xhtml:div} at (0,0) size 250x20
+      LayoutText {#text} at (0,0) size 80x19
+        text run at (0,0) width 80: "This is a text"
+    LayoutBlockFlow (anonymous) at (0,20) size 250x20
+      LayoutInline {xhtml:a} at (0,0) size 66x19 [color=#0000EE]
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "and a link."
+      LayoutBR {xhtml:br} at (66,0) size 0x19
+    LayoutBlockFlow {xhtml:div} at (0,40) size 250x20
+      LayoutText {#text} at (0,0) size 56x19
+        text run at (0,0) width 56: "[HTML]"
+layer at (260,0) size 250x200 backgroundClip at (374,0) size 360x288 clip at (374,0) size 136x200 scrollHeight 205
+  LayoutSVGForeignObject {foreignObject} at (260,0) size 250x200
+    LayoutSVGRoot {svg} at (0,0) size 250x200
+      LayoutSVGContainer {g} at (0,1.77) size 81.38x58.19 [transform={m=((3.00,0.26)(0.26,3.02)) t=(0.00,0.00)}]
+        LayoutSVGText {text} at (0,1.77) size 81.38x18.19 contains 1 chunk(s)
+          LayoutSVGInlineText {#text} at (0,1.77) size 81.38x18.19
+            chunk 1 text run 1 at (0.00,16.00) startOffset 0 endOffset 14 width 81.05: "This is a text"
+        LayoutSVGContainer {a} at (0,20.77) size 66.16x18.19
+          LayoutSVGText {text} at (0,20.77) size 66.16x18.19 contains 1 chunk(s)
+            LayoutSVGInlineText {#text} at (0,20.77) size 66.16x18.19
+              chunk 1 text run 1 at (0.00,35.00) startOffset 0 endOffset 11 width 66.16: "and a link."
+        LayoutSVGText {text} at (0,41.77) size 42.67x18.19 contains 1 chunk(s)
+          LayoutSVGInlineText {#text} at (0,41.77) size 42.67x18.19
+            chunk 1 text run 1 at (0.00,56.00) startOffset 0 endOffset 5 width 42.67: "[SVG]"
+    LayoutText {#text} at (0,0) size 0x0
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/zoom/page/zoom-hixie-mixed-009-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/svg/zoom/page/zoom-hixie-mixed-009-expected.txt
index d620af130..77f7ef9 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/zoom/page/zoom-hixie-mixed-009-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/zoom/page/zoom-hixie-mixed-009-expected.txt
@@ -17,3 +17,8 @@
       LayoutBlockFlow {div} at (0,206.80) size 576x172.80 [color=#000080] [bgcolor=#EEEEEE]
         LayoutText {#text} at (0,3) size 344x164
           text run at (0,3) width 344: "TEST"
+layer at (12,39) size 60x10 scrollHeight 12
+  LayoutSVGForeignObject {foreignObject} at (0,0) size 60x10
+    LayoutBlockFlow {div} at (0,0) size 60x12 [color=#000080]
+      LayoutText {#text} at (0,0) size 24x12
+        text run at (0,0) width 24: "TEST"
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/zoom/text/zoom-hixie-mixed-008-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/svg/zoom/text/zoom-hixie-mixed-008-expected.txt
index f5bdcf3..0646ae00 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/zoom/text/zoom-hixie-mixed-008-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/zoom/text/zoom-hixie-mixed-008-expected.txt
@@ -15,3 +15,8 @@
               LayoutText {#text} at (114,1) size 172x81
                 text run at (114,1) width 172: "TEST"
         LayoutText {#text} at (0,0) size 0x0
+layer at (8,248) size 400x50 scrollHeight 84
+  LayoutSVGForeignObject {foreignObject} at (0,175) size 400x50 [color=#FFFFFF]
+    LayoutBlockFlow {div} at (0,0) size 400x84
+      LayoutText {#text} at (114,1) size 172x81
+        text run at (114,1) width 172: "TEST"
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/zoom/text/zoom-hixie-mixed-009-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/svg/zoom/text/zoom-hixie-mixed-009-expected.txt
index 08b8494..e8c09f7d 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/zoom/text/zoom-hixie-mixed-009-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/zoom/text/zoom-hixie-mixed-009-expected.txt
@@ -17,3 +17,8 @@
       LayoutBlockFlow {div} at (0,154) size 400x120 [color=#000080] [bgcolor=#EEEEEE]
         LayoutText {#text} at (0,3) size 344x164
           text run at (0,3) width 344: "TEST"
+layer at (8,35) size 60x10 scrollHeight 17
+  LayoutSVGForeignObject {foreignObject} at (0,0) size 60x10
+    LayoutBlockFlow {div} at (0,0) size 60x17 [color=#000080]
+      LayoutText {#text} at (0,0) size 35x16
+        text run at (0,0) width 35: "TEST"
diff --git a/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/bugs/bug2886-2-expected.png b/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/bugs/bug2886-2-expected.png
index 8958489a..e5cfb78 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/bugs/bug2886-2-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/bugs/bug2886-2-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/disable-spv175/paint/invalidation/svg/foreign-object-repaint-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/disable-spv175/paint/invalidation/svg/foreign-object-repaint-expected.png
new file mode 100644
index 0000000..17bdbb7
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/disable-spv175/paint/invalidation/svg/foreign-object-repaint-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/disable-spv175/paint/invalidation/svg/zoom-foreignObject-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/disable-spv175/paint/invalidation/svg/zoom-foreignObject-expected.png
index d17fdcd..6368e49 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/disable-spv175/paint/invalidation/svg/zoom-foreignObject-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/disable-spv175/paint/invalidation/svg/zoom-foreignObject-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/imagemap-focus-ring-outline-color-not-inherited-from-map-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/imagemap-focus-ring-outline-color-not-inherited-from-map-expected.png
index ccb4fdb2..b41b3e11 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/imagemap-focus-ring-outline-color-not-inherited-from-map-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/imagemap-focus-ring-outline-color-not-inherited-from-map-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/imagemap-focus-ring-outline-color-not-inherited-from-map-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/imagemap-focus-ring-outline-color-not-inherited-from-map-expected.txt
index 2c5771c5..3b327342 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/imagemap-focus-ring-outline-color-not-inherited-from-map-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/imagemap-focus-ring-outline-color-not-inherited-from-map-expected.txt
@@ -12,7 +12,7 @@
             text run at (207,20) width 467: "section 18.4 \"Dynamic outlines: the 'outline' property\" of the CSS2.1 spec"
         LayoutText {#text} at (674,20) size 735x39
           text run at (674,20) width 61: ". This test"
-          text run at (0,40) width 566: "FAILED if a red-colored focus ring is drawn around the <area> in the imagemap (below)."
+          text run at (0,40) width 565: "FAILED if a red-colored focus ring is drawn around the <area> in the imagemap (below)."
       LayoutBlockFlow (anonymous) at (0,76) size 784x128
         LayoutInline {MAP} at (0,0) size 0x0
           LayoutText {#text} at (0,0) size 0x0
diff --git a/third_party/WebKit/LayoutTests/virtual/gpu/fast/canvas/canvas-composite-video-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu/fast/canvas/canvas-composite-video-shadow-expected.png
similarity index 100%
rename from third_party/WebKit/LayoutTests/virtual/gpu/fast/canvas/canvas-composite-video-shadow-expected.png
rename to third_party/WebKit/LayoutTests/platform/linux/virtual/gpu/fast/canvas/canvas-composite-video-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/layout_ng/fast/block/margin-collapse/103-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/layout_ng/fast/block/margin-collapse/103-expected.png
index 5269f8a..7736f52 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/layout_ng/fast/block/margin-collapse/103-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/layout_ng/fast/block/margin-collapse/103-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/spv175/paint/invalidation/svg/transform-foreign-object-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/virtual/spv175/paint/invalidation/svg/transform-foreign-object-expected.txt
new file mode 100644
index 0000000..56c9291
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/spv175/paint/invalidation/svg/transform-foreign-object-expected.txt
@@ -0,0 +1,33 @@
+{
+  "layers": [
+    {
+      "name": "LayoutView #document",
+      "bounds": [800, 600],
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "Scrolling Layer",
+      "bounds": [800, 600],
+      "drawsContent": false
+    },
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "paintInvalidations": [
+        {
+          "object": "LayoutSVGForeignObject foreignObject",
+          "rect": [108, 8, 100, 100],
+          "reason": "appeared"
+        },
+        {
+          "object": "LayoutSVGRoot svg",
+          "rect": [8, 8, 100, 100],
+          "reason": "disappeared"
+        }
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/table/backgr_border-table-column-group-collapsed-border-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/table/backgr_border-table-column-group-collapsed-border-expected.png
index 06b761e..7b63edc 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/table/backgr_border-table-column-group-collapsed-border-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/table/backgr_border-table-column-group-collapsed-border-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.11/fast/table/backgr_border-table-column-group-collapsed-border-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.11/fast/table/backgr_border-table-column-group-collapsed-border-expected.png
index 9584597..6fbc174 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.11/fast/table/backgr_border-table-column-group-collapsed-border-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.11/fast/table/backgr_border-table-column-group-collapsed-border-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/prefer_compositing_to_lcd_text/compositing/overflow/accelerated-scrolling-with-clip-path-text-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/prefer_compositing_to_lcd_text/compositing/overflow/accelerated-scrolling-with-clip-path-text-expected.txt
deleted file mode 100644
index cc5006c7..0000000
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/prefer_compositing_to_lcd_text/compositing/overflow/accelerated-scrolling-with-clip-path-text-expected.txt
+++ /dev/null
@@ -1,22 +0,0 @@
-layer at (0,0) size 800x600
-  LayoutView at (0,0) size 800x600
-layer at (0,0) size 800x434
-  LayoutBlockFlow {HTML} at (0,0) size 800x434
-    LayoutBlockFlow {BODY} at (8,8) size 784x418
-      LayoutBlockFlow (anonymous) at (0,0) size 784x18
-        LayoutText {#text} at (0,0) size 579x18
-          text run at (0,0) width 579: "This tests that reference clip-path with text is correctly applied with composited scrolling. "
-        LayoutSVGRoot {svg} at (578.50,14) size 0x0
-          LayoutSVGHiddenContainer {defs} at (0,0) size 0x0
-            LayoutSVGResourceClipper {clipPath} [id="clipping"] [clipPathUnits=userSpaceOnUse]
-              LayoutSVGText {text} at (100,66) size 143.34x69 contains 1 chunk(s)
-                LayoutSVGInlineText {#text} at (100,66) size 143.34x69
-                  chunk 1 text run 1 at (100.00,120.00) startOffset 0 endOffset 4 width 143.35: "CLIP"
-        LayoutText {#text} at (0,0) size 0x0
-layer at (8,26) size 400x400 backgroundClip at (108,92) size 144x69 clip at (108,92) size 144x69 scrollWidth 500 scrollHeight 700
-  LayoutBlockFlow {DIV} at (0,18) size 400x400 [bgcolor=#0000FF]
-    LayoutBlockFlow {DIV} at (0,0) size 100x100 [bgcolor=#008000]
-    LayoutBlockFlow {DIV} at (0,100) size 500x500 [bgcolor=#FFFF00]
-    LayoutBlockFlow {DIV} at (0,600) size 100x100 [bgcolor=#008000]
-layer at (8,376) size 100x100 backgroundClip at (108,92) size 144x69 clip at (108,92) size 144x69
-  LayoutBlockFlow (relative positioned) {DIV} at (0,0) size 100x100 [bgcolor=#008000]
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/fast/table/backgr_border-table-cell-collapsed-border-expected.png b/third_party/WebKit/LayoutTests/platform/mac-retina/fast/table/backgr_border-table-cell-collapsed-border-expected.png
deleted file mode 100644
index f0cf6f4d..0000000
--- a/third_party/WebKit/LayoutTests/platform/mac-retina/fast/table/backgr_border-table-cell-collapsed-border-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/fast/table/backgr_border-table-column-group-collapsed-border-expected.png b/third_party/WebKit/LayoutTests/platform/mac-retina/fast/table/backgr_border-table-column-group-collapsed-border-expected.png
deleted file mode 100644
index b93563c..0000000
--- a/third_party/WebKit/LayoutTests/platform/mac-retina/fast/table/backgr_border-table-column-group-collapsed-border-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/webaudio/DynamicsCompressor/dynamicscompressor-clear-internal-state-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-retina/webaudio/DynamicsCompressor/dynamicscompressor-clear-internal-state-expected.txt
deleted file mode 100644
index 7ba628d..0000000
--- a/third_party/WebKit/LayoutTests/platform/mac-retina/webaudio/DynamicsCompressor/dynamicscompressor-clear-internal-state-expected.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-This is a testharness.js-based test.
-PASS # AUDIT TASK RUNNER STARTED.
-PASS > [test] Validate Reduction Value of DynamicsCompressor after Disabling
-FAIL X Math.abs(compressor.reduction) is not less than or equal to 0.048223. Got 5.246633529663086. assert_true: expected true got false
-FAIL < [test] 1 out of 1 assertions were failed. assert_true: expected true got false
-FAIL # AUDIT TASK RUNNER FINISHED: 1 out of 1 tasks were failed. assert_true: expected true got false
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/platform/win/css3/filters/effect-reference-subregion-nested-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/css3/filters/effect-reference-subregion-nested-expected.txt
similarity index 71%
rename from third_party/WebKit/LayoutTests/platform/win/css3/filters/effect-reference-subregion-nested-expected.txt
rename to third_party/WebKit/LayoutTests/platform/mac/css3/filters/effect-reference-subregion-nested-expected.txt
index 1661801..33675f7 100644
--- a/third_party/WebKit/LayoutTests/platform/win/css3/filters/effect-reference-subregion-nested-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/css3/filters/effect-reference-subregion-nested-expected.txt
@@ -1,10 +1,10 @@
 layer at (0,0) size 800x600
   LayoutView at (0,0) size 800x600
-layer at (0,0) size 800x268
-  LayoutBlockFlow {HTML} at (0,0) size 800x268
-    LayoutBlockFlow {BODY} at (8,8) size 784x240
-      LayoutBlockFlow (anonymous) at (0,0) size 784x20
-        LayoutSVGRoot {svg} at (0,15) size 0x0
+layer at (0,0) size 800x266
+  LayoutBlockFlow {HTML} at (0,0) size 800x266
+    LayoutBlockFlow {BODY} at (8,8) size 784x238
+      LayoutBlockFlow (anonymous) at (0,0) size 784x18
+        LayoutSVGRoot {svg} at (0,14) size 0x0
           LayoutSVGHiddenContainer {defs} at (0,0) size 0x0
             LayoutSVGResourceFilter {filter} [id="merge"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
               [feMerge mergeNodes="2"]
@@ -15,5 +15,5 @@
                   [feColorMatrix type="MATRIX" values="1.00 0.00 0.00 0.00 0.00 0.00 1.00 0.00 0.00 0.00 0.00 0.00 1.00 0.00 0.00 0.00 0.00 0.00 0.30 0.00"]
                     [SourceGraphic]
         LayoutText {#text} at (0,0) size 0x0
-layer at (28,48) size 200x200
-  LayoutBlockFlow {DIV} at (20,40) size 200x200 [bgcolor=#008000]
+layer at (28,46) size 200x200
+  LayoutBlockFlow {DIV} at (20,38) size 200x200 [bgcolor=#008000]
diff --git a/third_party/WebKit/LayoutTests/platform/mac/editing/selection/click-start-of-line-expected.png b/third_party/WebKit/LayoutTests/platform/mac/editing/selection/click-start-of-line-expected.png
index ca1909e..83936959 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/editing/selection/click-start-of-line-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/editing/selection/click-start-of-line-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/datalist/input-appearance-range-with-datalist-zoomed-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/datalist/input-appearance-range-with-datalist-zoomed-expected.png
index 657fc52..9f75243 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/datalist/input-appearance-range-with-datalist-zoomed-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/datalist/input-appearance-range-with-datalist-zoomed-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/table/backgr_border-table-column-group-collapsed-border-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/table/backgr_border-table-column-group-collapsed-border-expected.png
index b93563c..1bc16fc 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/table/backgr_border-table-column-group-collapsed-border-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/table/backgr_border-table-column-group-collapsed-border-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/svg/text-rescale-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/svg/text-rescale-expected.txt
index 5a17bb7b..5d47139 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/svg/text-rescale-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/svg/text-rescale-expected.txt
@@ -19,12 +19,12 @@
       "paintInvalidations": [
         {
           "object": "InlineTextBox 'PASS '",
-          "rect": [0, 113, 302, 47],
+          "rect": [0, 114, 194, 46],
           "reason": "appeared"
         },
         {
           "object": "LayoutSVGRoot (positioned) svg",
-          "rect": [0, 13, 302, 47],
+          "rect": [0, 14, 194, 46],
           "reason": "appeared"
         },
         {
@@ -38,8 +38,18 @@
           "reason": "appeared"
         },
         {
+          "object": "LayoutSVGForeignObject foreignObject",
+          "rect": [210, 113, 92, 46],
+          "reason": "paint property change"
+        },
+        {
+          "object": "LayoutSVGForeignObject foreignObject",
+          "rect": [210, 13, 92, 46],
+          "reason": "paint property change"
+        },
+        {
           "object": "LayoutSVGContainer g id='text3g'",
-          "rect": [0, 3, 10, 2],
+          "rect": [0, 3, 6, 2],
           "reason": "disappeared"
         },
         {
@@ -48,9 +58,14 @@
           "reason": "paint property change"
         },
         {
-          "object": "LayoutSVGContainer g id='text1g'",
+          "object": "LayoutSVGForeignObject foreignObject",
+          "rect": [6, 3, 4, 2],
+          "reason": "paint property change"
+        },
+        {
+          "object": "LayoutSVGForeignObject foreignObject",
           "rect": [0, 0, 1, 1],
-          "reason": "disappeared"
+          "reason": "paint property change"
         }
       ]
     }
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/svg/zoom-foreignObject-expected.png b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/svg/zoom-foreignObject-expected.png
index 705289c..605b4cd 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/svg/zoom-foreignObject-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/svg/zoom-foreignObject-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/animate-elem-82-t-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/animate-elem-82-t-expected.png
index 6421bfce..c91bb7e0 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/animate-elem-82-t-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/animate-elem-82-t-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/as-background-image/svg-as-background-5-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/as-background-image/svg-as-background-5-expected.png
index a80af4f9..98c2fe3 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/as-background-image/svg-as-background-5-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/as-background-image/svg-as-background-5-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/as-object/svg-embedded-in-html-in-iframe-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/svg/as-object/svg-embedded-in-html-in-iframe-expected.txt
similarity index 62%
rename from third_party/WebKit/LayoutTests/platform/win/svg/as-object/svg-embedded-in-html-in-iframe-expected.txt
rename to third_party/WebKit/LayoutTests/platform/mac/svg/as-object/svg-embedded-in-html-in-iframe-expected.txt
index 456fbfb..602fbe6 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/as-object/svg-embedded-in-html-in-iframe-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/as-object/svg-embedded-in-html-in-iframe-expected.txt
@@ -1,15 +1,15 @@
 layer at (0,0) size 800x600
   LayoutView at (0,0) size 800x600
-layer at (0,0) size 800x171
-  LayoutBlockFlow {HTML} at (0,0) size 800x171
-    LayoutBlockFlow {BODY} at (8,8) size 784x155
+layer at (0,0) size 800x170
+  LayoutBlockFlow {HTML} at (0,0) size 800x170
+    LayoutBlockFlow {BODY} at (8,8) size 784x154
       LayoutText {#text} at (0,0) size 0x0
 layer at (8,8) size 784x150
   LayoutIFrame {IFRAME} at (0,0) size 784x150
     layer at (0,0) size 784x150
       LayoutView at (0,0) size 784x150
-    layer at (0,0) size 784x121
-      LayoutBlockFlow {HTML} at (0,0) size 784x121
-        LayoutBlockFlow {BODY} at (8,8) size 768x105
+    layer at (0,0) size 784x120
+      LayoutBlockFlow {HTML} at (0,0) size 784x120
+        LayoutBlockFlow {BODY} at (8,8) size 768x104
           LayoutSVGRoot {svg} at (0,0) size 100x100
             LayoutSVGEllipse {circle} at (0,0) size 100x100 [fill={[type=SOLID] [color=#0000FF]}] [cx=50.00] [cy=50.00] [r=50.00]
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/custom/dominant-baseline-hanging-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/svg/custom/dominant-baseline-hanging-expected.txt
index 953df44..5203f9f 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/custom/dominant-baseline-hanging-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/custom/dominant-baseline-hanging-expected.txt
@@ -54,3 +54,43 @@
                 text run at (0,0) width 92: "Antoine Quint"
             LayoutText {#text} at (91,0) size 92x18
               text run at (91,0) width 92: ", January 27th"
+layer at (10,45) size 380x150 scrollHeight 156
+  LayoutSVGForeignObject {foreignObject} at (10,45) size 380x150
+    LayoutBlockFlow {html} at (0,16) size 380x124
+      LayoutBlockFlow {body} at (8,0) size 364x124
+        LayoutBlockFlow {p} at (0,0) size 364x90
+          LayoutText {#text} at (0,0) size 353x36
+            text run at (0,0) width 353: "The piece of text above should be aligned with the top-"
+            text run at (0,18) width 293: "left corner of the rectangle below it. Both the "
+          LayoutInline {code} at (0,0) size 48x15
+            LayoutText {#text} at (292,20) size 48x15
+              text run at (292,20) width 48: "<text>"
+          LayoutText {#text} at (0,36) size 51x18
+            text run at (0,36) width 51: "and the "
+          LayoutInline {code} at (0,0) size 48x15
+            LayoutText {#text} at (50,38) size 48x15
+              text run at (50,38) width 48: "<rect>"
+          LayoutText {#text} at (97,36) size 352x36
+            text run at (97,36) width 255: " are located at the same coordinates and"
+            text run at (0,54) width 24: "the "
+          LayoutInline {code} at (0,0) size 48x15
+            LayoutText {#text} at (23,56) size 48x15
+              text run at (23,56) width 48: "<text>"
+          LayoutText {#text} at (70,54) size 115x18
+            text run at (70,54) width 115: " element uses the "
+          LayoutInline {code} at (0,0) size 55x15
+            LayoutText {#text} at (184,56) size 55x15
+              text run at (184,56) width 55: "hanging"
+          LayoutText {#text} at (238,54) size 82x18
+            text run at (238,54) width 82: " value for its"
+          LayoutInline {code} at (0,0) size 133x15
+            LayoutText {#text} at (0,74) size 133x15
+              text run at (0,74) width 133: "dominant-baseline"
+          LayoutText {#text} at (132,72) size 62x18
+            text run at (132,72) width 62: " attribute."
+        LayoutBlockFlow {p} at (0,106) size 364x18
+          LayoutInline {a} at (0,0) size 92x18 [color=#800000]
+            LayoutText {#text} at (0,0) size 92x18
+              text run at (0,0) width 92: "Antoine Quint"
+          LayoutText {#text} at (91,0) size 92x18
+            text run at (91,0) width 92: ", January 27th"
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/custom/filter-css-transform-resolution-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/svg/custom/filter-css-transform-resolution-expected.txt
similarity index 78%
rename from third_party/WebKit/LayoutTests/platform/win/svg/custom/filter-css-transform-resolution-expected.txt
rename to third_party/WebKit/LayoutTests/platform/mac/svg/custom/filter-css-transform-resolution-expected.txt
index bcc1bec..eafa544 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/custom/filter-css-transform-resolution-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/custom/filter-css-transform-resolution-expected.txt
@@ -1,9 +1,9 @@
 layer at (0,0) size 800x600
   LayoutView at (0,0) size 800x600
-layer at (0,0) size 800x321
-  LayoutBlockFlow {HTML} at (0,0) size 800x321
-    LayoutBlockFlow {BODY} at (8,8) size 784x305
-      LayoutBlockFlow {DIV} at (0,0) size 784x305
+layer at (0,0) size 800x320
+  LayoutBlockFlow {HTML} at (0,0) size 800x320
+    LayoutBlockFlow {BODY} at (8,8) size 784x304
+      LayoutBlockFlow {DIV} at (0,0) size 784x304
         LayoutSVGRoot {svg} at (0,0) size 300x300
           LayoutSVGHiddenContainer {defs} at (0,0) size 0x0
             LayoutSVGResourceFilter {filter} [id="filter"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/custom/foreign-object-skew-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/svg/custom/foreign-object-skew-expected.txt
index 5eb41914..c331aad 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/custom/foreign-object-skew-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/custom/foreign-object-skew-expected.txt
@@ -14,3 +14,15 @@
         LayoutButton {xhtml:input} at (0,18) size 16x18 [bgcolor=#FFFFFF]
         LayoutText {#text} at (0,0) size 0x0
     LayoutSVGRect {rect} at (10,10) size 580x380 [stroke={[type=SOLID] [color=#008000]}] [x=10.00] [y=10.00] [width=580.00] [height=380.00]
+layer at (10,10) size 580x380 backgroundClip at (54,55) size 746x545 clip at (54,55) size 536x335
+  LayoutSVGForeignObject {foreignObject} at (10,10) size 580x380
+    LayoutBlockFlow {xhtml:div} at (0,0) size 580x18
+      LayoutText {#text} at (0,0) size 81x18
+        text run at (0,0) width 81: "This is a test"
+    LayoutBlockFlow (anonymous) at (0,18) size 580x37
+      LayoutInline {xhtml:a} at (0,0) size 68x18 [color=#0000EE]
+        LayoutText {#text} at (0,0) size 68x18
+          text run at (0,0) width 68: "and a link."
+      LayoutBR {xhtml:br} at (67,0) size 1x18
+      LayoutButton {xhtml:input} at (0,18) size 16x18 [bgcolor=#FFFFFF]
+      LayoutText {#text} at (0,0) size 0x0
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/custom/use-on-disallowed-foreign-object-1-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/svg/custom/use-on-disallowed-foreign-object-1-expected.txt
index 72339e2..eda46c63 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/custom/use-on-disallowed-foreign-object-1-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/custom/use-on-disallowed-foreign-object-1-expected.txt
@@ -7,3 +7,8 @@
         LayoutText {#text} at (0,0) size 245x18
           text run at (0,0) width 245: "You should only see this string ONCE"
     LayoutSVGContainer {use} at (0,0) size 0x0 [transform={m=((0.71,0.71)(-0.71,0.71)) t=(250.00,-35.86)}]
+layer at (10,10) size 480x360 backgroundClip at (54,55) size 746x545 clip at (54,55) size 436x315
+  LayoutSVGForeignObject {foreignObject} at (10,10) size 480x360
+    LayoutBlockFlow {xhtml:div} at (0,0) size 480x18
+      LayoutText {#text} at (0,0) size 245x18
+        text run at (0,0) width 245: "You should only see this string ONCE"
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/custom/use-on-disallowed-foreign-object-2-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/svg/custom/use-on-disallowed-foreign-object-2-expected.txt
index 541b5424..d9e6d8e 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/custom/use-on-disallowed-foreign-object-2-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/custom/use-on-disallowed-foreign-object-2-expected.txt
@@ -11,3 +11,8 @@
     LayoutSVGContainer {use} at (0,0) size 0x0 [transform={m=((0.71,0.71)(-0.71,0.71)) t=(250.00,-35.86)}]
       LayoutSVGContainer {g} at (0,0) size 0x0
         LayoutSVGContainer {g} at (0,0) size 0x0
+layer at (10,10) size 580x380 backgroundClip at (54,55) size 746x545 clip at (54,55) size 536x335
+  LayoutSVGForeignObject {foreignObject} at (10,10) size 580x380
+    LayoutBlockFlow {xhtml:div} at (0,0) size 580x18
+      LayoutText {#text} at (0,0) size 245x18
+        text run at (0,0) width 245: "You should only see this string ONCE"
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/custom/use-on-disallowed-foreign-object-3-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/svg/custom/use-on-disallowed-foreign-object-3-expected.txt
index c655e0b..6910e316 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/custom/use-on-disallowed-foreign-object-3-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/custom/use-on-disallowed-foreign-object-3-expected.txt
@@ -8,3 +8,8 @@
           text run at (0,0) width 245: "You should only see this string ONCE"
     LayoutSVGContainer {use} at (0,0) size 0x0 [transform={m=((0.71,0.71)(-0.71,0.71)) t=(250.00,-35.86)}]
     LayoutSVGContainer {use} at (0,0) size 0x0 [transform={m=((0.71,0.71)(-0.71,0.71)) t=(250.00,-35.86)}]
+layer at (10,10) size 580x380 backgroundClip at (54,55) size 746x545 clip at (54,55) size 536x335
+  LayoutSVGForeignObject {foreignObject} at (10,10) size 580x380
+    LayoutBlockFlow {xhtml:div} at (0,0) size 580x18
+      LayoutText {#text} at (0,0) size 245x18
+        text run at (0,0) width 245: "You should only see this string ONCE"
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/custom/use-on-disallowed-foreign-object-4-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/svg/custom/use-on-disallowed-foreign-object-4-expected.txt
index 8f1d3ce..ea7f316 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/custom/use-on-disallowed-foreign-object-4-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/custom/use-on-disallowed-foreign-object-4-expected.txt
@@ -15,3 +15,8 @@
       LayoutSVGContainer {g} at (0,0) size 0x0 [transform={m=((0.71,0.71)(-0.71,0.71)) t=(250.00,-35.86)}]
         LayoutSVGContainer {g} at (0,0) size 0x0
           LayoutSVGContainer {g} at (0,0) size 0x0
+layer at (10,10) size 580x380 backgroundClip at (54,55) size 746x545 clip at (54,55) size 536x335
+  LayoutSVGForeignObject {foreignObject} at (10,10) size 580x380
+    LayoutBlockFlow {xhtml:div} at (0,0) size 580x18
+      LayoutText {#text} at (0,0) size 245x18
+        text run at (0,0) width 245: "You should only see this string ONCE"
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/custom/use-on-disallowed-foreign-object-5-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/svg/custom/use-on-disallowed-foreign-object-5-expected.txt
index db05588..2116a43 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/custom/use-on-disallowed-foreign-object-5-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/custom/use-on-disallowed-foreign-object-5-expected.txt
@@ -13,3 +13,8 @@
     LayoutSVGContainer {use} at (0,0) size 0x0 [transform={m=((1.00,0.00)(0.00,1.00)) t=(10.00,10.00)}]
       LayoutSVGContainer {g} at (0,0) size 0x0 [transform={m=((1.00,0.00)(0.00,1.00)) t=(25.00,25.00)}]
         LayoutSVGViewportContainer {svg} at (0,0) size 0x0
+layer at (10,10) size 580x380 backgroundClip at (54,55) size 746x545 clip at (54,55) size 536x335
+  LayoutSVGForeignObject {foreignObject} at (10,10) size 580x380
+    LayoutBlockFlow {xhtml:div} at (0,0) size 580x18
+      LayoutText {#text} at (0,0) size 245x18
+        text run at (0,0) width 245: "You should only see this string ONCE"
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/custom/use-on-disallowed-foreign-object-6-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/svg/custom/use-on-disallowed-foreign-object-6-expected.txt
index 792e891..df266a0 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/custom/use-on-disallowed-foreign-object-6-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/custom/use-on-disallowed-foreign-object-6-expected.txt
@@ -13,3 +13,8 @@
     LayoutSVGContainer {use} at (0,0) size 0x0 [transform={m=((1.00,0.00)(0.00,1.00)) t=(10.00,10.00)}]
       LayoutSVGContainer {g} at (0,0) size 0x0 [transform={m=((1.00,0.00)(0.00,1.00)) t=(25.00,25.00)}]
         LayoutSVGViewportContainer {svg} at (0,0) size 0x0
+layer at (10,10) size 580x380 backgroundClip at (54,55) size 746x545 clip at (54,55) size 536x335
+  LayoutSVGForeignObject {foreignObject} at (10,10) size 580x380
+    LayoutBlockFlow {xhtml:div} at (0,0) size 580x18
+      LayoutText {#text} at (0,0) size 245x18
+        text run at (0,0) width 245: "You should only see this string ONCE"
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/custom/use-on-non-svg-namespaced-element-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/svg/custom/use-on-non-svg-namespaced-element-expected.txt
index 72339e2..eda46c63 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/custom/use-on-non-svg-namespaced-element-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/custom/use-on-non-svg-namespaced-element-expected.txt
@@ -7,3 +7,8 @@
         LayoutText {#text} at (0,0) size 245x18
           text run at (0,0) width 245: "You should only see this string ONCE"
     LayoutSVGContainer {use} at (0,0) size 0x0 [transform={m=((0.71,0.71)(-0.71,0.71)) t=(250.00,-35.86)}]
+layer at (10,10) size 480x360 backgroundClip at (54,55) size 746x545 clip at (54,55) size 436x315
+  LayoutSVGForeignObject {foreignObject} at (10,10) size 480x360
+    LayoutBlockFlow {xhtml:div} at (0,0) size 480x18
+      LayoutText {#text} at (0,0) size 245x18
+        text run at (0,0) width 245: "You should only see this string ONCE"
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/filters/feBlend-all-modes-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/svg/filters/feBlend-all-modes-expected.txt
similarity index 94%
rename from third_party/WebKit/LayoutTests/platform/win/svg/filters/feBlend-all-modes-expected.txt
rename to third_party/WebKit/LayoutTests/platform/mac/svg/filters/feBlend-all-modes-expected.txt
index 012b8c4f..9e928b6 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/filters/feBlend-all-modes-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/filters/feBlend-all-modes-expected.txt
@@ -1,9 +1,9 @@
 layer at (0,0) size 800x600
   LayoutView at (0,0) size 800x600
-layer at (0,0) size 800x346
-  LayoutBlockFlow {HTML} at (0,0) size 800x346
-    LayoutBlockFlow {BODY} at (8,8) size 784x330
-      LayoutBlockFlow {DIV} at (0,0) size 400x110
+layer at (0,0) size 800x340
+  LayoutBlockFlow {HTML} at (0,0) size 800x340
+    LayoutBlockFlow {BODY} at (8,8) size 784x324
+      LayoutBlockFlow {DIV} at (0,0) size 400x108
         LayoutSVGRoot {svg} at (0,0) size 50x50
           LayoutSVGResourceFilter {filter} [id="f_normal0"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="normal"]
@@ -60,63 +60,63 @@
               [feFlood flood-color="#00FF00" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
             [filter="f_color-burn0"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
-        LayoutSVGRoot {svg} at (0,55) size 50x50
+        LayoutSVGRoot {svg} at (0,54) size 50x50
           LayoutSVGResourceFilter {filter} [id="f_hard-light0"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="hard-light"]
               [feFlood flood-color="#FF0000" flood-opacity="1.00"]
               [feFlood flood-color="#00FF00" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
             [filter="f_hard-light0"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
-        LayoutSVGRoot {svg} at (50,55) size 50x50
+        LayoutSVGRoot {svg} at (50,54) size 50x50
           LayoutSVGResourceFilter {filter} [id="f_soft-light0"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="soft-light"]
               [feFlood flood-color="#FF0000" flood-opacity="1.00"]
               [feFlood flood-color="#00FF00" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
             [filter="f_soft-light0"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
-        LayoutSVGRoot {svg} at (100,55) size 50x50
+        LayoutSVGRoot {svg} at (100,54) size 50x50
           LayoutSVGResourceFilter {filter} [id="f_difference0"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="difference"]
               [feFlood flood-color="#FF0000" flood-opacity="1.00"]
               [feFlood flood-color="#00FF00" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
             [filter="f_difference0"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
-        LayoutSVGRoot {svg} at (150,55) size 50x50
+        LayoutSVGRoot {svg} at (150,54) size 50x50
           LayoutSVGResourceFilter {filter} [id="f_exclusion0"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="exclusion"]
               [feFlood flood-color="#FF0000" flood-opacity="1.00"]
               [feFlood flood-color="#00FF00" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
             [filter="f_exclusion0"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
-        LayoutSVGRoot {svg} at (200,55) size 50x50
+        LayoutSVGRoot {svg} at (200,54) size 50x50
           LayoutSVGResourceFilter {filter} [id="f_hue0"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="hue"]
               [feFlood flood-color="#FF0000" flood-opacity="1.00"]
               [feFlood flood-color="#00FF00" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
             [filter="f_hue0"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
-        LayoutSVGRoot {svg} at (250,55) size 50x50
+        LayoutSVGRoot {svg} at (250,54) size 50x50
           LayoutSVGResourceFilter {filter} [id="f_saturation0"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="saturation"]
               [feFlood flood-color="#FF0000" flood-opacity="1.00"]
               [feFlood flood-color="#00FF00" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
             [filter="f_saturation0"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
-        LayoutSVGRoot {svg} at (300,55) size 50x50
+        LayoutSVGRoot {svg} at (300,54) size 50x50
           LayoutSVGResourceFilter {filter} [id="f_color0"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="color"]
               [feFlood flood-color="#FF0000" flood-opacity="1.00"]
               [feFlood flood-color="#00FF00" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
             [filter="f_color0"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
-        LayoutSVGRoot {svg} at (350,55) size 50x50
+        LayoutSVGRoot {svg} at (350,54) size 50x50
           LayoutSVGResourceFilter {filter} [id="f_luminosity0"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="luminosity"]
               [feFlood flood-color="#FF0000" flood-opacity="1.00"]
               [feFlood flood-color="#00FF00" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
             [filter="f_luminosity0"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
-      LayoutBlockFlow {DIV} at (0,110) size 400x110
+      LayoutBlockFlow {DIV} at (0,108) size 400x108
         LayoutSVGRoot {svg} at (0,0) size 50x50
           LayoutSVGResourceFilter {filter} [id="f_normal1"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="normal"]
@@ -173,63 +173,63 @@
               [feFlood flood-color="#99C066" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
             [filter="f_color-burn1"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
-        LayoutSVGRoot {svg} at (0,55) size 50x50
+        LayoutSVGRoot {svg} at (0,54) size 50x50
           LayoutSVGResourceFilter {filter} [id="f_hard-light1"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="hard-light"]
               [feFlood flood-color="#3340CC" flood-opacity="1.00"]
               [feFlood flood-color="#99C066" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
             [filter="f_hard-light1"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
-        LayoutSVGRoot {svg} at (50,55) size 50x50
+        LayoutSVGRoot {svg} at (50,54) size 50x50
           LayoutSVGResourceFilter {filter} [id="f_soft-light1"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="soft-light"]
               [feFlood flood-color="#3340CC" flood-opacity="1.00"]
               [feFlood flood-color="#99C066" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
             [filter="f_soft-light1"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
-        LayoutSVGRoot {svg} at (100,55) size 50x50
+        LayoutSVGRoot {svg} at (100,54) size 50x50
           LayoutSVGResourceFilter {filter} [id="f_difference1"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="difference"]
               [feFlood flood-color="#3340CC" flood-opacity="1.00"]
               [feFlood flood-color="#99C066" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
             [filter="f_difference1"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
-        LayoutSVGRoot {svg} at (150,55) size 50x50
+        LayoutSVGRoot {svg} at (150,54) size 50x50
           LayoutSVGResourceFilter {filter} [id="f_exclusion1"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="exclusion"]
               [feFlood flood-color="#3340CC" flood-opacity="1.00"]
               [feFlood flood-color="#99C066" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
             [filter="f_exclusion1"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
-        LayoutSVGRoot {svg} at (200,55) size 50x50
+        LayoutSVGRoot {svg} at (200,54) size 50x50
           LayoutSVGResourceFilter {filter} [id="f_hue1"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="hue"]
               [feFlood flood-color="#3340CC" flood-opacity="1.00"]
               [feFlood flood-color="#99C066" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
             [filter="f_hue1"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
-        LayoutSVGRoot {svg} at (250,55) size 50x50
+        LayoutSVGRoot {svg} at (250,54) size 50x50
           LayoutSVGResourceFilter {filter} [id="f_saturation1"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="saturation"]
               [feFlood flood-color="#3340CC" flood-opacity="1.00"]
               [feFlood flood-color="#99C066" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
             [filter="f_saturation1"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
-        LayoutSVGRoot {svg} at (300,55) size 50x50
+        LayoutSVGRoot {svg} at (300,54) size 50x50
           LayoutSVGResourceFilter {filter} [id="f_color1"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="color"]
               [feFlood flood-color="#3340CC" flood-opacity="1.00"]
               [feFlood flood-color="#99C066" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
             [filter="f_color1"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
-        LayoutSVGRoot {svg} at (350,55) size 50x50
+        LayoutSVGRoot {svg} at (350,54) size 50x50
           LayoutSVGResourceFilter {filter} [id="f_luminosity1"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="luminosity"]
               [feFlood flood-color="#3340CC" flood-opacity="1.00"]
               [feFlood flood-color="#99C066" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
             [filter="f_luminosity1"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
-      LayoutBlockFlow {DIV} at (0,220) size 400x110
+      LayoutBlockFlow {DIV} at (0,216) size 400x108
         LayoutSVGRoot {svg} at (0,0) size 50x50
           LayoutSVGResourceFilter {filter} [id="f_normal2"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="normal"]
@@ -286,56 +286,56 @@
               [feFlood flood-color="#99C06680" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
             [filter="f_color-burn2"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
-        LayoutSVGRoot {svg} at (0,55) size 50x50
+        LayoutSVGRoot {svg} at (0,54) size 50x50
           LayoutSVGResourceFilter {filter} [id="f_hard-light2"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="hard-light"]
               [feFlood flood-color="#3340CC80" flood-opacity="1.00"]
               [feFlood flood-color="#99C06680" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
             [filter="f_hard-light2"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
-        LayoutSVGRoot {svg} at (50,55) size 50x50
+        LayoutSVGRoot {svg} at (50,54) size 50x50
           LayoutSVGResourceFilter {filter} [id="f_soft-light2"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="soft-light"]
               [feFlood flood-color="#3340CC80" flood-opacity="1.00"]
               [feFlood flood-color="#99C06680" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
             [filter="f_soft-light2"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
-        LayoutSVGRoot {svg} at (100,55) size 50x50
+        LayoutSVGRoot {svg} at (100,54) size 50x50
           LayoutSVGResourceFilter {filter} [id="f_difference2"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="difference"]
               [feFlood flood-color="#3340CC80" flood-opacity="1.00"]
               [feFlood flood-color="#99C06680" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
             [filter="f_difference2"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
-        LayoutSVGRoot {svg} at (150,55) size 50x50
+        LayoutSVGRoot {svg} at (150,54) size 50x50
           LayoutSVGResourceFilter {filter} [id="f_exclusion2"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="exclusion"]
               [feFlood flood-color="#3340CC80" flood-opacity="1.00"]
               [feFlood flood-color="#99C06680" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
             [filter="f_exclusion2"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
-        LayoutSVGRoot {svg} at (200,55) size 50x50
+        LayoutSVGRoot {svg} at (200,54) size 50x50
           LayoutSVGResourceFilter {filter} [id="f_hue2"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="hue"]
               [feFlood flood-color="#3340CC80" flood-opacity="1.00"]
               [feFlood flood-color="#99C06680" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
             [filter="f_hue2"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
-        LayoutSVGRoot {svg} at (250,55) size 50x50
+        LayoutSVGRoot {svg} at (250,54) size 50x50
           LayoutSVGResourceFilter {filter} [id="f_saturation2"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="saturation"]
               [feFlood flood-color="#3340CC80" flood-opacity="1.00"]
               [feFlood flood-color="#99C06680" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
             [filter="f_saturation2"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
-        LayoutSVGRoot {svg} at (300,55) size 50x50
+        LayoutSVGRoot {svg} at (300,54) size 50x50
           LayoutSVGResourceFilter {filter} [id="f_color2"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="color"]
               [feFlood flood-color="#3340CC80" flood-opacity="1.00"]
               [feFlood flood-color="#99C06680" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
             [filter="f_color2"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
-        LayoutSVGRoot {svg} at (350,55) size 50x50
+        LayoutSVGRoot {svg} at (350,54) size 50x50
           LayoutSVGResourceFilter {filter} [id="f_luminosity2"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="luminosity"]
               [feFlood flood-color="#3340CC80" flood-opacity="1.00"]
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/foreignObject/fO-parent-display-changes-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/svg/foreignObject/fO-parent-display-changes-expected.txt
index eeac7e54..0365c4b2a 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/foreignObject/fO-parent-display-changes-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/foreignObject/fO-parent-display-changes-expected.txt
@@ -9,3 +9,9 @@
           LayoutBlockFlow {body} at (0,0) size 100x100 [color=#FFFFFF]
             LayoutText {#text} at (0,0) size 37x18
               text run at (0,0) width 37: "PASS"
+layer at (0,0) size 100x90 scrollHeight 100
+  LayoutSVGForeignObject {foreignObject} at (0,0) size 100x90
+    LayoutBlockFlow {html} at (0,0) size 100x100
+      LayoutBlockFlow {body} at (0,0) size 100x100 [color=#FFFFFF]
+        LayoutText {#text} at (0,0) size 37x18
+          text run at (0,0) width 37: "PASS"
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/foreignObject/no-crash-with-svg-content-in-html-document-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/svg/foreignObject/no-crash-with-svg-content-in-html-document-expected.txt
index 3d6882b..9056e703 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/foreignObject/no-crash-with-svg-content-in-html-document-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/foreignObject/no-crash-with-svg-content-in-html-document-expected.txt
@@ -10,3 +10,12 @@
         LayoutBlockFlow (anonymous) at (0,18) size 300x0
           LayoutInline {g} at (0,0) size 0x0
           LayoutText {#text} at (0,0) size 0x0
+layer at (0,0) size 300x100
+  LayoutSVGForeignObject {foreignObject} at (0,0) size 300x100
+    LayoutBlockFlow {html} at (0,0) size 300x18
+      LayoutBlockFlow {p} at (0,0) size 300x18
+        LayoutText {#text} at (0,0) size 138x18
+          text run at (0,0) width 138: "This should not crash"
+      LayoutBlockFlow (anonymous) at (0,18) size 300x0
+        LayoutInline {g} at (0,0) size 0x0
+        LayoutText {#text} at (0,0) size 0x0
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/foreignObject/svg-document-as-direct-child-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/svg/foreignObject/svg-document-as-direct-child-expected.txt
index 9a95304..e69197c 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/foreignObject/svg-document-as-direct-child-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/foreignObject/svg-document-as-direct-child-expected.txt
@@ -17,3 +17,21 @@
       LayoutSVGRoot {svg} at (0,0) size 300x150
         LayoutSVGRect {rect} at (0,0) size 100x100 [fill={[type=SOLID] [color=#008000]}] [x=0.00] [y=0.00] [width=100.00] [height=100.00]
       LayoutText {#text} at (0,0) size 0x0
+layer at (0,0) size 300x100 scrollHeight 154
+  LayoutSVGForeignObject {foreignObject} at (0,0) size 300x100
+    LayoutSVGRoot {svg} at (0,0) size 300x150
+      LayoutSVGContainer {g} at (0,6) size 33.75x18
+        LayoutSVGText {text} at (0,6) size 33.75x18 contains 1 chunk(s)
+          LayoutSVGInlineText {#text} at (0,6) size 33.75x18
+            chunk 1 text run 1 at (0.00,20.00) startOffset 0 endOffset 5 width 33.76: "crash"
+    LayoutText {#text} at (0,0) size 0x0
+layer at (0,50) size 300x100 scrollHeight 154
+  LayoutSVGForeignObject {foreignObject} at (0,50) size 300x100
+    LayoutSVGRoot {svg} at (0,0) size 300x150
+      LayoutSVGRect {rect} at (0,0) size 100x100 [fill={[type=SOLID] [color=#008000]}] [x=0.00] [y=0.00] [width=100.00] [height=100.00]
+    LayoutText {#text} at (0,0) size 0x0
+layer at (0,150) size 300x100 scrollHeight 154
+  LayoutSVGForeignObject {foreignObject} at (0,150) size 300x100
+    LayoutSVGRoot {svg} at (0,0) size 300x150
+      LayoutSVGRect {rect} at (0,0) size 100x100 [fill={[type=SOLID] [color=#008000]}] [x=0.00] [y=0.00] [width=100.00] [height=100.00]
+    LayoutText {#text} at (0,0) size 0x0
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/foreignObject/svg-document-in-html-document-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/svg/foreignObject/svg-document-in-html-document-expected.txt
index 452b52d..29a4400 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/foreignObject/svg-document-in-html-document-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/foreignObject/svg-document-in-html-document-expected.txt
@@ -14,3 +14,16 @@
               LayoutSVGInlineText {#text} at (0,36) size 272.63x18
                 chunk 1 text run 1 at (0.00,50.00) startOffset 0 endOffset 38 width 272.61: "Test from SVG in HTML in foreignObject"
           LayoutText {#text} at (0,0) size 0x0
+layer at (0,0) size 300x100 scrollHeight 188
+  LayoutSVGForeignObject {foreignObject} at (0,0) size 300x100
+    LayoutBlockFlow {html} at (0,0) size 300x188
+      LayoutBlockFlow {p} at (0,0) size 300x18
+        LayoutText {#text} at (0,0) size 221x18
+          text run at (0,0) width 221: "Test from HTML in foreignObject"
+      LayoutBlockFlow (anonymous) at (0,34) size 300x154
+        LayoutSVGRoot {svg} at (0,0) size 300x150
+          LayoutSVGRect {rect} at (0,0) size 20x20 [fill={[type=SOLID] [color=#008000]}] [x=0.00] [y=0.00] [width=20.00] [height=20.00]
+          LayoutSVGText {text} at (0,36) size 272.63x18 contains 1 chunk(s)
+            LayoutSVGInlineText {#text} at (0,36) size 272.63x18
+              chunk 1 text run 1 at (0.00,50.00) startOffset 0 endOffset 38 width 272.61: "Test from SVG in HTML in foreignObject"
+        LayoutText {#text} at (0,0) size 0x0
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/hixie/mixed/004-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/svg/hixie/mixed/004-expected.txt
similarity index 76%
rename from third_party/WebKit/LayoutTests/platform/linux/svg/hixie/mixed/004-expected.txt
rename to third_party/WebKit/LayoutTests/platform/mac/svg/hixie/mixed/004-expected.txt
index 6892ace..72300e0 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/hixie/mixed/004-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/hixie/mixed/004-expected.txt
@@ -1,8 +1,8 @@
 layer at (0,0) size 800x600
   LayoutView at (0,0) size 800x600
-layer at (0,0) size 800x221
-  LayoutBlockFlow {html} at (0,0) size 800x221
-    LayoutBlockFlow {body} at (8,8) size 784x205
+layer at (0,0) size 800x220
+  LayoutBlockFlow {html} at (0,0) size 800x220
+    LayoutBlockFlow {body} at (8,8) size 784x204
       LayoutSVGRoot {svg} at (0,0) size 200x200
         LayoutSVGEllipse {circle} at (0,0) size 100x100 [fill={[type=SOLID] [color=#FF0000]}] [cx=50.00] [cy=50.00] [r=50.00]
         LayoutSVGEllipse {circle} at (0,0) size 100x100 [fill={[type=SOLID] [color=#008000]}] [cx=50.00] [cy=50.00] [r=50.00]
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/hixie/mixed/004-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/svg/hixie/mixed/005-expected.txt
similarity index 76%
copy from third_party/WebKit/LayoutTests/platform/linux/svg/hixie/mixed/004-expected.txt
copy to third_party/WebKit/LayoutTests/platform/mac/svg/hixie/mixed/005-expected.txt
index 6892ace..72300e0 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/hixie/mixed/004-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/hixie/mixed/005-expected.txt
@@ -1,8 +1,8 @@
 layer at (0,0) size 800x600
   LayoutView at (0,0) size 800x600
-layer at (0,0) size 800x221
-  LayoutBlockFlow {html} at (0,0) size 800x221
-    LayoutBlockFlow {body} at (8,8) size 784x205
+layer at (0,0) size 800x220
+  LayoutBlockFlow {html} at (0,0) size 800x220
+    LayoutBlockFlow {body} at (8,8) size 784x204
       LayoutSVGRoot {svg} at (0,0) size 200x200
         LayoutSVGEllipse {circle} at (0,0) size 100x100 [fill={[type=SOLID] [color=#FF0000]}] [cx=50.00] [cy=50.00] [r=50.00]
         LayoutSVGEllipse {circle} at (0,0) size 100x100 [fill={[type=SOLID] [color=#008000]}] [cx=50.00] [cy=50.00] [r=50.00]
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/hixie/mixed/006-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/svg/hixie/mixed/006-expected.txt
index ff39b109..897b277 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/hixie/mixed/006-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/hixie/mixed/006-expected.txt
@@ -13,6 +13,8 @@
       text run at (0,0) width 194: "There should be a green circle"
       text run at (0,18) width 164: "below with no red on this"
       text run at (0,36) width 35: "page."
+layer at (8,208) size 200x200
+  LayoutSVGForeignObject {foreignObject} at (0,0) size 200x200
 layer at (8,8) size 200x200 backgroundClip at (8,208) size 200x200 clip at (8,208) size 200x200
   LayoutBlockFlow (positioned) {div} at (0,-200) size 200x200 [color=#FFFF00] [bgcolor=#FF0000]
     LayoutText {#text} at (0,0) size 35x18
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/hixie/mixed/007-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/svg/hixie/mixed/007-expected.txt
index 2ca81a7..5376d2f1 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/hixie/mixed/007-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/hixie/mixed/007-expected.txt
@@ -6,3 +6,8 @@
       LayoutBlockFlow {p} at (0,0) size 400x18
         LayoutText {#text} at (0,0) size 37x18
           text run at (0,0) width 37: "PASS"
+layer at (0,0) size 400x400
+  LayoutSVGForeignObject {foreignObject} at (0,0) size 400x400
+    LayoutBlockFlow {p} at (0,0) size 400x18
+      LayoutText {#text} at (0,0) size 37x18
+        text run at (0,0) width 37: "PASS"
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/hixie/mixed/008-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/svg/hixie/mixed/008-expected.txt
index d691b5d..211a5f38 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/hixie/mixed/008-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/hixie/mixed/008-expected.txt
@@ -15,3 +15,8 @@
               LayoutText {#text} at (140,0) size 120x59
                 text run at (140,0) width 120: "TEST"
         LayoutText {#text} at (0,0) size 0x0
+layer at (8,225) size 400x50 scrollHeight 59
+  LayoutSVGForeignObject {foreignObject} at (0,175) size 400x50 [color=#FFFFFF]
+    LayoutBlockFlow {div} at (0,0) size 400x59
+      LayoutText {#text} at (140,0) size 120x59
+        text run at (140,0) width 120: "TEST"
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/hixie/mixed/009-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/svg/hixie/mixed/009-expected.txt
index 1b3b8b99..874fe59f 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/hixie/mixed/009-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/hixie/mixed/009-expected.txt
@@ -17,3 +17,8 @@
       LayoutBlockFlow {div} at (0,142) size 400x120 [color=#000080] [bgcolor=#EEEEEE]
         LayoutText {#text} at (0,0) size 239x115
           text run at (0,0) width 239: "TEST"
+layer at (8,26) size 60x10 scrollHeight 13
+  LayoutSVGForeignObject {foreignObject} at (0,0) size 60x10
+    LayoutBlockFlow {div} at (0,0) size 60x13 [color=#000080]
+      LayoutText {#text} at (0,0) size 24x13
+        text run at (0,0) width 24: "TEST"
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/hixie/mixed/011-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/svg/hixie/mixed/011-expected.txt
index d1c74e4..61f6e69 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/hixie/mixed/011-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/hixie/mixed/011-expected.txt
@@ -7,7 +7,9 @@
         LayoutSVGEllipse {circle} at (50,50) size 100x100 [fill={[type=SOLID] [color=#008000]}] [cx=100.00] [cy=100.00] [r=50.00]
         LayoutSVGForeignObject {foreignObject} at (0,0) size 200x200
       LayoutText {#text} at (0,0) size 0x0
-layer at (50,0) size 150x200 backgroundClip at (0,8) size 149x283 clip at (0,8) size 149x283
+layer at (8,8) size 200x200 backgroundClip at (0,8) size 149x283 clip at (8,8) size 141x200
+  LayoutSVGForeignObject {foreignObject} at (0,0) size 200x200
+layer at (58,8) size 150x200 backgroundClip at (0,8) size 149x283 clip at (0,8) size 149x283
   LayoutBlockFlow (positioned) {div} at (50,0) size 150x200
     LayoutText {#text} at (0,0) size 139x72
       text run at (0,0) width 115: "There should be a"
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/hixie/perf/007-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/hixie/perf/007-expected.png
index 55388e84..3090a0ab 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/hixie/perf/007-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/hixie/perf/007-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/stroke/empty-path-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/svg/stroke/empty-path-expected.txt
similarity index 66%
rename from third_party/WebKit/LayoutTests/platform/win/svg/stroke/empty-path-expected.txt
rename to third_party/WebKit/LayoutTests/platform/mac/svg/stroke/empty-path-expected.txt
index 215c7adcd..609dbebe 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/stroke/empty-path-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/stroke/empty-path-expected.txt
@@ -1,8 +1,8 @@
 layer at (0,0) size 800x600
   LayoutView at (0,0) size 800x600
-layer at (0,0) size 800x121
-  LayoutBlockFlow {HTML} at (0,0) size 800x121
-    LayoutBlockFlow {BODY} at (8,8) size 784x105
+layer at (0,0) size 800x120
+  LayoutBlockFlow {HTML} at (0,0) size 800x120
+    LayoutBlockFlow {BODY} at (8,8) size 784x104
       LayoutSVGRoot {svg} at (0,0) size 100x100
         LayoutSVGPath {path} at (0,0) size 0x0 [fill={[type=SOLID] [color=#000000]}] [data=""]
       LayoutText {#text} at (0,0) size 0x0
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/text/foreignObject-repaint-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/svg/text/foreignObject-repaint-expected.txt
index 9e83e80..e9a4a3e 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/text/foreignObject-repaint-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/text/foreignObject-repaint-expected.txt
@@ -8,3 +8,10 @@
           text run at (0,0) width 490: "Select this text using"
           text run at (0,61) width 478: "the mouse, it should"
           text run at (0,122) width 338: "not disappear!"
+layer at (100,100) size 500x300
+  LayoutSVGForeignObject {foreignObject} at (100,100) size 500x300
+    LayoutBlockFlow {div} at (0,0) size 500x183
+      LayoutText {#text} at (0,0) size 490x183
+        text run at (0,0) width 490: "Select this text using"
+        text run at (0,61) width 478: "the mouse, it should"
+        text run at (0,122) width 338: "not disappear!"
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/text/foreignObject-text-clipping-bug-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/svg/text/foreignObject-text-clipping-bug-expected.txt
index 11fa6914..f776e9a3 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/text/foreignObject-text-clipping-bug-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/text/foreignObject-text-clipping-bug-expected.txt
@@ -14,6 +14,11 @@
               LayoutText {#text} at (0,0) size 24x13
                 text run at (0,0) width 24: "TEST"
         LayoutText {#text} at (0,0) size 0x0
+layer at (9,27) size 60x10 backgroundClip at (18,36) size 390x100 clip at (18,36) size 51x1 scrollHeight 13
+  LayoutSVGForeignObject {foreignObject} at (1,1) size 60x10
+    LayoutBlockFlow {div} at (0,0) size 60x13 [color=#000080]
+      LayoutText {#text} at (0,0) size 24x13
+        text run at (0,0) width 24: "TEST"
 layer at (18,160) size 390x110
   LayoutBlockFlow (relative positioned) {div} at (0,142) size 390x110 [color=#000080] [bgcolor=#D3D3D3]
     LayoutBlockFlow {div} at (0,0) size 390x115
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/zoom/page/zoom-foreignObject-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/zoom/page/zoom-foreignObject-expected.png
index c9405381..be6ed89 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/zoom/page/zoom-foreignObject-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/zoom/page/zoom-foreignObject-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/zoom/page/zoom-foreignObject-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/svg/zoom/page/zoom-foreignObject-expected.txt
index 7f3d4c40..785215d 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/zoom/page/zoom-foreignObject-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/zoom/page/zoom-foreignObject-expected.txt
@@ -31,3 +31,31 @@
       LayoutText {#text} at (0,0) size 0x0
     LayoutSVGRect {rect} at (260,0) size 250x200 [stroke={[type=SOLID] [color=#008000]}] [x=260.00] [y=0.00] [width=250.00] [height=200.00]
     LayoutSVGHiddenContainer {defs} at (0,0) size 0x0
+layer at (0,0) size 250x200
+  LayoutSVGForeignObject {foreignObject} at (0,0) size 250x200
+    LayoutBlockFlow {xhtml:div} at (0,0) size 250x18
+      LayoutText {#text} at (0,0) size 83x18
+        text run at (0,0) width 83: "This is a text"
+    LayoutBlockFlow (anonymous) at (0,18) size 250x18
+      LayoutInline {xhtml:a} at (0,0) size 68x18 [color=#0000EE]
+        LayoutText {#text} at (0,0) size 68x18
+          text run at (0,0) width 68: "and a link."
+      LayoutBR {xhtml:br} at (67,0) size 1x18
+    LayoutBlockFlow {xhtml:div} at (0,36) size 250x18
+      LayoutText {#text} at (0,0) size 56x18
+        text run at (0,0) width 56: "[HTML]"
+layer at (260,0) size 250x200 backgroundClip at (374,0) size 360x288 clip at (374,0) size 136x200 scrollHeight 204
+  LayoutSVGForeignObject {foreignObject} at (260,0) size 250x200
+    LayoutSVGRoot {svg} at (0,0) size 250x200
+      LayoutSVGContainer {g} at (0,1.77) size 82.20x58.19 [transform={m=((3.00,0.26)(0.26,3.02)) t=(0.00,0.00)}]
+        LayoutSVGText {text} at (0,1.77) size 82.20x18.19 contains 1 chunk(s)
+          LayoutSVGInlineText {#text} at (0,1.77) size 82.20x18.19
+            chunk 1 text run 1 at (0.00,16.00) startOffset 0 endOffset 14 width 82.20: "This is a text"
+        LayoutSVGContainer {a} at (0,20.77) size 67.08x18.19
+          LayoutSVGText {text} at (0,20.77) size 67.08x18.19 contains 1 chunk(s)
+            LayoutSVGInlineText {#text} at (0,20.77) size 67.08x18.19
+              chunk 1 text run 1 at (0.00,35.00) startOffset 0 endOffset 11 width 67.08: "and a link."
+        LayoutSVGText {text} at (0,41.77) size 42.66x18.19 contains 1 chunk(s)
+          LayoutSVGInlineText {#text} at (0,41.77) size 42.66x18.19
+            chunk 1 text run 1 at (0.00,56.00) startOffset 0 endOffset 5 width 42.66: "[SVG]"
+    LayoutText {#text} at (0,0) size 0x0
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/zoom/page/zoom-hixie-mixed-008-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/svg/zoom/page/zoom-hixie-mixed-008-expected.txt
index e45fbb5..ecb8f66 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/zoom/page/zoom-hixie-mixed-008-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/zoom/page/zoom-hixie-mixed-008-expected.txt
@@ -15,3 +15,8 @@
               LayoutText {#text} at (140,0) size 120x59
                 text run at (140,0) width 120: "TEST"
         LayoutText {#text} at (0,0) size 0x0
+layer at (12,247) size 400x50 backgroundClip at (12,324) size 576x72 clip at (0,0) size 0x0 scrollHeight 59
+  LayoutSVGForeignObject {foreignObject} at (0,175) size 400x50 [color=#FFFFFF]
+    LayoutBlockFlow {div} at (0,0) size 400x59
+      LayoutText {#text} at (140,0) size 120x59
+        text run at (140,0) width 120: "TEST"
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/zoom/page/zoom-hixie-mixed-009-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/svg/zoom/page/zoom-hixie-mixed-009-expected.txt
index af606b6a..24b0024 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/zoom/page/zoom-hixie-mixed-009-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/zoom/page/zoom-hixie-mixed-009-expected.txt
@@ -17,3 +17,8 @@
       LayoutBlockFlow {div} at (0,204.80) size 576x172.80 [color=#000080] [bgcolor=#EEEEEE]
         LayoutText {#text} at (0,0) size 344x166
           text run at (0,0) width 344: "TEST"
+layer at (12,38) size 60x10 scrollHeight 13
+  LayoutSVGForeignObject {foreignObject} at (0,0) size 60x10
+    LayoutBlockFlow {div} at (0,0) size 60x13 [color=#000080]
+      LayoutText {#text} at (0,0) size 24x13
+        text run at (0,0) width 24: "TEST"
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/zoom/text/zoom-hixie-mixed-008-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/svg/zoom/text/zoom-hixie-mixed-008-expected.txt
index 6e8d2a72..253b6f8 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/zoom/text/zoom-hixie-mixed-008-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/zoom/text/zoom-hixie-mixed-008-expected.txt
@@ -15,3 +15,8 @@
               LayoutText {#text} at (114,0) size 172x83
                 text run at (114,0) width 172: "TEST"
         LayoutText {#text} at (0,0) size 0x0
+layer at (8,247) size 400x50 scrollHeight 83
+  LayoutSVGForeignObject {foreignObject} at (0,175) size 400x50 [color=#FFFFFF]
+    LayoutBlockFlow {div} at (0,0) size 400x83
+      LayoutText {#text} at (114,0) size 172x83
+        text run at (114,0) width 172: "TEST"
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/zoom/text/zoom-hixie-mixed-009-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/svg/zoom/text/zoom-hixie-mixed-009-expected.txt
index 11e692d..d0b1db5e 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/zoom/text/zoom-hixie-mixed-009-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/zoom/text/zoom-hixie-mixed-009-expected.txt
@@ -17,3 +17,8 @@
       LayoutBlockFlow {div} at (0,152) size 400x120 [color=#000080] [bgcolor=#EEEEEE]
         LayoutText {#text} at (0,0) size 344x166
           text run at (0,0) width 344: "TEST"
+layer at (8,34) size 60x10 scrollHeight 17
+  LayoutSVGForeignObject {foreignObject} at (0,0) size 60x10
+    LayoutBlockFlow {div} at (0,0) size 60x17 [color=#000080]
+      LayoutText {#text} at (0,0) size 35x17
+        text run at (0,0) width 35: "TEST"
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/imagemap-focus-ring-outline-color-not-inherited-from-map-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/imagemap-focus-ring-outline-color-not-inherited-from-map-expected.png
index 3bcbeb9..b494c8b 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/imagemap-focus-ring-outline-color-not-inherited-from-map-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/imagemap-focus-ring-outline-color-not-inherited-from-map-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu/fast/canvas/canvas-composite-video-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu/fast/canvas/canvas-composite-video-expected.png
index 57aa718..c84d109 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu/fast/canvas/canvas-composite-video-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu/fast/canvas/canvas-composite-video-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu/fast/canvas/canvas-composite-video-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu/fast/canvas/canvas-composite-video-shadow-expected.png
index ec0a202..8a42b60 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu/fast/canvas/canvas-composite-video-shadow-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu/fast/canvas/canvas-composite-video-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/table/backgr_border-table-column-group-collapsed-border-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/table/backgr_border-table-column-group-collapsed-border-expected.png
index a7243c6..4dc67a4 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/table/backgr_border-table-column-group-collapsed-border-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/table/backgr_border-table-column-group-collapsed-border-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/svg/text-rescale-expected.txt b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/svg/text-rescale-expected.txt
index b99bf12..8dfdc54 100644
--- a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/svg/text-rescale-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/svg/text-rescale-expected.txt
@@ -19,12 +19,12 @@
       "paintInvalidations": [
         {
           "object": "InlineTextBox 'PASS '",
-          "rect": [0, 114, 301, 46],
+          "rect": [0, 114, 192, 46],
           "reason": "appeared"
         },
         {
           "object": "LayoutSVGRoot (positioned) svg",
-          "rect": [0, 14, 301, 46],
+          "rect": [0, 14, 192, 46],
           "reason": "appeared"
         },
         {
@@ -38,8 +38,18 @@
           "reason": "appeared"
         },
         {
+          "object": "LayoutSVGForeignObject foreignObject",
+          "rect": [210, 114, 91, 46],
+          "reason": "paint property change"
+        },
+        {
+          "object": "LayoutSVGForeignObject foreignObject",
+          "rect": [210, 14, 91, 46],
+          "reason": "paint property change"
+        },
+        {
           "object": "LayoutSVGContainer g id='text3g'",
-          "rect": [0, 3, 10, 2],
+          "rect": [0, 3, 8, 2],
           "reason": "disappeared"
         },
         {
@@ -48,9 +58,14 @@
           "reason": "paint property change"
         },
         {
-          "object": "LayoutSVGContainer g id='text1g'",
+          "object": "LayoutSVGForeignObject foreignObject",
+          "rect": [6, 3, 4, 2],
+          "reason": "paint property change"
+        },
+        {
+          "object": "LayoutSVGForeignObject foreignObject",
           "rect": [0, 0, 1, 1],
-          "reason": "disappeared"
+          "reason": "paint property change"
         }
       ]
     }
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/svg/zoom-foreignObject-expected.png b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/svg/zoom-foreignObject-expected.png
index 19ef50b..093fffa 100644
--- a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/svg/zoom-foreignObject-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/svg/zoom-foreignObject-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/animate-elem-82-t-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/animate-elem-82-t-expected.png
index 9b893f0..fa5ed25 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/animate-elem-82-t-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/animate-elem-82-t-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/as-background-image/svg-as-background-5-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/as-background-image/svg-as-background-5-expected.png
index 52d84b8..3bb285c 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/as-background-image/svg-as-background-5-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/as-background-image/svg-as-background-5-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/custom/dominant-baseline-hanging-expected.txt b/third_party/WebKit/LayoutTests/platform/win/svg/custom/dominant-baseline-hanging-expected.txt
index 0103d81..0bd17f7e 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/custom/dominant-baseline-hanging-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/custom/dominant-baseline-hanging-expected.txt
@@ -54,3 +54,43 @@
                 text run at (0,0) width 84: "Antoine Quint"
             LayoutText {#text} at (84,0) size 85x19
               text run at (84,0) width 85: ", January 27th"
+layer at (10,45) size 380x150 scrollHeight 168
+  LayoutSVGForeignObject {foreignObject} at (10,45) size 380x150
+    LayoutBlockFlow {html} at (0,16) size 380x136
+      LayoutBlockFlow {body} at (8,0) size 364x136
+        LayoutBlockFlow {p} at (0,0) size 364x100
+          LayoutText {#text} at (0,0) size 349x39
+            text run at (0,0) width 349: "The piece of text above should be aligned with the top-left"
+            text run at (0,20) width 250: "corner of the rectangle below it. Both the "
+          LayoutInline {code} at (0,0) size 48x16
+            LayoutText {#text} at (250,23) size 48x16
+              text run at (250,23) width 48: "<text>"
+          LayoutText {#text} at (298,20) size 48x19
+            text run at (298,20) width 48: " and the"
+          LayoutInline {code} at (0,0) size 48x16
+            LayoutText {#text} at (0,43) size 48x16
+              text run at (0,43) width 48: "<rect>"
+          LayoutText {#text} at (48,40) size 265x19
+            text run at (48,40) width 265: " are located at the same coordinates and the"
+          LayoutInline {code} at (0,0) size 48x16
+            LayoutText {#text} at (0,63) size 48x16
+              text run at (0,63) width 48: "<text>"
+          LayoutText {#text} at (48,60) size 106x19
+            text run at (48,60) width 106: " element uses the "
+          LayoutInline {code} at (0,0) size 56x16
+            LayoutText {#text} at (154,63) size 56x16
+              text run at (154,63) width 56: "hanging"
+          LayoutText {#text} at (210,60) size 77x19
+            text run at (210,60) width 77: " value for its "
+          LayoutInline {code} at (0,0) size 359x36
+            LayoutText {#text} at (287,63) size 359x36
+              text run at (287,63) width 72: "dominant-"
+              text run at (0,83) width 64: "baseline"
+          LayoutText {#text} at (64,80) size 57x19
+            text run at (64,80) width 57: " attribute."
+        LayoutBlockFlow {p} at (0,116) size 364x20
+          LayoutInline {a} at (0,0) size 84x19 [color=#800000]
+            LayoutText {#text} at (0,0) size 84x19
+              text run at (0,0) width 84: "Antoine Quint"
+          LayoutText {#text} at (84,0) size 85x19
+            text run at (84,0) width 85: ", January 27th"
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/custom/foreign-object-skew-expected.txt b/third_party/WebKit/LayoutTests/platform/win/svg/custom/foreign-object-skew-expected.txt
index 0bb2aee..9c78a72f 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/custom/foreign-object-skew-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/custom/foreign-object-skew-expected.txt
@@ -14,3 +14,15 @@
         LayoutButton {xhtml:input} at (0,20) size 16x22 [bgcolor=#C0C0C0] [border: (2px outset #C0C0C0)]
         LayoutText {#text} at (0,0) size 0x0
     LayoutSVGRect {rect} at (10,10) size 580x380 [stroke={[type=SOLID] [color=#008000]}] [x=10.00] [y=10.00] [width=580.00] [height=380.00]
+layer at (10,10) size 580x380 backgroundClip at (54,55) size 746x545 clip at (54,55) size 536x335
+  LayoutSVGForeignObject {foreignObject} at (10,10) size 580x380
+    LayoutBlockFlow {xhtml:div} at (0,0) size 580x20
+      LayoutText {#text} at (0,0) size 74x19
+        text run at (0,0) width 74: "This is a test"
+    LayoutBlockFlow (anonymous) at (0,20) size 580x44
+      LayoutInline {xhtml:a} at (0,0) size 62x19 [color=#0000EE]
+        LayoutText {#text} at (0,0) size 62x19
+          text run at (0,0) width 62: "and a link."
+      LayoutBR {xhtml:br} at (62,0) size 0x19
+      LayoutButton {xhtml:input} at (0,20) size 16x22 [bgcolor=#C0C0C0] [border: (2px outset #C0C0C0)]
+      LayoutText {#text} at (0,0) size 0x0
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/custom/use-on-disallowed-foreign-object-1-expected.txt b/third_party/WebKit/LayoutTests/platform/win/svg/custom/use-on-disallowed-foreign-object-1-expected.txt
index 72b94b4..3e2a089 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/custom/use-on-disallowed-foreign-object-1-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/custom/use-on-disallowed-foreign-object-1-expected.txt
@@ -7,3 +7,8 @@
         LayoutText {#text} at (0,0) size 228x19
           text run at (0,0) width 228: "You should only see this string ONCE"
     LayoutSVGContainer {use} at (0,0) size 0x0 [transform={m=((0.71,0.71)(-0.71,0.71)) t=(250.00,-35.86)}]
+layer at (10,10) size 480x360 backgroundClip at (54,55) size 746x545 clip at (54,55) size 436x315
+  LayoutSVGForeignObject {foreignObject} at (10,10) size 480x360
+    LayoutBlockFlow {xhtml:div} at (0,0) size 480x20
+      LayoutText {#text} at (0,0) size 228x19
+        text run at (0,0) width 228: "You should only see this string ONCE"
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/custom/use-on-disallowed-foreign-object-2-expected.txt b/third_party/WebKit/LayoutTests/platform/win/svg/custom/use-on-disallowed-foreign-object-2-expected.txt
index 17a0039..3a337bea 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/custom/use-on-disallowed-foreign-object-2-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/custom/use-on-disallowed-foreign-object-2-expected.txt
@@ -11,3 +11,8 @@
     LayoutSVGContainer {use} at (0,0) size 0x0 [transform={m=((0.71,0.71)(-0.71,0.71)) t=(250.00,-35.86)}]
       LayoutSVGContainer {g} at (0,0) size 0x0
         LayoutSVGContainer {g} at (0,0) size 0x0
+layer at (10,10) size 580x380 backgroundClip at (54,55) size 746x545 clip at (54,55) size 536x335
+  LayoutSVGForeignObject {foreignObject} at (10,10) size 580x380
+    LayoutBlockFlow {xhtml:div} at (0,0) size 580x20
+      LayoutText {#text} at (0,0) size 228x19
+        text run at (0,0) width 228: "You should only see this string ONCE"
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/custom/use-on-disallowed-foreign-object-3-expected.txt b/third_party/WebKit/LayoutTests/platform/win/svg/custom/use-on-disallowed-foreign-object-3-expected.txt
index 4656608..302a45f 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/custom/use-on-disallowed-foreign-object-3-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/custom/use-on-disallowed-foreign-object-3-expected.txt
@@ -8,3 +8,8 @@
           text run at (0,0) width 228: "You should only see this string ONCE"
     LayoutSVGContainer {use} at (0,0) size 0x0 [transform={m=((0.71,0.71)(-0.71,0.71)) t=(250.00,-35.86)}]
     LayoutSVGContainer {use} at (0,0) size 0x0 [transform={m=((0.71,0.71)(-0.71,0.71)) t=(250.00,-35.86)}]
+layer at (10,10) size 580x380 backgroundClip at (54,55) size 746x545 clip at (54,55) size 536x335
+  LayoutSVGForeignObject {foreignObject} at (10,10) size 580x380
+    LayoutBlockFlow {xhtml:div} at (0,0) size 580x20
+      LayoutText {#text} at (0,0) size 228x19
+        text run at (0,0) width 228: "You should only see this string ONCE"
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/custom/use-on-disallowed-foreign-object-4-expected.txt b/third_party/WebKit/LayoutTests/platform/win/svg/custom/use-on-disallowed-foreign-object-4-expected.txt
index 7a9320f..b4b8844f 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/custom/use-on-disallowed-foreign-object-4-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/custom/use-on-disallowed-foreign-object-4-expected.txt
@@ -15,3 +15,8 @@
       LayoutSVGContainer {g} at (0,0) size 0x0 [transform={m=((0.71,0.71)(-0.71,0.71)) t=(250.00,-35.86)}]
         LayoutSVGContainer {g} at (0,0) size 0x0
           LayoutSVGContainer {g} at (0,0) size 0x0
+layer at (10,10) size 580x380 backgroundClip at (54,55) size 746x545 clip at (54,55) size 536x335
+  LayoutSVGForeignObject {foreignObject} at (10,10) size 580x380
+    LayoutBlockFlow {xhtml:div} at (0,0) size 580x20
+      LayoutText {#text} at (0,0) size 228x19
+        text run at (0,0) width 228: "You should only see this string ONCE"
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/custom/use-on-disallowed-foreign-object-5-expected.txt b/third_party/WebKit/LayoutTests/platform/win/svg/custom/use-on-disallowed-foreign-object-5-expected.txt
index 7443c41..25cf26e 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/custom/use-on-disallowed-foreign-object-5-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/custom/use-on-disallowed-foreign-object-5-expected.txt
@@ -13,3 +13,8 @@
     LayoutSVGContainer {use} at (0,0) size 0x0 [transform={m=((1.00,0.00)(0.00,1.00)) t=(10.00,10.00)}]
       LayoutSVGContainer {g} at (0,0) size 0x0 [transform={m=((1.00,0.00)(0.00,1.00)) t=(25.00,25.00)}]
         LayoutSVGViewportContainer {svg} at (0,0) size 0x0
+layer at (10,10) size 580x380 backgroundClip at (54,55) size 746x545 clip at (54,55) size 536x335
+  LayoutSVGForeignObject {foreignObject} at (10,10) size 580x380
+    LayoutBlockFlow {xhtml:div} at (0,0) size 580x20
+      LayoutText {#text} at (0,0) size 228x19
+        text run at (0,0) width 228: "You should only see this string ONCE"
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/custom/use-on-disallowed-foreign-object-6-expected.txt b/third_party/WebKit/LayoutTests/platform/win/svg/custom/use-on-disallowed-foreign-object-6-expected.txt
index 21e0b76..dc33230 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/custom/use-on-disallowed-foreign-object-6-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/custom/use-on-disallowed-foreign-object-6-expected.txt
@@ -13,3 +13,8 @@
     LayoutSVGContainer {use} at (0,0) size 0x0 [transform={m=((1.00,0.00)(0.00,1.00)) t=(10.00,10.00)}]
       LayoutSVGContainer {g} at (0,0) size 0x0 [transform={m=((1.00,0.00)(0.00,1.00)) t=(25.00,25.00)}]
         LayoutSVGViewportContainer {svg} at (0,0) size 0x0
+layer at (10,10) size 580x380 backgroundClip at (54,55) size 746x545 clip at (54,55) size 536x335
+  LayoutSVGForeignObject {foreignObject} at (10,10) size 580x380
+    LayoutBlockFlow {xhtml:div} at (0,0) size 580x20
+      LayoutText {#text} at (0,0) size 228x19
+        text run at (0,0) width 228: "You should only see this string ONCE"
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/custom/use-on-non-svg-namespaced-element-expected.txt b/third_party/WebKit/LayoutTests/platform/win/svg/custom/use-on-non-svg-namespaced-element-expected.txt
index 72b94b4..3e2a089 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/custom/use-on-non-svg-namespaced-element-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/custom/use-on-non-svg-namespaced-element-expected.txt
@@ -7,3 +7,8 @@
         LayoutText {#text} at (0,0) size 228x19
           text run at (0,0) width 228: "You should only see this string ONCE"
     LayoutSVGContainer {use} at (0,0) size 0x0 [transform={m=((0.71,0.71)(-0.71,0.71)) t=(250.00,-35.86)}]
+layer at (10,10) size 480x360 backgroundClip at (54,55) size 746x545 clip at (54,55) size 436x315
+  LayoutSVGForeignObject {foreignObject} at (10,10) size 480x360
+    LayoutBlockFlow {xhtml:div} at (0,0) size 480x20
+      LayoutText {#text} at (0,0) size 228x19
+        text run at (0,0) width 228: "You should only see this string ONCE"
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/foreignObject/fO-parent-display-changes-expected.txt b/third_party/WebKit/LayoutTests/platform/win/svg/foreignObject/fO-parent-display-changes-expected.txt
index 015ddfc..e65d290 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/foreignObject/fO-parent-display-changes-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/foreignObject/fO-parent-display-changes-expected.txt
@@ -9,3 +9,9 @@
           LayoutBlockFlow {body} at (0,0) size 100x100 [color=#FFFFFF]
             LayoutText {#text} at (0,0) size 37x19
               text run at (0,0) width 37: "PASS"
+layer at (0,0) size 100x90 scrollHeight 100
+  LayoutSVGForeignObject {foreignObject} at (0,0) size 100x90
+    LayoutBlockFlow {html} at (0,0) size 100x100
+      LayoutBlockFlow {body} at (0,0) size 100x100 [color=#FFFFFF]
+        LayoutText {#text} at (0,0) size 37x19
+          text run at (0,0) width 37: "PASS"
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/foreignObject/no-crash-with-svg-content-in-html-document-expected.txt b/third_party/WebKit/LayoutTests/platform/win/svg/foreignObject/no-crash-with-svg-content-in-html-document-expected.txt
index 664319c..e3d834e5 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/foreignObject/no-crash-with-svg-content-in-html-document-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/foreignObject/no-crash-with-svg-content-in-html-document-expected.txt
@@ -10,3 +10,12 @@
         LayoutBlockFlow (anonymous) at (0,20) size 300x0
           LayoutInline {g} at (0,0) size 0x0
           LayoutText {#text} at (0,0) size 0x0
+layer at (0,0) size 300x100
+  LayoutSVGForeignObject {foreignObject} at (0,0) size 300x100
+    LayoutBlockFlow {html} at (0,0) size 300x20
+      LayoutBlockFlow {p} at (0,0) size 300x20
+        LayoutText {#text} at (0,0) size 127x19
+          text run at (0,0) width 127: "This should not crash"
+      LayoutBlockFlow (anonymous) at (0,20) size 300x0
+        LayoutInline {g} at (0,0) size 0x0
+        LayoutText {#text} at (0,0) size 0x0
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/foreignObject/svg-document-as-direct-child-expected.txt b/third_party/WebKit/LayoutTests/platform/win/svg/foreignObject/svg-document-as-direct-child-expected.txt
index 3fe5571b..1281904 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/foreignObject/svg-document-as-direct-child-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/foreignObject/svg-document-as-direct-child-expected.txt
@@ -17,3 +17,21 @@
       LayoutSVGRoot {svg} at (0,0) size 300x150
         LayoutSVGRect {rect} at (0,0) size 100x100 [fill={[type=SOLID] [color=#008000]}] [x=0.00] [y=0.00] [width=100.00] [height=100.00]
       LayoutText {#text} at (0,0) size 0x0
+layer at (0,0) size 300x100 scrollHeight 155
+  LayoutSVGForeignObject {foreignObject} at (0,0) size 300x100
+    LayoutSVGRoot {svg} at (0,0) size 300x150
+      LayoutSVGContainer {g} at (0,5) size 32x19
+        LayoutSVGText {text} at (0,5) size 32x19 contains 1 chunk(s)
+          LayoutSVGInlineText {#text} at (0,5) size 32x19
+            chunk 1 text run 1 at (0.00,20.00) startOffset 0 endOffset 5 width 32.00: "crash"
+    LayoutText {#text} at (0,0) size 0x0
+layer at (0,50) size 300x100 scrollHeight 155
+  LayoutSVGForeignObject {foreignObject} at (0,50) size 300x100
+    LayoutSVGRoot {svg} at (0,0) size 300x150
+      LayoutSVGRect {rect} at (0,0) size 100x100 [fill={[type=SOLID] [color=#008000]}] [x=0.00] [y=0.00] [width=100.00] [height=100.00]
+    LayoutText {#text} at (0,0) size 0x0
+layer at (0,150) size 300x100 scrollHeight 155
+  LayoutSVGForeignObject {foreignObject} at (0,150) size 300x100
+    LayoutSVGRoot {svg} at (0,0) size 300x150
+      LayoutSVGRect {rect} at (0,0) size 100x100 [fill={[type=SOLID] [color=#008000]}] [x=0.00] [y=0.00] [width=100.00] [height=100.00]
+    LayoutText {#text} at (0,0) size 0x0
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/foreignObject/svg-document-in-html-document-expected.txt b/third_party/WebKit/LayoutTests/platform/win/svg/foreignObject/svg-document-in-html-document-expected.txt
index 1f7e3c6..29c50f5 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/foreignObject/svg-document-in-html-document-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/foreignObject/svg-document-in-html-document-expected.txt
@@ -14,3 +14,16 @@
               LayoutSVGInlineText {#text} at (0,35) size 254x19
                 chunk 1 text run 1 at (0.00,50.00) startOffset 0 endOffset 38 width 254.00: "Test from SVG in HTML in foreignObject"
           LayoutText {#text} at (0,0) size 0x0
+layer at (0,0) size 300x100 scrollHeight 191
+  LayoutSVGForeignObject {foreignObject} at (0,0) size 300x100
+    LayoutBlockFlow {html} at (0,0) size 300x191
+      LayoutBlockFlow {p} at (0,0) size 300x20
+        LayoutText {#text} at (0,0) size 205x19
+          text run at (0,0) width 205: "Test from HTML in foreignObject"
+      LayoutBlockFlow (anonymous) at (0,36) size 300x155
+        LayoutSVGRoot {svg} at (0,0) size 300x150
+          LayoutSVGRect {rect} at (0,0) size 20x20 [fill={[type=SOLID] [color=#008000]}] [x=0.00] [y=0.00] [width=20.00] [height=20.00]
+          LayoutSVGText {text} at (0,35) size 254x19 contains 1 chunk(s)
+            LayoutSVGInlineText {#text} at (0,35) size 254x19
+              chunk 1 text run 1 at (0.00,50.00) startOffset 0 endOffset 38 width 254.00: "Test from SVG in HTML in foreignObject"
+        LayoutText {#text} at (0,0) size 0x0
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/hixie/mixed/004-expected.txt b/third_party/WebKit/LayoutTests/platform/win/svg/hixie/mixed/004-expected.txt
deleted file mode 100644
index 6892ace..0000000
--- a/third_party/WebKit/LayoutTests/platform/win/svg/hixie/mixed/004-expected.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-layer at (0,0) size 800x600
-  LayoutView at (0,0) size 800x600
-layer at (0,0) size 800x221
-  LayoutBlockFlow {html} at (0,0) size 800x221
-    LayoutBlockFlow {body} at (8,8) size 784x205
-      LayoutSVGRoot {svg} at (0,0) size 200x200
-        LayoutSVGEllipse {circle} at (0,0) size 100x100 [fill={[type=SOLID] [color=#FF0000]}] [cx=50.00] [cy=50.00] [r=50.00]
-        LayoutSVGEllipse {circle} at (0,0) size 100x100 [fill={[type=SOLID] [color=#008000]}] [cx=50.00] [cy=50.00] [r=50.00]
-      LayoutText {#text} at (0,0) size 0x0
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/hixie/mixed/005-expected.txt b/third_party/WebKit/LayoutTests/platform/win/svg/hixie/mixed/005-expected.txt
deleted file mode 100644
index 6892ace..0000000
--- a/third_party/WebKit/LayoutTests/platform/win/svg/hixie/mixed/005-expected.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-layer at (0,0) size 800x600
-  LayoutView at (0,0) size 800x600
-layer at (0,0) size 800x221
-  LayoutBlockFlow {html} at (0,0) size 800x221
-    LayoutBlockFlow {body} at (8,8) size 784x205
-      LayoutSVGRoot {svg} at (0,0) size 200x200
-        LayoutSVGEllipse {circle} at (0,0) size 100x100 [fill={[type=SOLID] [color=#FF0000]}] [cx=50.00] [cy=50.00] [r=50.00]
-        LayoutSVGEllipse {circle} at (0,0) size 100x100 [fill={[type=SOLID] [color=#008000]}] [cx=50.00] [cy=50.00] [r=50.00]
-      LayoutText {#text} at (0,0) size 0x0
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/hixie/mixed/006-expected.txt b/third_party/WebKit/LayoutTests/platform/win/svg/hixie/mixed/006-expected.txt
index 7d29150..e9477e9 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/hixie/mixed/006-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/hixie/mixed/006-expected.txt
@@ -12,6 +12,8 @@
     LayoutText {#text} at (0,0) size 189x39
       text run at (0,0) width 181: "There should be a green circle"
       text run at (0,20) width 189: "below with no red on this page."
+layer at (8,208) size 200x200
+  LayoutSVGForeignObject {foreignObject} at (0,0) size 200x200
 layer at (8,8) size 200x200 backgroundClip at (8,208) size 200x200 clip at (8,208) size 200x200
   LayoutBlockFlow (positioned) {div} at (0,-200) size 200x200 [color=#FFFF00] [bgcolor=#FF0000]
     LayoutText {#text} at (0,0) size 33x19
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/hixie/mixed/007-expected.txt b/third_party/WebKit/LayoutTests/platform/win/svg/hixie/mixed/007-expected.txt
index 142bc19..365ef24b 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/hixie/mixed/007-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/hixie/mixed/007-expected.txt
@@ -6,3 +6,8 @@
       LayoutBlockFlow {p} at (0,0) size 400x20
         LayoutText {#text} at (0,0) size 37x19
           text run at (0,0) width 37: "PASS"
+layer at (0,0) size 400x400
+  LayoutSVGForeignObject {foreignObject} at (0,0) size 400x400
+    LayoutBlockFlow {p} at (0,0) size 400x20
+      LayoutText {#text} at (0,0) size 37x19
+        text run at (0,0) width 37: "PASS"
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/hixie/mixed/008-expected.txt b/third_party/WebKit/LayoutTests/platform/win/svg/hixie/mixed/008-expected.txt
index d42890e..f5b0df9d 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/hixie/mixed/008-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/hixie/mixed/008-expected.txt
@@ -15,3 +15,8 @@
               LayoutText {#text} at (139,1) size 122x57
                 text run at (139,1) width 122: "TEST"
         LayoutText {#text} at (0,0) size 0x0
+layer at (8,227) size 400x50 scrollHeight 59
+  LayoutSVGForeignObject {foreignObject} at (0,175) size 400x50 [color=#FFFFFF]
+    LayoutBlockFlow {div} at (0,0) size 400x59
+      LayoutText {#text} at (139,1) size 122x57
+        text run at (139,1) width 122: "TEST"
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/hixie/mixed/009-expected.txt b/third_party/WebKit/LayoutTests/platform/win/svg/hixie/mixed/009-expected.txt
index b7e5ee4..167c7b6 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/hixie/mixed/009-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/hixie/mixed/009-expected.txt
@@ -17,3 +17,8 @@
       LayoutBlockFlow {div} at (0,145) size 400x120 [color=#000080] [bgcolor=#EEEEEE]
         LayoutText {#text} at (0,2) size 239x114
           text run at (0,2) width 239: "TEST"
+layer at (8,28) size 60x10 scrollHeight 12
+  LayoutSVGForeignObject {foreignObject} at (0,0) size 60x10
+    LayoutBlockFlow {div} at (0,0) size 60x12 [color=#000080]
+      LayoutText {#text} at (0,0) size 26x12
+        text run at (0,0) width 26: "TEST"
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/hixie/mixed/011-expected.txt b/third_party/WebKit/LayoutTests/platform/win/svg/hixie/mixed/011-expected.txt
index 70c696f..82daefc 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/hixie/mixed/011-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/hixie/mixed/011-expected.txt
@@ -7,7 +7,9 @@
         LayoutSVGEllipse {circle} at (50,50) size 100x100 [fill={[type=SOLID] [color=#008000]}] [cx=100.00] [cy=100.00] [r=50.00]
         LayoutSVGForeignObject {foreignObject} at (0,0) size 200x200
       LayoutText {#text} at (0,0) size 0x0
-layer at (50,0) size 150x200 backgroundClip at (0,8) size 149x283 clip at (0,8) size 149x283
+layer at (8,8) size 200x200 backgroundClip at (0,8) size 149x283 clip at (8,8) size 141x200
+  LayoutSVGForeignObject {foreignObject} at (0,0) size 200x200
+layer at (58,8) size 150x200 backgroundClip at (0,8) size 149x283 clip at (0,8) size 149x283
   LayoutBlockFlow (positioned) {div} at (50,0) size 150x200
     LayoutText {#text} at (0,0) size 145x79
       text run at (0,0) width 145: "There should be a green"
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/hixie/perf/007-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/hixie/perf/007-expected.png
index 33a1d55..b708e40 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/hixie/perf/007-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/hixie/perf/007-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/text/foreignObject-repaint-expected.txt b/third_party/WebKit/LayoutTests/platform/win/svg/text/foreignObject-repaint-expected.txt
index 134198f..8dcf359 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/text/foreignObject-repaint-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/text/foreignObject-repaint-expected.txt
@@ -8,3 +8,10 @@
           text run at (0,1) width 481: "Select this text using"
           text run at (0,63) width 468: "the mouse, it should"
           text run at (0,125) width 334: "not disappear!"
+layer at (100,100) size 500x300
+  LayoutSVGForeignObject {foreignObject} at (100,100) size 500x300
+    LayoutBlockFlow {div} at (0,0) size 500x186
+      LayoutText {#text} at (0,1) size 481x184
+        text run at (0,1) width 481: "Select this text using"
+        text run at (0,63) width 468: "the mouse, it should"
+        text run at (0,125) width 334: "not disappear!"
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/text/foreignObject-text-clipping-bug-expected.txt b/third_party/WebKit/LayoutTests/platform/win/svg/text/foreignObject-text-clipping-bug-expected.txt
index 279de61..78284b0 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/text/foreignObject-text-clipping-bug-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/text/foreignObject-text-clipping-bug-expected.txt
@@ -14,6 +14,11 @@
               LayoutText {#text} at (0,0) size 26x12
                 text run at (0,0) width 26: "TEST"
         LayoutText {#text} at (0,0) size 0x0
+layer at (9,29) size 60x10 backgroundClip at (18,38) size 390x100 clip at (18,38) size 51x1 scrollHeight 12
+  LayoutSVGForeignObject {foreignObject} at (1,1) size 60x10
+    LayoutBlockFlow {div} at (0,0) size 60x12 [color=#000080]
+      LayoutText {#text} at (0,0) size 26x12
+        text run at (0,0) width 26: "TEST"
 layer at (18,163) size 390x110
   LayoutBlockFlow (relative positioned) {div} at (0,145) size 390x110 [color=#000080] [bgcolor=#D3D3D3]
     LayoutBlockFlow {div} at (0,0) size 390x118
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/zoom/page/zoom-foreignObject-expected.txt b/third_party/WebKit/LayoutTests/platform/win/svg/zoom/page/zoom-foreignObject-expected.txt
index 541f556..e7b537477e 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/zoom/page/zoom-foreignObject-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/zoom/page/zoom-foreignObject-expected.txt
@@ -31,3 +31,31 @@
       LayoutText {#text} at (0,0) size 0x0
     LayoutSVGRect {rect} at (260,0) size 250x200 [stroke={[type=SOLID] [color=#008000]}] [x=260.00] [y=0.00] [width=250.00] [height=200.00]
     LayoutSVGHiddenContainer {defs} at (0,0) size 0x0
+layer at (0,0) size 250x200
+  LayoutSVGForeignObject {foreignObject} at (0,0) size 250x200
+    LayoutBlockFlow {xhtml:div} at (0,0) size 250x20
+      LayoutText {#text} at (0,0) size 75x19
+        text run at (0,0) width 75: "This is a text"
+    LayoutBlockFlow (anonymous) at (0,20) size 250x20
+      LayoutInline {xhtml:a} at (0,0) size 62x19 [color=#0000EE]
+        LayoutText {#text} at (0,0) size 62x19
+          text run at (0,0) width 62: "and a link."
+      LayoutBR {xhtml:br} at (62,0) size 0x19
+    LayoutBlockFlow {xhtml:div} at (0,40) size 250x20
+      LayoutText {#text} at (0,0) size 53x19
+        text run at (0,0) width 53: "[HTML]"
+layer at (260,0) size 250x200 backgroundClip at (374,0) size 360x288 clip at (374,0) size 136x200 scrollHeight 205
+  LayoutSVGForeignObject {foreignObject} at (260,0) size 250x200
+    LayoutSVGRoot {svg} at (0,0) size 250x200
+      LayoutSVGContainer {g} at (0,1.77) size 80.05x58.19 [transform={m=((3.00,0.26)(0.26,3.02)) t=(0.00,0.00)}]
+        LayoutSVGText {text} at (0,1.77) size 80.05x18.19 contains 1 chunk(s)
+          LayoutSVGInlineText {#text} at (0,1.77) size 80.05x18.19
+            chunk 1 text run 1 at (0.00,16.00) startOffset 0 endOffset 14 width 80.06: "This is a text"
+        LayoutSVGContainer {a} at (0,20.77) size 64.50x18.19
+          LayoutSVGText {text} at (0,20.77) size 64.50x18.19 contains 1 chunk(s)
+            LayoutSVGInlineText {#text} at (0,20.77) size 64.50x18.19
+              chunk 1 text run 1 at (0.00,35.00) startOffset 0 endOffset 11 width 64.51: "and a link."
+        LayoutSVGText {text} at (0,41.77) size 42.67x18.19 contains 1 chunk(s)
+          LayoutSVGInlineText {#text} at (0,41.77) size 42.67x18.19
+            chunk 1 text run 1 at (0.00,56.00) startOffset 0 endOffset 5 width 42.67: "[SVG]"
+    LayoutText {#text} at (0,0) size 0x0
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/zoom/page/zoom-hixie-mixed-008-expected.txt b/third_party/WebKit/LayoutTests/platform/win/svg/zoom/page/zoom-hixie-mixed-008-expected.txt
index 61555e6..07cc09c 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/zoom/page/zoom-hixie-mixed-008-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/zoom/page/zoom-hixie-mixed-008-expected.txt
@@ -15,3 +15,8 @@
               LayoutText {#text} at (139,1) size 122x57
                 text run at (139,1) width 122: "TEST"
         LayoutText {#text} at (0,0) size 0x0
+layer at (12,248) size 400x50 backgroundClip at (12,325) size 576x72 clip at (0,0) size 0x0 scrollHeight 59
+  LayoutSVGForeignObject {foreignObject} at (0,175) size 400x50 [color=#FFFFFF]
+    LayoutBlockFlow {div} at (0,0) size 400x59
+      LayoutText {#text} at (139,1) size 122x57
+        text run at (139,1) width 122: "TEST"
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/zoom/page/zoom-hixie-mixed-009-expected.txt b/third_party/WebKit/LayoutTests/platform/win/svg/zoom/page/zoom-hixie-mixed-009-expected.txt
index 2b5f47b..b046ac327 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/zoom/page/zoom-hixie-mixed-009-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/zoom/page/zoom-hixie-mixed-009-expected.txt
@@ -17,3 +17,8 @@
       LayoutBlockFlow {div} at (0,206.80) size 576x172.80 [color=#000080] [bgcolor=#EEEEEE]
         LayoutText {#text} at (0,3) size 344x164
           text run at (0,3) width 344: "TEST"
+layer at (12,39) size 60x10 scrollHeight 12
+  LayoutSVGForeignObject {foreignObject} at (0,0) size 60x10
+    LayoutBlockFlow {div} at (0,0) size 60x12 [color=#000080]
+      LayoutText {#text} at (0,0) size 26x12
+        text run at (0,0) width 26: "TEST"
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/zoom/text/zoom-hixie-mixed-008-expected.txt b/third_party/WebKit/LayoutTests/platform/win/svg/zoom/text/zoom-hixie-mixed-008-expected.txt
index 76fd7f3..b585ac01 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/zoom/text/zoom-hixie-mixed-008-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/zoom/text/zoom-hixie-mixed-008-expected.txt
@@ -15,3 +15,8 @@
               LayoutText {#text} at (113,1) size 174x81
                 text run at (113,1) width 174: "TEST"
         LayoutText {#text} at (0,0) size 0x0
+layer at (8,248) size 400x50 scrollHeight 84
+  LayoutSVGForeignObject {foreignObject} at (0,175) size 400x50 [color=#FFFFFF]
+    LayoutBlockFlow {div} at (0,0) size 400x84
+      LayoutText {#text} at (113,1) size 174x81
+        text run at (113,1) width 174: "TEST"
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/zoom/text/zoom-hixie-mixed-009-expected.txt b/third_party/WebKit/LayoutTests/platform/win/svg/zoom/text/zoom-hixie-mixed-009-expected.txt
index ee2d5c3..7246e8f 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/zoom/text/zoom-hixie-mixed-009-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/zoom/text/zoom-hixie-mixed-009-expected.txt
@@ -17,3 +17,8 @@
       LayoutBlockFlow {div} at (0,154) size 400x120 [color=#000080] [bgcolor=#EEEEEE]
         LayoutText {#text} at (0,3) size 344x164
           text run at (0,3) width 344: "TEST"
+layer at (8,35) size 60x10 scrollHeight 17
+  LayoutSVGForeignObject {foreignObject} at (0,0) size 60x10
+    LayoutBlockFlow {div} at (0,0) size 60x17 [color=#000080]
+      LayoutText {#text} at (0,0) size 34x16
+        text run at (0,0) width 34: "TEST"
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/gpu/fast/canvas/canvas-composite-video-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/gpu/fast/canvas/canvas-composite-video-expected.png
index 2d2c80d..ad55ce264 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/gpu/fast/canvas/canvas-composite-video-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/gpu/fast/canvas/canvas-composite-video-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/gpu/fast/canvas/canvas-composite-video-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/gpu/fast/canvas/canvas-composite-video-shadow-expected.png
new file mode 100644
index 0000000..c82dc763
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/gpu/fast/canvas/canvas-composite-video-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/fast/table/backgr_border-table-column-group-collapsed-border-expected.png b/third_party/WebKit/LayoutTests/platform/win7/fast/table/backgr_border-table-column-group-collapsed-border-expected.png
index 8fed5647..830c44bc 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/fast/table/backgr_border-table-column-group-collapsed-border-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/fast/table/backgr_border-table-column-group-collapsed-border-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/svg/as-background-image/svg-as-background-5-expected.png b/third_party/WebKit/LayoutTests/platform/win7/svg/as-background-image/svg-as-background-5-expected.png
index 2428c45..4469f08 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/svg/as-background-image/svg-as-background-5-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/svg/as-background-image/svg-as-background-5-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/as-object/svg-embedded-in-html-in-iframe-expected.txt b/third_party/WebKit/LayoutTests/svg/as-object/svg-embedded-in-html-in-iframe-expected.txt
index 602fbe6..456fbfb 100644
--- a/third_party/WebKit/LayoutTests/svg/as-object/svg-embedded-in-html-in-iframe-expected.txt
+++ b/third_party/WebKit/LayoutTests/svg/as-object/svg-embedded-in-html-in-iframe-expected.txt
@@ -1,15 +1,15 @@
 layer at (0,0) size 800x600
   LayoutView at (0,0) size 800x600
-layer at (0,0) size 800x170
-  LayoutBlockFlow {HTML} at (0,0) size 800x170
-    LayoutBlockFlow {BODY} at (8,8) size 784x154
+layer at (0,0) size 800x171
+  LayoutBlockFlow {HTML} at (0,0) size 800x171
+    LayoutBlockFlow {BODY} at (8,8) size 784x155
       LayoutText {#text} at (0,0) size 0x0
 layer at (8,8) size 784x150
   LayoutIFrame {IFRAME} at (0,0) size 784x150
     layer at (0,0) size 784x150
       LayoutView at (0,0) size 784x150
-    layer at (0,0) size 784x120
-      LayoutBlockFlow {HTML} at (0,0) size 784x120
-        LayoutBlockFlow {BODY} at (8,8) size 768x104
+    layer at (0,0) size 784x121
+      LayoutBlockFlow {HTML} at (0,0) size 784x121
+        LayoutBlockFlow {BODY} at (8,8) size 768x105
           LayoutSVGRoot {svg} at (0,0) size 100x100
             LayoutSVGEllipse {circle} at (0,0) size 100x100 [fill={[type=SOLID] [color=#0000FF]}] [cx=50.00] [cy=50.00] [r=50.00]
diff --git a/third_party/WebKit/LayoutTests/svg/custom/display-table-caption-foreignObject-expected.txt b/third_party/WebKit/LayoutTests/svg/custom/display-table-caption-foreignObject-expected.txt
index fbea555a..8b13789 100644
--- a/third_party/WebKit/LayoutTests/svg/custom/display-table-caption-foreignObject-expected.txt
+++ b/third_party/WebKit/LayoutTests/svg/custom/display-table-caption-foreignObject-expected.txt
@@ -1 +1 @@
-This test PASSED if we don't crash when the display value is table-caption
+
diff --git a/third_party/WebKit/LayoutTests/svg/custom/display-table-caption-inherit-foreignObject-expected.txt b/third_party/WebKit/LayoutTests/svg/custom/display-table-caption-inherit-foreignObject-expected.txt
index 1f42074..8b13789 100644
--- a/third_party/WebKit/LayoutTests/svg/custom/display-table-caption-inherit-foreignObject-expected.txt
+++ b/third_party/WebKit/LayoutTests/svg/custom/display-table-caption-inherit-foreignObject-expected.txt
@@ -1,2 +1 @@
-This test PASSED if we don't crash when the display value is table-caption by using inherit
 
diff --git a/third_party/WebKit/LayoutTests/svg/custom/filter-css-transform-resolution-expected.txt b/third_party/WebKit/LayoutTests/svg/custom/filter-css-transform-resolution-expected.txt
index eafa544..bcc1bec 100644
--- a/third_party/WebKit/LayoutTests/svg/custom/filter-css-transform-resolution-expected.txt
+++ b/third_party/WebKit/LayoutTests/svg/custom/filter-css-transform-resolution-expected.txt
@@ -1,9 +1,9 @@
 layer at (0,0) size 800x600
   LayoutView at (0,0) size 800x600
-layer at (0,0) size 800x320
-  LayoutBlockFlow {HTML} at (0,0) size 800x320
-    LayoutBlockFlow {BODY} at (8,8) size 784x304
-      LayoutBlockFlow {DIV} at (0,0) size 784x304
+layer at (0,0) size 800x321
+  LayoutBlockFlow {HTML} at (0,0) size 800x321
+    LayoutBlockFlow {BODY} at (8,8) size 784x305
+      LayoutBlockFlow {DIV} at (0,0) size 784x305
         LayoutSVGRoot {svg} at (0,0) size 300x300
           LayoutSVGHiddenContainer {defs} at (0,0) size 0x0
             LayoutSVGResourceFilter {filter} [id="filter"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
diff --git a/third_party/WebKit/LayoutTests/svg/custom/foreign-object-skew.svg b/third_party/WebKit/LayoutTests/svg/custom/foreign-object-skew.svg
index e060051..3c19e664 100644
--- a/third_party/WebKit/LayoutTests/svg/custom/foreign-object-skew.svg
+++ b/third_party/WebKit/LayoutTests/svg/custom/foreign-object-skew.svg
@@ -8,4 +8,4 @@
 <xhtml:input type="button">Button</xhtml:input>
 </foreignObject>
 <rect x="10" y="10" width="580" height="380" stroke="green" fill="none" />
-</svg>
\ No newline at end of file
+</svg>
diff --git a/third_party/WebKit/LayoutTests/svg/custom/use-on-use-with-child-expected.txt b/third_party/WebKit/LayoutTests/svg/custom/use-on-use-with-child-expected.txt
index 4eb5570..8b13789 100644
--- a/third_party/WebKit/LayoutTests/svg/custom/use-on-use-with-child-expected.txt
+++ b/third_party/WebKit/LayoutTests/svg/custom/use-on-use-with-child-expected.txt
@@ -1,10 +1 @@
-The instance tree of use element zoomplus:
-      this = [object ShadowRoot]
-           id = loupePlus this = [object SVGGElement]
-                this = [object Text]
-                id = useRim this = [object SVGGElement]
-                     this = [object Text]
-                     this = [object Text]
-                     id = rim this = [object SVGCircleElement]
-                this = [object Text]
 
diff --git a/third_party/WebKit/LayoutTests/svg/dom/SVGScriptElement/script-async-attr-expected.txt b/third_party/WebKit/LayoutTests/svg/dom/SVGScriptElement/script-async-attr-expected.txt
index 05b0917..8b13789 100644
--- a/third_party/WebKit/LayoutTests/svg/dom/SVGScriptElement/script-async-attr-expected.txt
+++ b/third_party/WebKit/LayoutTests/svg/dom/SVGScriptElement/script-async-attr-expected.txt
@@ -1,3 +1 @@
-Tests that the async attribute is not supported for SVG scripts.
 
-PASS
diff --git a/third_party/WebKit/LayoutTests/svg/dom/SVGScriptElement/script-reexecution-expected.txt b/third_party/WebKit/LayoutTests/svg/dom/SVGScriptElement/script-reexecution-expected.txt
index c5e6be32..8b13789 100644
--- a/third_party/WebKit/LayoutTests/svg/dom/SVGScriptElement/script-reexecution-expected.txt
+++ b/third_party/WebKit/LayoutTests/svg/dom/SVGScriptElement/script-reexecution-expected.txt
@@ -1,7 +1 @@
-Created script element, script data passed as text content, appended: PASS
 
-Removed element, readd element, remove again, script shouldn't have executed:PASS
-
-Created script element, loading external script content, appended: PASS
-
-Removed element, readd element, script shouldn't have executed: PASS
diff --git a/third_party/WebKit/LayoutTests/svg/dom/SVGScriptElement/script-set-href-expected.txt b/third_party/WebKit/LayoutTests/svg/dom/SVGScriptElement/script-set-href-expected.txt
index f2d149a..8b13789 100644
--- a/third_party/WebKit/LayoutTests/svg/dom/SVGScriptElement/script-set-href-expected.txt
+++ b/third_party/WebKit/LayoutTests/svg/dom/SVGScriptElement/script-set-href-expected.txt
@@ -1,21 +1 @@
-Parser-created script elements:
 
-Already containing text: PASS
-
-Already specifying missing source: PASS
-
-Already specifying valid source: PASS
-
-No text and no source: PASS
-
-Self-closing <script> tag: PASS
-
-Using setAttribute: PASS
-
-Dynamically-inserted script elements:
-
-Set before insertion: PASS
-
-Set after insertion: PASS
-
-Set twice before and once after insertion: PASS
diff --git a/third_party/WebKit/LayoutTests/svg/dom/SVGScriptElement/script-type-attribute-expected.txt b/third_party/WebKit/LayoutTests/svg/dom/SVGScriptElement/script-type-attribute-expected.txt
index 0cd12cc3..8b13789 100644
--- a/third_party/WebKit/LayoutTests/svg/dom/SVGScriptElement/script-type-attribute-expected.txt
+++ b/third_party/WebKit/LayoutTests/svg/dom/SVGScriptElement/script-type-attribute-expected.txt
@@ -1,3 +1 @@
-Test that getting/setting the type JS property on SVGScriptElement keeps sync with the type content attribute.
 
-PASS
diff --git a/third_party/WebKit/LayoutTests/svg/dom/smil-methods-expected.txt b/third_party/WebKit/LayoutTests/svg/dom/smil-methods-expected.txt
index 5bedbe9b..8b13789 100644
--- a/third_party/WebKit/LayoutTests/svg/dom/smil-methods-expected.txt
+++ b/third_party/WebKit/LayoutTests/svg/dom/smil-methods-expected.txt
@@ -1,6 +1 @@
-This test checks whether the methods on ElementTimeControl correctly return undefined.
-animate.beginElement(): PASS
-animate.beginElementAt(0): PASS
-animate.endElement(): PASS
-animate.endElementAt(0): PASS
 
diff --git a/third_party/WebKit/LayoutTests/svg/filters/feBlend-all-modes-expected.txt b/third_party/WebKit/LayoutTests/svg/filters/feBlend-all-modes-expected.txt
index 9e928b6..012b8c4f 100644
--- a/third_party/WebKit/LayoutTests/svg/filters/feBlend-all-modes-expected.txt
+++ b/third_party/WebKit/LayoutTests/svg/filters/feBlend-all-modes-expected.txt
@@ -1,9 +1,9 @@
 layer at (0,0) size 800x600
   LayoutView at (0,0) size 800x600
-layer at (0,0) size 800x340
-  LayoutBlockFlow {HTML} at (0,0) size 800x340
-    LayoutBlockFlow {BODY} at (8,8) size 784x324
-      LayoutBlockFlow {DIV} at (0,0) size 400x108
+layer at (0,0) size 800x346
+  LayoutBlockFlow {HTML} at (0,0) size 800x346
+    LayoutBlockFlow {BODY} at (8,8) size 784x330
+      LayoutBlockFlow {DIV} at (0,0) size 400x110
         LayoutSVGRoot {svg} at (0,0) size 50x50
           LayoutSVGResourceFilter {filter} [id="f_normal0"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="normal"]
@@ -60,63 +60,63 @@
               [feFlood flood-color="#00FF00" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
             [filter="f_color-burn0"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
-        LayoutSVGRoot {svg} at (0,54) size 50x50
+        LayoutSVGRoot {svg} at (0,55) size 50x50
           LayoutSVGResourceFilter {filter} [id="f_hard-light0"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="hard-light"]
               [feFlood flood-color="#FF0000" flood-opacity="1.00"]
               [feFlood flood-color="#00FF00" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
             [filter="f_hard-light0"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
-        LayoutSVGRoot {svg} at (50,54) size 50x50
+        LayoutSVGRoot {svg} at (50,55) size 50x50
           LayoutSVGResourceFilter {filter} [id="f_soft-light0"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="soft-light"]
               [feFlood flood-color="#FF0000" flood-opacity="1.00"]
               [feFlood flood-color="#00FF00" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
             [filter="f_soft-light0"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
-        LayoutSVGRoot {svg} at (100,54) size 50x50
+        LayoutSVGRoot {svg} at (100,55) size 50x50
           LayoutSVGResourceFilter {filter} [id="f_difference0"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="difference"]
               [feFlood flood-color="#FF0000" flood-opacity="1.00"]
               [feFlood flood-color="#00FF00" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
             [filter="f_difference0"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
-        LayoutSVGRoot {svg} at (150,54) size 50x50
+        LayoutSVGRoot {svg} at (150,55) size 50x50
           LayoutSVGResourceFilter {filter} [id="f_exclusion0"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="exclusion"]
               [feFlood flood-color="#FF0000" flood-opacity="1.00"]
               [feFlood flood-color="#00FF00" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
             [filter="f_exclusion0"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
-        LayoutSVGRoot {svg} at (200,54) size 50x50
+        LayoutSVGRoot {svg} at (200,55) size 50x50
           LayoutSVGResourceFilter {filter} [id="f_hue0"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="hue"]
               [feFlood flood-color="#FF0000" flood-opacity="1.00"]
               [feFlood flood-color="#00FF00" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
             [filter="f_hue0"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
-        LayoutSVGRoot {svg} at (250,54) size 50x50
+        LayoutSVGRoot {svg} at (250,55) size 50x50
           LayoutSVGResourceFilter {filter} [id="f_saturation0"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="saturation"]
               [feFlood flood-color="#FF0000" flood-opacity="1.00"]
               [feFlood flood-color="#00FF00" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
             [filter="f_saturation0"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
-        LayoutSVGRoot {svg} at (300,54) size 50x50
+        LayoutSVGRoot {svg} at (300,55) size 50x50
           LayoutSVGResourceFilter {filter} [id="f_color0"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="color"]
               [feFlood flood-color="#FF0000" flood-opacity="1.00"]
               [feFlood flood-color="#00FF00" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
             [filter="f_color0"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
-        LayoutSVGRoot {svg} at (350,54) size 50x50
+        LayoutSVGRoot {svg} at (350,55) size 50x50
           LayoutSVGResourceFilter {filter} [id="f_luminosity0"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="luminosity"]
               [feFlood flood-color="#FF0000" flood-opacity="1.00"]
               [feFlood flood-color="#00FF00" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
             [filter="f_luminosity0"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
-      LayoutBlockFlow {DIV} at (0,108) size 400x108
+      LayoutBlockFlow {DIV} at (0,110) size 400x110
         LayoutSVGRoot {svg} at (0,0) size 50x50
           LayoutSVGResourceFilter {filter} [id="f_normal1"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="normal"]
@@ -173,63 +173,63 @@
               [feFlood flood-color="#99C066" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
             [filter="f_color-burn1"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
-        LayoutSVGRoot {svg} at (0,54) size 50x50
+        LayoutSVGRoot {svg} at (0,55) size 50x50
           LayoutSVGResourceFilter {filter} [id="f_hard-light1"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="hard-light"]
               [feFlood flood-color="#3340CC" flood-opacity="1.00"]
               [feFlood flood-color="#99C066" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
             [filter="f_hard-light1"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
-        LayoutSVGRoot {svg} at (50,54) size 50x50
+        LayoutSVGRoot {svg} at (50,55) size 50x50
           LayoutSVGResourceFilter {filter} [id="f_soft-light1"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="soft-light"]
               [feFlood flood-color="#3340CC" flood-opacity="1.00"]
               [feFlood flood-color="#99C066" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
             [filter="f_soft-light1"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
-        LayoutSVGRoot {svg} at (100,54) size 50x50
+        LayoutSVGRoot {svg} at (100,55) size 50x50
           LayoutSVGResourceFilter {filter} [id="f_difference1"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="difference"]
               [feFlood flood-color="#3340CC" flood-opacity="1.00"]
               [feFlood flood-color="#99C066" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
             [filter="f_difference1"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
-        LayoutSVGRoot {svg} at (150,54) size 50x50
+        LayoutSVGRoot {svg} at (150,55) size 50x50
           LayoutSVGResourceFilter {filter} [id="f_exclusion1"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="exclusion"]
               [feFlood flood-color="#3340CC" flood-opacity="1.00"]
               [feFlood flood-color="#99C066" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
             [filter="f_exclusion1"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
-        LayoutSVGRoot {svg} at (200,54) size 50x50
+        LayoutSVGRoot {svg} at (200,55) size 50x50
           LayoutSVGResourceFilter {filter} [id="f_hue1"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="hue"]
               [feFlood flood-color="#3340CC" flood-opacity="1.00"]
               [feFlood flood-color="#99C066" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
             [filter="f_hue1"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
-        LayoutSVGRoot {svg} at (250,54) size 50x50
+        LayoutSVGRoot {svg} at (250,55) size 50x50
           LayoutSVGResourceFilter {filter} [id="f_saturation1"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="saturation"]
               [feFlood flood-color="#3340CC" flood-opacity="1.00"]
               [feFlood flood-color="#99C066" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
             [filter="f_saturation1"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
-        LayoutSVGRoot {svg} at (300,54) size 50x50
+        LayoutSVGRoot {svg} at (300,55) size 50x50
           LayoutSVGResourceFilter {filter} [id="f_color1"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="color"]
               [feFlood flood-color="#3340CC" flood-opacity="1.00"]
               [feFlood flood-color="#99C066" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
             [filter="f_color1"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
-        LayoutSVGRoot {svg} at (350,54) size 50x50
+        LayoutSVGRoot {svg} at (350,55) size 50x50
           LayoutSVGResourceFilter {filter} [id="f_luminosity1"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="luminosity"]
               [feFlood flood-color="#3340CC" flood-opacity="1.00"]
               [feFlood flood-color="#99C066" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
             [filter="f_luminosity1"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
-      LayoutBlockFlow {DIV} at (0,216) size 400x108
+      LayoutBlockFlow {DIV} at (0,220) size 400x110
         LayoutSVGRoot {svg} at (0,0) size 50x50
           LayoutSVGResourceFilter {filter} [id="f_normal2"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="normal"]
@@ -286,56 +286,56 @@
               [feFlood flood-color="#99C06680" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
             [filter="f_color-burn2"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
-        LayoutSVGRoot {svg} at (0,54) size 50x50
+        LayoutSVGRoot {svg} at (0,55) size 50x50
           LayoutSVGResourceFilter {filter} [id="f_hard-light2"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="hard-light"]
               [feFlood flood-color="#3340CC80" flood-opacity="1.00"]
               [feFlood flood-color="#99C06680" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
             [filter="f_hard-light2"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
-        LayoutSVGRoot {svg} at (50,54) size 50x50
+        LayoutSVGRoot {svg} at (50,55) size 50x50
           LayoutSVGResourceFilter {filter} [id="f_soft-light2"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="soft-light"]
               [feFlood flood-color="#3340CC80" flood-opacity="1.00"]
               [feFlood flood-color="#99C06680" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
             [filter="f_soft-light2"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
-        LayoutSVGRoot {svg} at (100,54) size 50x50
+        LayoutSVGRoot {svg} at (100,55) size 50x50
           LayoutSVGResourceFilter {filter} [id="f_difference2"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="difference"]
               [feFlood flood-color="#3340CC80" flood-opacity="1.00"]
               [feFlood flood-color="#99C06680" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
             [filter="f_difference2"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
-        LayoutSVGRoot {svg} at (150,54) size 50x50
+        LayoutSVGRoot {svg} at (150,55) size 50x50
           LayoutSVGResourceFilter {filter} [id="f_exclusion2"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="exclusion"]
               [feFlood flood-color="#3340CC80" flood-opacity="1.00"]
               [feFlood flood-color="#99C06680" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
             [filter="f_exclusion2"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
-        LayoutSVGRoot {svg} at (200,54) size 50x50
+        LayoutSVGRoot {svg} at (200,55) size 50x50
           LayoutSVGResourceFilter {filter} [id="f_hue2"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="hue"]
               [feFlood flood-color="#3340CC80" flood-opacity="1.00"]
               [feFlood flood-color="#99C06680" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
             [filter="f_hue2"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
-        LayoutSVGRoot {svg} at (250,54) size 50x50
+        LayoutSVGRoot {svg} at (250,55) size 50x50
           LayoutSVGResourceFilter {filter} [id="f_saturation2"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="saturation"]
               [feFlood flood-color="#3340CC80" flood-opacity="1.00"]
               [feFlood flood-color="#99C06680" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
             [filter="f_saturation2"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
-        LayoutSVGRoot {svg} at (300,54) size 50x50
+        LayoutSVGRoot {svg} at (300,55) size 50x50
           LayoutSVGResourceFilter {filter} [id="f_color2"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="color"]
               [feFlood flood-color="#3340CC80" flood-opacity="1.00"]
               [feFlood flood-color="#99C06680" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
             [filter="f_color2"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
-        LayoutSVGRoot {svg} at (350,54) size 50x50
+        LayoutSVGRoot {svg} at (350,55) size 50x50
           LayoutSVGResourceFilter {filter} [id="f_luminosity2"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="luminosity"]
               [feFlood flood-color="#3340CC80" flood-opacity="1.00"]
diff --git a/third_party/WebKit/LayoutTests/svg/foreignObject/background-render-phase-expected.txt b/third_party/WebKit/LayoutTests/svg/foreignObject/background-render-phase-expected.txt
index a232a1c4..75fdc60 100644
--- a/third_party/WebKit/LayoutTests/svg/foreignObject/background-render-phase-expected.txt
+++ b/third_party/WebKit/LayoutTests/svg/foreignObject/background-render-phase-expected.txt
@@ -8,3 +8,6 @@
         LayoutSVGForeignObject {foreignObject} at (0,0) size 200x50
           LayoutBlockFlow {DIV} at (0,0) size 200x50 [bgcolor=#008000]
       LayoutText {#text} at (0,0) size 0x0
+layer at (0,0) size 200x50
+  LayoutSVGForeignObject {foreignObject} at (0,0) size 200x50
+    LayoutBlockFlow {DIV} at (0,0) size 200x50 [bgcolor=#008000]
diff --git a/third_party/WebKit/LayoutTests/svg/foreignObject/body-background-expected.txt b/third_party/WebKit/LayoutTests/svg/foreignObject/body-background-expected.txt
index fc338f6f..7a6cc0e 100644
--- a/third_party/WebKit/LayoutTests/svg/foreignObject/body-background-expected.txt
+++ b/third_party/WebKit/LayoutTests/svg/foreignObject/body-background-expected.txt
@@ -7,3 +7,8 @@
       LayoutBlockFlow {html} at (0,0) size 200x100
         LayoutBlockFlow {body} at (0,0) size 200x100 [bgcolor=#008000]
           LayoutBlockFlow {div} at (0,0) size 200x100
+layer at (20,20) size 200x100
+  LayoutSVGForeignObject {foreignObject} at (20,20) size 200x100
+    LayoutBlockFlow {html} at (0,0) size 200x100
+      LayoutBlockFlow {body} at (0,0) size 200x100 [bgcolor=#008000]
+        LayoutBlockFlow {div} at (0,0) size 200x100
diff --git a/third_party/WebKit/LayoutTests/svg/foreignObject/clip-expected.txt b/third_party/WebKit/LayoutTests/svg/foreignObject/clip-expected.txt
index 3cfd5e23..51c32e9e 100644
--- a/third_party/WebKit/LayoutTests/svg/foreignObject/clip-expected.txt
+++ b/third_party/WebKit/LayoutTests/svg/foreignObject/clip-expected.txt
@@ -11,3 +11,7 @@
           LayoutBlockFlow {DIV} at (0,0) size 200x50 [bgcolor=#00FE00]
           LayoutBlockFlow {DIV} at (0,50) size 200x50 [bgcolor=#FE0000]
       LayoutText {#text} at (0,0) size 0x0
+layer at (0,0) size 200x100 backgroundClip at (0,0) size 200x50 clip at (0,0) size 200x50 transparent
+  LayoutSVGForeignObject {foreignObject} at (0,0) size 200x100
+    LayoutBlockFlow {DIV} at (0,0) size 200x50 [bgcolor=#00FE00]
+    LayoutBlockFlow {DIV} at (0,50) size 200x50 [bgcolor=#FE0000]
diff --git a/third_party/WebKit/LayoutTests/svg/foreignObject/disallowed-svg-nodes-as-direct-children-expected.txt b/third_party/WebKit/LayoutTests/svg/foreignObject/disallowed-svg-nodes-as-direct-children-expected.txt
index fe01e93..42717fb5 100644
--- a/third_party/WebKit/LayoutTests/svg/foreignObject/disallowed-svg-nodes-as-direct-children-expected.txt
+++ b/third_party/WebKit/LayoutTests/svg/foreignObject/disallowed-svg-nodes-as-direct-children-expected.txt
@@ -3,3 +3,5 @@
 layer at (0,0) size 800x600
   LayoutSVGRoot {svg} at (0,0) size 800x600
     LayoutSVGForeignObject {foreignObject} at (0,0) size 300x100
+layer at (0,0) size 300x100
+  LayoutSVGForeignObject {foreignObject} at (0,0) size 300x100
diff --git a/third_party/WebKit/LayoutTests/svg/foreignObject/filter-expected.txt b/third_party/WebKit/LayoutTests/svg/foreignObject/filter-expected.txt
index 67c74aad..5db1c93 100644
--- a/third_party/WebKit/LayoutTests/svg/foreignObject/filter-expected.txt
+++ b/third_party/WebKit/LayoutTests/svg/foreignObject/filter-expected.txt
@@ -12,3 +12,7 @@
           LayoutBlockFlow {DIV} at (0,0) size 200x50 [bgcolor=#008000]
           LayoutBlockFlow {DIV} at (0,50) size 200x50 [bgcolor=#FF0000]
       LayoutText {#text} at (0,0) size 0x0
+layer at (0,0) size 200x100 transparent
+  LayoutSVGForeignObject {foreignObject} at (0,0) size 200x100
+    LayoutBlockFlow {DIV} at (0,0) size 200x50 [bgcolor=#008000]
+    LayoutBlockFlow {DIV} at (0,50) size 200x50 [bgcolor=#FF0000]
diff --git a/third_party/WebKit/LayoutTests/svg/foreignObject/mask-expected.txt b/third_party/WebKit/LayoutTests/svg/foreignObject/mask-expected.txt
index e788d9de..06b3c42 100644
--- a/third_party/WebKit/LayoutTests/svg/foreignObject/mask-expected.txt
+++ b/third_party/WebKit/LayoutTests/svg/foreignObject/mask-expected.txt
@@ -11,3 +11,7 @@
           LayoutBlockFlow {DIV} at (0,0) size 200x50 [bgcolor=#008000]
           LayoutBlockFlow {DIV} at (0,50) size 200x50 [bgcolor=#FF0000]
       LayoutText {#text} at (0,0) size 0x0
+layer at (0,0) size 200x100 backgroundClip at (0,0) size 200x50 clip at (0,0) size 200x50 transparent
+  LayoutSVGForeignObject {foreignObject} at (0,0) size 200x100
+    LayoutBlockFlow {DIV} at (0,0) size 200x50 [bgcolor=#008000]
+    LayoutBlockFlow {DIV} at (0,50) size 200x50 [bgcolor=#FF0000]
diff --git a/third_party/WebKit/LayoutTests/svg/foreignObject/multiple-foreign-objects-expected.txt b/third_party/WebKit/LayoutTests/svg/foreignObject/multiple-foreign-objects-expected.txt
index ce3c40a..b2139e2 100644
--- a/third_party/WebKit/LayoutTests/svg/foreignObject/multiple-foreign-objects-expected.txt
+++ b/third_party/WebKit/LayoutTests/svg/foreignObject/multiple-foreign-objects-expected.txt
@@ -9,3 +9,9 @@
         LayoutSVGForeignObject {foreignObject} at (150,0) size 100x100
           LayoutBlockFlow {DIV} at (0,0) size 100x100 [bgcolor=#008000]
       LayoutText {#text} at (0,0) size 0x0
+layer at (0,0) size 100x100
+  LayoutSVGForeignObject {foreignObject} at (0,0) size 100x100
+    LayoutBlockFlow {DIV} at (0,0) size 100x100 [bgcolor=#008000]
+layer at (150,0) size 100x100
+  LayoutSVGForeignObject {foreignObject} at (150,0) size 100x100
+    LayoutBlockFlow {DIV} at (0,0) size 100x100 [bgcolor=#008000]
diff --git a/third_party/WebKit/LayoutTests/svg/hixie/mixed/004-expected.txt b/third_party/WebKit/LayoutTests/svg/hixie/mixed/004-expected.txt
index 72300e0..6892ace 100644
--- a/third_party/WebKit/LayoutTests/svg/hixie/mixed/004-expected.txt
+++ b/third_party/WebKit/LayoutTests/svg/hixie/mixed/004-expected.txt
@@ -1,8 +1,8 @@
 layer at (0,0) size 800x600
   LayoutView at (0,0) size 800x600
-layer at (0,0) size 800x220
-  LayoutBlockFlow {html} at (0,0) size 800x220
-    LayoutBlockFlow {body} at (8,8) size 784x204
+layer at (0,0) size 800x221
+  LayoutBlockFlow {html} at (0,0) size 800x221
+    LayoutBlockFlow {body} at (8,8) size 784x205
       LayoutSVGRoot {svg} at (0,0) size 200x200
         LayoutSVGEllipse {circle} at (0,0) size 100x100 [fill={[type=SOLID] [color=#FF0000]}] [cx=50.00] [cy=50.00] [r=50.00]
         LayoutSVGEllipse {circle} at (0,0) size 100x100 [fill={[type=SOLID] [color=#008000]}] [cx=50.00] [cy=50.00] [r=50.00]
diff --git a/third_party/WebKit/LayoutTests/svg/hixie/mixed/005-expected.txt b/third_party/WebKit/LayoutTests/svg/hixie/mixed/005-expected.txt
index 72300e0..6892ace 100644
--- a/third_party/WebKit/LayoutTests/svg/hixie/mixed/005-expected.txt
+++ b/third_party/WebKit/LayoutTests/svg/hixie/mixed/005-expected.txt
@@ -1,8 +1,8 @@
 layer at (0,0) size 800x600
   LayoutView at (0,0) size 800x600
-layer at (0,0) size 800x220
-  LayoutBlockFlow {html} at (0,0) size 800x220
-    LayoutBlockFlow {body} at (8,8) size 784x204
+layer at (0,0) size 800x221
+  LayoutBlockFlow {html} at (0,0) size 800x221
+    LayoutBlockFlow {body} at (8,8) size 784x205
       LayoutSVGRoot {svg} at (0,0) size 200x200
         LayoutSVGEllipse {circle} at (0,0) size 100x100 [fill={[type=SOLID] [color=#FF0000]}] [cx=50.00] [cy=50.00] [r=50.00]
         LayoutSVGEllipse {circle} at (0,0) size 100x100 [fill={[type=SOLID] [color=#008000]}] [cx=50.00] [cy=50.00] [r=50.00]
diff --git a/third_party/WebKit/LayoutTests/svg/overflow/overflow-on-foreignObject-expected.txt b/third_party/WebKit/LayoutTests/svg/overflow/overflow-on-foreignObject-expected.txt
index 96080e6e..b8f96b01 100644
--- a/third_party/WebKit/LayoutTests/svg/overflow/overflow-on-foreignObject-expected.txt
+++ b/third_party/WebKit/LayoutTests/svg/overflow/overflow-on-foreignObject-expected.txt
@@ -3,5 +3,7 @@
 layer at (0,0) size 500x500
   LayoutSVGRoot {svg} at (0,0) size 500x500
     LayoutSVGForeignObject {foreignObject} at (100,100) size 300x300
+layer at (100,100) size 300x300 scrollWidth 6006 scrollHeight 6006
+  LayoutSVGForeignObject {foreignObject} at (100,100) size 300x300
 layer at (100,100) size 6006x6006 backgroundClip at (100,100) size 300x300 clip at (100,100) size 300x300
   LayoutBlockFlow (positioned) {html:div} at (0,0) size 6006x6006 [bgcolor=#008000] [border: (3px solid #000000)]
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/overflow/overflow-on-outermost-svg-element-in-xhtml-auto-expected.txt b/third_party/WebKit/LayoutTests/svg/overflow/overflow-on-outermost-svg-element-in-xhtml-auto-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/platform/win/svg/overflow/overflow-on-outermost-svg-element-in-xhtml-auto-expected.txt
rename to third_party/WebKit/LayoutTests/svg/overflow/overflow-on-outermost-svg-element-in-xhtml-auto-expected.txt
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/overflow/overflow-on-outermost-svg-element-in-xhtml-defaults-expected.txt b/third_party/WebKit/LayoutTests/svg/overflow/overflow-on-outermost-svg-element-in-xhtml-defaults-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/platform/win/svg/overflow/overflow-on-outermost-svg-element-in-xhtml-defaults-expected.txt
rename to third_party/WebKit/LayoutTests/svg/overflow/overflow-on-outermost-svg-element-in-xhtml-defaults-expected.txt
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/overflow/overflow-on-outermost-svg-element-in-xhtml-hidden-expected.txt b/third_party/WebKit/LayoutTests/svg/overflow/overflow-on-outermost-svg-element-in-xhtml-hidden-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/platform/win/svg/overflow/overflow-on-outermost-svg-element-in-xhtml-hidden-expected.txt
rename to third_party/WebKit/LayoutTests/svg/overflow/overflow-on-outermost-svg-element-in-xhtml-hidden-expected.txt
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/overflow/overflow-on-outermost-svg-element-in-xhtml-scroll-expected.txt b/third_party/WebKit/LayoutTests/svg/overflow/overflow-on-outermost-svg-element-in-xhtml-scroll-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/platform/win/svg/overflow/overflow-on-outermost-svg-element-in-xhtml-scroll-expected.txt
rename to third_party/WebKit/LayoutTests/svg/overflow/overflow-on-outermost-svg-element-in-xhtml-scroll-expected.txt
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/overflow/overflow-on-outermost-svg-element-in-xhtml-visible-expected.txt b/third_party/WebKit/LayoutTests/svg/overflow/overflow-on-outermost-svg-element-in-xhtml-visible-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/platform/win/svg/overflow/overflow-on-outermost-svg-element-in-xhtml-visible-expected.txt
rename to third_party/WebKit/LayoutTests/svg/overflow/overflow-on-outermost-svg-element-in-xhtml-visible-expected.txt
diff --git a/third_party/WebKit/LayoutTests/svg/stroke/empty-path-expected.txt b/third_party/WebKit/LayoutTests/svg/stroke/empty-path-expected.txt
index 609dbebe..215c7adcd 100644
--- a/third_party/WebKit/LayoutTests/svg/stroke/empty-path-expected.txt
+++ b/third_party/WebKit/LayoutTests/svg/stroke/empty-path-expected.txt
@@ -1,8 +1,8 @@
 layer at (0,0) size 800x600
   LayoutView at (0,0) size 800x600
-layer at (0,0) size 800x120
-  LayoutBlockFlow {HTML} at (0,0) size 800x120
-    LayoutBlockFlow {BODY} at (8,8) size 784x104
+layer at (0,0) size 800x121
+  LayoutBlockFlow {HTML} at (0,0) size 800x121
+    LayoutBlockFlow {BODY} at (8,8) size 784x105
       LayoutSVGRoot {svg} at (0,0) size 100x100
         LayoutSVGPath {path} at (0,0) size 0x0 [fill={[type=SOLID] [color=#000000]}] [data=""]
       LayoutText {#text} at (0,0) size 0x0
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/zoom/page/zoom-clip-path-expected.txt b/third_party/WebKit/LayoutTests/svg/zoom/page/zoom-clip-path-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/platform/win/svg/zoom/page/zoom-clip-path-expected.txt
rename to third_party/WebKit/LayoutTests/svg/zoom/page/zoom-clip-path-expected.txt
diff --git a/third_party/WebKit/LayoutTests/svg/zoom/page/zoom-foreign-content-expected.png b/third_party/WebKit/LayoutTests/svg/zoom/page/zoom-foreign-content-expected.png
index fa77093..9c89c21 100644
--- a/third_party/WebKit/LayoutTests/svg/zoom/page/zoom-foreign-content-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/zoom/page/zoom-foreign-content-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/zoom/page/zoom-foreign-content-expected.txt b/third_party/WebKit/LayoutTests/svg/zoom/page/zoom-foreign-content-expected.txt
index 7c98cfc..bad70ac 100644
--- a/third_party/WebKit/LayoutTests/svg/zoom/page/zoom-foreign-content-expected.txt
+++ b/third_party/WebKit/LayoutTests/svg/zoom/page/zoom-foreign-content-expected.txt
@@ -2,12 +2,21 @@
   LayoutView at (0,0) size 800x600
 layer at (0,0) size 800x600
   LayoutSVGRoot {svg} at (0,0) size 800x600
+    LayoutSVGRect {rect} at (0,0) size 100x100 [fill={[type=SOLID] [color=#0000FF]}] [x=0.00] [y=0.00] [width=100.00] [height=100.00]
     LayoutSVGForeignObject {foreignObject} at (0,0) size 800x600
       LayoutSVGRoot {svg} at (0,0) size 300x150
-        LayoutSVGRect {rect} at (0,0) size 99x99 [fill={[type=SOLID] [color=#FF0000]}] [x=0.00] [y=0.00] [width=99.00] [height=99.00]
+        LayoutSVGRect {rect} at (0,0) size 99x99 [fill={[type=SOLID] [color=#FFA500]}] [x=0.00] [y=0.00] [width=99.00] [height=99.00]
       LayoutText {#text} at (0,0) size 0x0
     LayoutSVGForeignObject {foreignObject} at (0,0) size 800x600
       LayoutBlockFlow {html} at (0,0) size 800x99
-        LayoutBlockFlow {div} at (0,0) size 99x99 [bgcolor=#FF0000]
-    LayoutSVGRect {rect} at (0,0) size 100x100 [fill={[type=SOLID] [color=#008000]}] [x=0.00] [y=0.00] [width=100.00] [height=100.00]
+        LayoutBlockFlow {div} at (0,0) size 99x99 [bgcolor=#008000]
     LayoutSVGHiddenContainer {defs} at (0,0) size 0x0
+layer at (0,0) size 800x600
+  LayoutSVGForeignObject {foreignObject} at (0,0) size 800x600
+    LayoutSVGRoot {svg} at (0,0) size 300x150
+      LayoutSVGRect {rect} at (0,0) size 99x99 [fill={[type=SOLID] [color=#FFA500]}] [x=0.00] [y=0.00] [width=99.00] [height=99.00]
+    LayoutText {#text} at (0,0) size 0x0
+layer at (0,0) size 800x600
+  LayoutSVGForeignObject {foreignObject} at (0,0) size 800x600
+    LayoutBlockFlow {html} at (0,0) size 800x99
+      LayoutBlockFlow {div} at (0,0) size 99x99 [bgcolor=#008000]
diff --git a/third_party/WebKit/LayoutTests/svg/zoom/page/zoom-foreign-content.svg b/third_party/WebKit/LayoutTests/svg/zoom/page/zoom-foreign-content.svg
index 06c8c07..1d4c8dc 100644
--- a/third_party/WebKit/LayoutTests/svg/zoom/page/zoom-foreign-content.svg
+++ b/third_party/WebKit/LayoutTests/svg/zoom/page/zoom-foreign-content.svg
@@ -2,21 +2,21 @@
 <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" onload="runAfterLayoutAndPaint(repaintTest, true);">
     <!-- This test verifies that foreignObject content does not have the zoom factor applied twice. -->
 
+    <!-- After zooming, there should be exactly one pixel of blue in each dimension -->
+    <rect width="100" height="100" fill="blue"/>
+
     <foreignObject width="800" height="600">
         <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
-            <rect width="99" height="99" fill="red"/>
+            <rect width="99" height="99" fill="orange"/>
         </svg>
     </foreignObject>
 
     <foreignObject width="800" height="600">
         <html xmlns="http://www.w3.org/1999/xhtml">
-            <div style="background-color: red; width: 99px; height: 99px;"></div>
+            <div style="background-color: green; width: 99px; height: 99px;"></div>
         </html>
     </foreignObject>
 
-    <!-- After zooming, this rect should still be obscuring everything. -->
-    <rect width="100" height="100" fill="green"/>
-
     <defs>
         <script>var zoomCount = 4;</script>
         <script xlink:href="../../../resources/run-after-layout-and-paint.js"/>
diff --git a/third_party/WebKit/LayoutTests/virtual/enable-webauthn/http/tests/credentialmanager/credentialscontainer-create-from-nested-frame-expected.txt b/third_party/WebKit/LayoutTests/virtual/enable-webauthn/http/tests/credentialmanager/credentialscontainer-create-from-nested-frame-expected.txt
index dff5413..f7059535 100644
--- a/third_party/WebKit/LayoutTests/virtual/enable-webauthn/http/tests/credentialmanager/credentialscontainer-create-from-nested-frame-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/enable-webauthn/http/tests/credentialmanager/credentialscontainer-create-from-nested-frame-expected.txt
@@ -1,6 +1,10 @@
+CONSOLE WARNING: line 10: The following mojom is loaded multiple times: mojo/public/mojom/base/string16.mojom
+CONSOLE WARNING: line 10: The following mojom is loaded multiple times: mojo/public/mojom/base/big_buffer.mojom
 CONSOLE WARNING: line 10: The following mojom is loaded multiple times: url/mojom/origin.mojom
 CONSOLE WARNING: line 10: The following mojom is loaded multiple times: url/mojom/url.mojom
 CONSOLE WARNING: line 10: The following mojom is loaded multiple times: mojo/public/mojom/base/time.mojom
+CONSOLE WARNING: line 10: The following mojom is loaded multiple times: mojo/public/mojom/base/string16.mojom
+CONSOLE WARNING: line 10: The following mojom is loaded multiple times: mojo/public/mojom/base/big_buffer.mojom
 CONSOLE WARNING: line 10: The following mojom is loaded multiple times: url/mojom/origin.mojom
 CONSOLE WARNING: line 10: The following mojom is loaded multiple times: url/mojom/url.mojom
 CONSOLE WARNING: line 10: The following mojom is loaded multiple times: mojo/public/mojom/base/time.mojom
diff --git a/third_party/WebKit/LayoutTests/virtual/enable-webauthn/http/tests/credentialmanager/credentialscontainer-get-from-nested-frame-expected.txt b/third_party/WebKit/LayoutTests/virtual/enable-webauthn/http/tests/credentialmanager/credentialscontainer-get-from-nested-frame-expected.txt
index cb497f3..aa809c9 100644
--- a/third_party/WebKit/LayoutTests/virtual/enable-webauthn/http/tests/credentialmanager/credentialscontainer-get-from-nested-frame-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/enable-webauthn/http/tests/credentialmanager/credentialscontainer-get-from-nested-frame-expected.txt
@@ -1,6 +1,10 @@
+CONSOLE WARNING: line 10: The following mojom is loaded multiple times: mojo/public/mojom/base/string16.mojom
+CONSOLE WARNING: line 10: The following mojom is loaded multiple times: mojo/public/mojom/base/big_buffer.mojom
 CONSOLE WARNING: line 10: The following mojom is loaded multiple times: url/mojom/origin.mojom
 CONSOLE WARNING: line 10: The following mojom is loaded multiple times: url/mojom/url.mojom
 CONSOLE WARNING: line 10: The following mojom is loaded multiple times: mojo/public/mojom/base/time.mojom
+CONSOLE WARNING: line 10: The following mojom is loaded multiple times: mojo/public/mojom/base/string16.mojom
+CONSOLE WARNING: line 10: The following mojom is loaded multiple times: mojo/public/mojom/base/big_buffer.mojom
 CONSOLE WARNING: line 10: The following mojom is loaded multiple times: url/mojom/origin.mojom
 CONSOLE WARNING: line 10: The following mojom is loaded multiple times: url/mojom/url.mojom
 CONSOLE WARNING: line 10: The following mojom is loaded multiple times: mojo/public/mojom/base/time.mojom
diff --git a/third_party/WebKit/LayoutTests/xmlviewer/long-multi-byte-char-expected.html b/third_party/WebKit/LayoutTests/xmlviewer/long-multi-byte-char-expected.html
new file mode 100644
index 0000000..dc94de2
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/xmlviewer/long-multi-byte-char-expected.html
@@ -0,0 +1,8 @@
+<!doctype html>

+<html xmlns:v="urn:schemas-microsoft-com:vml">

+  <head>

+  </head>

+  <body id="test-body">

+    Test passes if you see this line, and this line alone.

+  </body>

+</html>

diff --git a/third_party/WebKit/LayoutTests/xmlviewer/long-multi-byte-char.xml b/third_party/WebKit/LayoutTests/xmlviewer/long-multi-byte-char.xml
new file mode 100644
index 0000000..85c4e3e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/xmlviewer/long-multi-byte-char.xml
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="windows-1251"?>

+<?xml-stylesheet type="text/xsl" href="resources/long-multi-byte-char.xslt"?>

+<home>

+  Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Vulputate odio ut enim blandit volutpat maecenas volutpat blandit aliquam. Ornare aenean euismod elementum nisi quis eleifend quam. Urna et pharetra pharetra massa massa ultricies mi quis. Id nibh tortor id aliquet lectus proin nibh nisl. Elementum eu facilisis sed odio morbi. Nibh nisl condimentum id venenatis a condimentum vitae sapien. Aliquam vestibulum morbi blandit cursus risus at ultrices. At tellus at urna condimentum mattis pellentesque id nibh tortor. Tortor id aliquet lectus proin nibh nisl condimentum id. Nulla malesuada pellentesque elit eget. Porta nibh venenatis cras sed felis eget. Volutpat est velit egestas dui id ornare. Donec ac odio tempor orci. Lectus mauris ultrices eros in. Amet dictum sit amet justo. Facilisis magna etiam tempor orci eu lobortis elementum. Pellentesque dignissim enim sit amet venenatis urna cursus eget. Sit amet facilisis magna etiam tempor. Ornare arcu odio ut sem nulla pharetra.

+

+  Porttitor massa id neque aliquam vestibulum morbi. Euismod lacinia at quis risus sed vulputate odio ut. Massa id neque aliquam vestibulum morbi blandit cursus. Tristique magna sit amet purus gravida. Felis eget nunc lobortis mattis. Placerat orci nulla pellentesque dignissim. Malesuada bibendum arcu vitae elementum curabitur vitae nunc. Fames ac turpis egestas sed. Felis eget nunc lobortis mattis aliquam. Ut faucibus pulvinar elementum integer enim neque volutpat ac. Sollicitudin tempor id eu nisl nunc mi ipsum. Platea dictumst vestibulum rhoncus est pellentesque elit ullamcorper dignissim cras. Maecenas volutpat blandit aliquam etiam erat velit. Donec massa sapien faucibus et.

+

+  Duis ultricies lacus sed turpis tincidunt id aliquet risus. In tellus integer feugiat scelerisque varius morbi. Sit amet tellus cras adipiscing enim eu. Mi eget mauris pharetra et ultrices. Volutpat lacus laoreet non curabitur gravida arcu ac. Euismod quis viverra nibh cras pulvinar mattis nunc sed. In eu mi bibendum neque egestas. Fames ac turpis egestas maecenas pharetra convallis. Iaculis at erat pellentesque adipiscing commodo elit at imperdiet dui. Dui ut ornare lectus sit amet. Venenatis urna cursus eget nunc scelerisque viverra mauris in aliquam. Fermentum posuere urna nec tincidunt praesent semper feugiat nibh. Nec feugiat nisl pretium fusce id velit ut tortor pretium. Rhoncus mattis rhoncus urna neque viverra justo nec ultrices dui. Aenean pharetra magna ac placerat vestibulum lectus mauris ultrices eros. Erat nam at lectus urna duis convallis convallis. Tristique senectus et netus et malesuada fames ac. Purus in massa tempor nec feugiat nisl pretium fusce id. Et magnis dis parturient montes nascetur ridiculus.

+

+  At elementum eu facilisis sed odio morbi. Interdum velit laoreet id donec ultrices tincidunt arcu non sodales. Sapien nec sagittis aliquam malesuada bibendum. Viverra mauris in aliquam sem fringilla ut. Amet nulla facilisi morbi tempus iaculis urna id volutpat lacus. Mauris pellentesque pulvinar pellentesque habitant morbi tristique senectus et netus. Bibendum at varius vel pharetra vel turpis nunc eget. Arcu non odio euismod lacinia at quis risus. In massa tempor nec feugiat nisl pretium fusce id velit. Sem et tortor consequat id porta nibh venenatis cras sed. Amet risus nullam eget felis eget nunc. Imperdiet proin fermentum leo vel orci porta non pulvinar. Ac auctor augue mauris augue neque. Tellus at urna condimentum mattis. Amet luctus venenatis lectus magna fringilla urna porttitor. Tincidunt praesent semper feugiat nibh sed pulvinar.

+

+  Faucibus scelerisque eleifend donec pretium vulputate sapien nec sagittis. Elit at imperdiet dui accumsan sit amet nulla. Ut consequat semper viverra nam libero justo laoreet sit. Morbi tincidunt augue interdum velit euismod in. Platea dictumst vestibulum rhoncus est. Sem et tortor consequat id porta nibh. Tristique risus nec feugiat in fermentum posuere. Nibh cras pulvinar mattis nunc sed blandit libero volutpat sed. Velit egestas dui id ornare arcu. Amet commodo nulla facilisi nullam vehicula ipsum a arcu. Venenatis tellus in metus vulputate eu. Sollicitudin ac orci phasellus egestas tellus rutrum tellus. Faucibus nisl tincidunt eget nullam. Et netus et malesuada fames ac turpis egestas maecenas. Diam quam nulla porttitor massa id neque aliquam vestibulum.

+

+  Ac turpis egestas integer eget aliquet nibh praesent tristique magna. Tellus pellentesque eu tincidunt tortor aliquam nulla facilisi cras. Risus pretium quam vulputate dignissim suspendisse in. Nunc sed id semper risus in hendrerit gravida rutrum. Interdum velit euismod in pellentesque massa placerat duis. Amet mauris commodo quis imperdiet massa tincidunt. Urna duis convallis convallis tellus id. Aliquam vestibulum morbi blandit cursus. Magna ac placerat vestibulum lectus mauris ultrices eros in cursus. Vitae et leo duis ut diam. Orci porta non pulvinar neque laoreet suspendisse interdum consectetur. Faucibus nisl tincidunt eget nullam non nisi est sit amet.

+

+  Vel risus commodo viverra maecenas accumsan lacus. Magna sit amet purus gravida quis blandit. Purus non enim praesent elementum facilisis leo. Purus sit amet luctus venenatis lectus magna fringilla urna porttitor. Cursus sit amet dictum sit. Tellus cras adipiscing enim eu turpis egestas pretium. Tempus imperdiet nulla malesuada pellentesque elit. Etiam non quam lacus suspendisse faucibus interdum posuere. Tempus quam pellentesque nec nam aliquam sem et. Semper feugiat nibh sed pulvinar proin gravida hendrerit lectus a. Maecenas sed enim ut sem. Amet venenatis urna cursus eget nunc scelerisque. Curabitur vitae nunc sed velit. Risus feugiat in ante metus dictum. Auctor elit sed vulputate mi sit amet mauris commodo. Quam adipiscing vitae proin sagittis nisl rhoncus mattis rhoncus urna. Nibh sed pulvinar proin gravida hendrerit. Suscipit adipiscing bibendum est ultricies integer quis auctor. Odio facilisis mauris sit amet.

+

+  Turpis egestas integer eget aliquet nibh. Nisl tincidunt eget nullam non nisi est sit amet facilisis. Adipiscing elit duis tristique sollicitudin nibh sit amet. Nec feugiat nisl pretium fusce id. Fames ac turpis egestas integer. In dictum non consectetur a erat nam at lectus. Interdum velit euismod in pellentesque massa placerat duis ultricies. Enim facilisis gravida neque convallis a cras semper auctor neque. Condimentum lacinia quis vel eros donec ac odio tempor orci. Quam id leo in vitae turpis massa sed elementum. Mauris pharetra et ultrices neque ornare aenean.

+

+  Pulvinar sapien et ligula ullamcorper malesuada proin libero nunc consequat. Mus mauris vitae ultricies leo integer malesuada nunc vel risus. Placerat orci nulla pellentesque dignissim enim sit amet venenatis. Dignissim sodales ut eu sem integer. Amet consectetur adipiscing elit pellentesque habitant morbi tristique senectus. Dignissim enim sit amet venenatis urna cursus. Nisl vel pretium lectus quam. Quis risus sed vulputate odio ut. Quam elementum pulvinar etiam non quam lacus suspendisse faucibus interdum. Faucibus et molestie ac feugiat sed. Mauris cursus mattis molestie a iaculis at erat pellentesque. Odio aenean sed adipiscing diam donec adipiscing tristique risus. Metus aliquam eleifend mi in nulla posuere sollicitudin aliquam. Pulvinar mattis nunc sed blandit libero volutpat sed cras. Massa placerat duis ultricies lacus.

+

+  Tellus id interdum velit laoreet. Sed faucibus turpis in eu mi bibendum neque egestas. Proin sagittis nisl rhoncus mattis. Arcu vitae elementum curabitur vitae nunc sed. Amet risus nullam eget felis eget nunc. Lacinia quis vel eros donec ac odio tempor. Enim eu turpis egestas pretium aenean pharetra magna ac. Suspendisse sed nisi lacus sed viverra tellus in hac. At volutpat diam ut venenatis tellus in metus vulputate. Ornare arcu odio ut sem nulla pharetra diam sit amet. Quis hendrerit dolor magna eget est. Pellentesque massa placerat duis ultricies lacus sed turpis.

+

+  Magna eget est lorem ipsum dolor sit amet consectetur adipiscing. At varius vel pharetra vel turpis nunc. Dis parturient montes nascetur ridiculus mus mauris vitae. Quam vulputate dignissim suspendisse in est ante. Neque convallis a cras semper auctor neque. Donec ultrices tincidunt arcu non sodales neque sodales ut etiam. Urna nunc id cursus metus aliquam eleifend mi in nulla. Nunc sed velit dignissim sodales ut eu sem integer vitae. Auctor eu augue ut lectus arcu. Nunc sed velit dignissim sodales ut. Cum sociis natoque penatibus et magnis dis parturient montes.

+

+  Neque aliquam vestibulum morbi blandit. Urna condimentum mattis pellentesque id. Dapibus ultrices in iaculis nunc sed augue lacus viverra. Dictum sit amet justo donec enim diam. Sit amet nulla facilisi morbi tempus. Duis tristique sollicitudin nibh sit amet commodo nulla facilisi. Lacus sed turpis tincidunt id aliquet risus feugiat in ante. Sed viverra ipsum nunc aliquet bibendum enim facilisis. Consequat interdum varius sit amet mattis vulputate enim. Cum sociis natoque penatibus et magnis dis. Cursus mattis molestie a iaculis at erat. Sed sed risus pretium quam. Scelerisque fermentum dui faucibus in. Feugiat nisl pretium fusce id velit. Orci a scelerisque purus semper eget duis. Adipiscing at in tellus integer feugiat.

+

+  Dui faucibus in ornare quam viverra orci. Aliquam eleifend mi in nulla posuere. Eleifend quam adipiscing vitae proin sagittis. Amet commodo nulla facilisi nullam vehicula. Interdum consectetur libero id faucibus nisl tincidunt eget nullam. Leo vel orci porta non pulvinar neque laoreet suspendisse interdum. Posuere sollicitudin aliquam ultrices sagittis orci a. Nec ultrices dui sapien eget mi proin. Sodales neque sodales ut etiam sit amet. Ac placerat vestibulum lectus mauris ultrices eros in cursus. Amet facilisis magna etiam tempor orci.

+

+  Auctor eu augue ut lectus arcu bibendum at varius vel. Aliquam ultrices sagittis orci a scelerisque purus semper eget duis. Volutpat ac tincidunt vitae semper. Ornare lectus sit amet est placerat in egestas. Ac orci phasellus egestas tellus rutrum tellus pellentesque. Ullamcorper malesuada proin libero nunc consequat. Eget est lorem ipsum dolor sit amet. Et netus et malesuada fames ac turpis egestas. Donec massa sapien faucibus et molestie ac. Laoreet sit amet cursus sit amet dictum. Eget nullam non nisi est sit amet facilisis magna etiam. At tempor commodo ullamcorper a lacus vestibulum sed arcu non. Eget nulla facilisi etiam dignissim diam quis enim.

+

+  Ante metus dictum at tempor commodo ullamcorper. Ultricies mi quis hendrerit dolor magna eget est lorem ipsum. Nunc sed blandit libero volutpat. Tristique senectus et netus et. Nisi lacus sed viverra tellus in hac habitasse platea dictumst. Elementum facilisis leo vel fringilla. Lacus viverra vitae congue eu. Nisl condimentum id venenatis a condimentum vitae. Ipsum a arcu cursus vitae congue mauris rhoncus aenean vel. Felis imperdiet proin fermentum leo vel orci porta. Malesuada fames ac turpis egestas sed tempus. Aenean et tortor at risus viverra adipiscing at. Ultrices sagittis orci a scelerisque purus semper.

+

+  Orci eu lobortis elementum nibh tellus molestie nunc non blandit. Vel pharetra vel turpis nunc eget lorem. Diam maecenas ultricies mi eget. Consectetur libero id faucibus nisl tincidunt eget nullam non. Sit amet purus gravida quis blandit turpis cursus. Eget est lorem ipsum dolor sit amet consectetur. Pellentesque habitant morbi tristique senectus et netus. Nunc mattis enim ut tellus elementum sagittis vitae et leo. Laoreet id donec ultrices tincidunt arcu. Tellus id interdum velit laoreet id donec ultrices. Et netus et malesuada fames ac turpis egestas sed tempus. Viverra ipsum nunc aliquet bibendum enim. Mauris commodo quis imperdiet massa tincidunt nunc pulvinar sapien et. Diam vulputate ut pharetra sit amet aliquam. Eu tincidunt tortor aliquam nulla facilisi cras fermentum.

+

+  Massa sapien faucibus et molestie ac feugiat. Eget egestas purus viverra accumsan in nisl. Metus dictum at tempor commodo ullamcorper a lacus. Tempus imperdiet nulla malesuada pellentesque elit. At erat pellentesque adipiscing commodo elit at imperdiet. Lectus quam id leo in vitae turpis. Donec ultrices tincidunt arcu non sodales neque sodales. Semper eget duis at tellus at urna. Elementum sagittis vitae et leo duis ut. Imperdiet sed euismod nisi porta. Odio eu feugiat pretium nibh ipsum consequat nisl. Sit amet nulla facilisi morbi tempus iaculis. Sed pulvinar proin gravida hendrerit. Ut venenatis tellus in metus vulputate eu scelerisque felis imperdiet. Vitae semper quis lectus nulla at volutpat. Ut tortor pretium viverra suspendisse potenti nullam. Vitae ultricies leo integer malesuada nunc vel risus commodo viverra. Varius quam quisque id diam vel quam elementum. Cursus mattis molestie a iaculis at erat pellentesque adipiscing.

+

+  Lectus mauris ultrices eros in cursus turpis massa. Id aliquet risus feugiat in ante metus dictum at. Parturient montes nascetur ridiculus mus. Blandit massa enim nec dui. Ornare arcu odio ut sem. Cursus in hac habitasse platea. Eu sem integer vitae justo eget magna fermentum iaculis eu. Pharetra magna ac placerat vestibulum. Aenean euismod elementum nisi quis eleifend quam adipiscing vitae proin. Mi bibendum neque egestas congue quisque egestas. Sapien faucibus et molestie ac feugiat sed lectus vestibulum. Urna id volutpat lacus laoreet non curabitur gravida arcu. Quis lectus nulla at volutpat diam ut.

+

+  Et netus et malesuada fames ac. At varius vel pharetra vel turpis. Nisi quis eleifend quam adipiscing vitae proin. Donec enim diam vulputate ut pharetra sit amet. Lectus arcu bibendum at varius vel pharetra vel turpis. Et molestie ac feugiat sed lectus. Cursus eget nunc scelerisque viverra mauris. Posuere lorem ipsum dolor sit amet consectetur adipiscing elit duis. Ultrices tincidunt arcu non sodales. Tempor orci dapibus ultrices in. Vehicula ipsum a arcu cursus vitae congue. Lectus vestibulum mattis ullamcorper velit sed ullamcorper morbi tincidunt. Erat velit scelerisque in dictum non consectetur a erat nam. Risus quis varius quam quisque id. Lobortis elementum nibh tellus molestie. Pellentesque nec nam aliquam sem et tortor.

+

+  Nibh sed pulvinar proin gravida hendrerit lectus a. Consectetur a erat nam at lectus urna duis convallis. Consectetur a erat nam at lectus urna duis convallis convallis. Hac habitasse platea dictumst quisque sagittis purus sit amet. Sed odio morbi quis commodo. Cras fermentum odio eu feugiat pretium nibh ipsum consequat nisl. Consectetur libero id faucibus nisl tincidunt eget nullam. Convallis aenean et tortor at risus viverra adipiscing. At varius vel pharetra vel turpis nunc eget lorem. Tempus imperdiet nulla malesuada pellentesque elit eget gravida. Lobortis feugiat vivamus at augue eget arcu dictum varius. Bibendum ut tristique et egestas quis ipsum suspendisse ultrices. Nullam vehicula ipsum a arcu cursus vitae congue mauris rhoncus. Pretium nibh ipsum consequat nisl vel. Pretium aenean pharetra magna ac. Proin libero nunc consequat interdum varius sit amet. Aenean euismod elementum nisi quis eleifend quam adipiscing.

+

+  Turpis egestas maecenas pharetra convallis. Tellus in hac habitasse platea dictumst vestibulum. Est pellentesque elit ullamcorper dignissim. In pellentesque massa placerat duis ultricies lacus sed turpis tincidunt. Sed elementum tempus egestas sed sed risus pretium quam. Tellus mauris a diam maecenas. Aenean pharetra magna ac placerat vestibulum lectus mauris ultrices. Dictum at tempor commodo ullamcorper. Integer eget aliquet nibh praesent tristique magna sit amet. Venenatis tellus in metus vulputate eu scelerisque felis imperdiet proin. Risus nec feugiat in fermentum posuere urna nec tincidunt. Auctor elit sed vulputate mi sit amet mauris commodo quis. Sapien faucibus et molestie ac feugiat. Venenatis tellus in metus vulputate eu scelerisque felis. Congue mauris rhoncus aenean vel elit scelerisque mauris pellentesque. Potenti nullam ac tortor vitae purus. Ultrices gravida dictum fusce ut placerat. Ornare aenean euismod elementum nisi quis. Varius vel pharetra vel turpis. In pellentesque massa placerat duis.

+

+  Eget gravida cum sociis natoque penatibus et magnis. Diam maecenas ultricies mi eget mauris. Amet commodo nulla facilisi nullam vehicula ipsum a arcu cursus. Hendrerit gravida rutrum quisque non tellus orci ac auctor augue. Ac ut consequat semper viverra. Amet mauris commodo quis imperdiet massa tincidunt nunc pulvinar sapien. Sagittis orci a scelerisque purus semper eget duis. Leo vel fringilla est ullamcorper eget nulla facilisi etiam dignissim. Viverra orci sagittis eu volutpat odio. Leo vel orci porta non pulvinar. Lacus luctus accumsan tortor posuere ac.

+

+  Faucibus scelerisque eleifend donec pretium vulputate sapien nec sagittis aliquam. Risus ultricies tristique nulla aliquet enim tortor at auctor urna. Odio morbi quis commodo odio aenean sed adipiscing. Lacus laoreet non curabitur gravida arcu. In aliquam sem fringilla ut. Egestas egestas fringilla phasellus faucibus scelerisque. Gravida in fermentum et sollicitudin ac orci phasellus. Enim sit amet venenatis urna cursus. Egestas erat imperdiet sed euismod nisi porta lorem mollis. Mus mauris vitae ultricies leo integer malesuada nunc vel risus. Id ornare arcu odio ut sem nulla pharetra diam sit.

+

+  Sed ullamcorper morbi tincidunt ornare massa eget egestas purus. Sagittis nisl rhoncus mattis rhoncus. Integer malesuada nunc vel risus commodo viverra maecenas. Enim nec dui nunc mattis enim. Enim eu turpis egestas pretium aenean pharetra magna ac placerat. Tortor dignissim convallis aenean et. Amet aliquam id diam maecenas ultricies mi eget. Amet mattis vulputate enim nulla aliquet porttitor lacus luctus. Vel quam elementum pulvinar etiam non quam. Tincidunt id aliquet risus feugiat in ante metus dictum. Eget sit amet tellus cras. Semper feugiat nibh sed pulvinar proin gravida hendrerit lectus. Feugiat vivamus at augue eget arcu dictum varius duis at. Morbi blandit cursus risus at ultrices mi tempus. Lacus sed viverra tellus in hac habitasse platea dictumst. Eget nullam non nisi est sit amet facilisis magna. Augue ut lectus arcu bibendum at varius. Consectetur libero id faucibus nisl tincidunt eget nullam non nisi. Tincidunt dui ut ornare lectus sit amet est placerat in.

+

+  A erat nam at lectus urna duis convallis convallis tellus. Pretium viverra suspendisse potenti nullam ac tortor vitae purus faucibus. Sagittis id consectetur purus ut faucibus pulvinar. Praesent semper feugiat nibh sed pulvinar proin gravida. Mattis ullamcorper velit sed ullamcorper morbi tincidunt ornare. Viverra nibh cras pulvinar mattis nunc sed. Et malesuada fames ac turpis egestas sed tempus urna. Penatibus et magnis dis parturient montes nascetur ridiculus mus mauris. Dapibus ultrices in iaculis nunc sed augue lacus. Ullamcorper sit amet risus nullam eget felis.

+

+  Faucibus et molestie ac feugiat sed lectus vestibulum mattis. Dui faucibus in ornare quam viverra orci. Vestibulum lorem sed risus ultricies tristique. Aliquet nibh praesent tristique magna sit amet purus. Interdum velit laoreet id donec ultrices tincidunt arcu. Tempor commodo ullamcorper a lacus vestibulum sed. Congue nisi vitae suscipit tellus. Sapien faucibus et molestie ac feugiat sed lectus. Nisi lacus sed viverra tellus. Nec ultrices dui sapien eget mi proin. A diam sollicitudin tempor id eu nisl nunc. Aenean sed adipiscing diam donec. Id porta nibh venenatis cras sed felis. Imperdiet massa tincidunt nunc pulvinar sapien et. Nisl pretium fusce id velit ut tortor pretium viverra. Magna eget est lorem ipsum dolor sit. Diam phasellus vestibulum lorem sed risus ultricies.

+

+  Aliquam eleifend mi in nulla posuere sollicitudin aliquam ultrices. Mauris nunc congue nisi vitae suscipit. Cras fermentum odio eu feugiat pretium nibh. Senectus et netus et malesuada. Quam nulla porttitor massa id neque aliquam vestibulum morbi blandit. Nam aliquam sem et tortor consequat. Arcu bibendum at varius vel pharetra. Faucibus purus in massa tempor nec feugiat nisl pretium fusce. Maecenas accumsan lacus vel facilisis volutpat est velit. Diam phasellus vestibulum lorem sed risus ultricies tristique. Et malesuada fames ac turpis egestas integer eget aliquet. Leo urna molestie at elementum eu facilisis. Molestie ac feugiat sed lectus vestibulum mattis ullamcorper velit. Sapien et ligula ullamcorper malesuada proin. Odio euismod lacinia at quis. Lacus viverra vitae congue eu consequat ac felis donec et. Bibendum neque egestas congue quisque egestas diam in arcu cursus. Aenean euismod elementum nisi quis. Egestas dui id ornare arcu odio ut.

+

+  Tortor pretium viverra suspendisse potenti nullam ac. Nec tincidunt praesent semper feugiat nibh sed. Nibh tortor id aliquet lectus proin nibh nisl. Gravida rutrum quisque non tellus orci ac auctor augue. Dui id ornare arcu odio. Turpis egestas sed tempus urna. Ut sem nulla pharetra diam sit amet. Cursus metus aliquam eleifend mi in nulla posuere sollicitudin aliquam. Mi sit amet mauris commodo quis. Quam id leo in vitae turpis massa sed elementum.

+

+  Quam adipiscing vitae proin sagittis. Sapien nec sagittis aliquam malesuada bibendum arcu vitae elementum. Nibh tellus molestie nunc non blandit massa enim nec dui. Volutpat odio facilisis mauris sit amet. Vestibulum sed arcu non odio euismod lacinia. Eget nunc scelerisque viverra mauris in aliquam sem. Aenean et tortor at risus viverra adipiscing at. Quis hendrerit dolor magna eget est lorem. Id porta nibh venenatis cras sed. Ut pharetra sit amet aliquam id diam maecenas ultricies mi.

+

+  Odio aenean sed adipiscing diam donec adipiscing tristique risus. Enim nunc faucibus a pellentesque sit amet porttitor. Mus mauris vitae ultricies leo integer malesuada nunc vel risus. Convallis convallis tellus id interdum velit laoreet. Iaculis eu non diam phasellus vestibulum lorem sed risus. Nunc vel risus commodo viverra. Malesuada nunc vel risus commodo viverra maecenas accumsan. Odio aenean sed adipiscing diam donec adipiscing tristique risus nec. Cursus mattis molestie a iaculis at. Arcu vitae elementum curabitur vitae nunc sed velit dignissim. Velit egestas dui id ornare arcu odio ut sem nulla.

+

+  Urna porttitor rhoncus dolor purus non enim praesent elementum facilisis. Tincidunt nunc pulvinar sapien et ligula ullamcorper malesuada proin. Posuere morbi leo urna molestie at elementum. Cum sociis natoque penatibus et magnis dis parturient. Urna id volutpat lacus laoreet. Urna cursus eget nunc scelerisque viverra mauris in aliquam. Laoreet non curabitur gravida arcu ac tortor dignissim convallis aenean. Gravida arcu ac tortor dignissim convallis. Orci a scelerisque purus semper eget duis at. Tristique senectus et netus et malesuada fames ac turpis egestas. Ultricies lacus sed turpis tincidunt id aliquet risus feugiat in. Eu augue ut lectus arcu bibendum at varius. Vestibulum lectus mauris ultrices eros in.

+

+  Ut eu sem integer vitae justo eget magna. Non enim praesent elementum facilisis leo vel. Eget nulla facilisi etiam dignissim diam quis enim lobortis. Pellentesque pulvinar pellentesque habitant morbi. Aliquam id diam maecenas ultricies mi. Mattis molestie a iaculis at erat pellentesque adipiscing commodo elit. Justo nec ultrices dui sapien eget. Sit amet cursus sit amet. Sed risus ultricies tristique nulla aliquet enim tortor. Sit amet tellus cras adipiscing enim eu turpis. Scelerisque fermentum dui faucibus in ornare quam viverra orci. Ipsum dolor sit amet consectetur adipiscing elit ut aliquam purus. Non quam lacus suspendisse faucibus interdum. Elit pellentesque habitant morbi tristique senectus et netus et.

+

+  Vulputate odio ut enim blandit volutpat maecenas volutpat blandit. Ac orci phasellus egestas tellus rutrum tellus pellentesque eu tincidunt. Nunc congue nisi vitae suscipit tellus mauris a. Dictum non consectetur a erat. Aliquet eget sit amet tellus cras adipiscing enim. Gravida rutrum quisque non tellus orci ac auctor augue mauris. Consequat ac felis donec et. Sed vulputate odio ut enim blandit volutpat. Vulputate enim nulla aliquet porttitor lacus luctus accumsan tortor. Aenean sed adipiscing diam donec adipiscing. Nunc mi ipsum faucibus vitae aliquet nec ullamcorper sit amet. Sed viverra ipsum nunc aliquet. Nunc aliquet bibendum enim facilisis gravida neque. Laoreet id donec ultrices tincidunt arcu. Cras fermentum odio eu feugiat pretium nibh. Egestas erat imperdiet sed euismod nisi. At tempor commodo ullamcorper a lacus vestibulum sed. Odio pellentesque diam volutpat commodo.

+

+  Suspendisse interdum consectetur libero id faucibus nisl tincidunt. Orci dapibus ultrices in iaculis nunc sed augue. In hac habitasse platea dictumst quisque sagittis purus. Elementum eu facilisis sed odio. Elementum nibh tellus molestie nunc. Vulputate ut pharetra sit amet aliquam id diam maecenas ultricies. Ut sem nulla pharetra diam sit amet nisl. Blandit massa enim nec dui nunc mattis enim ut. A scelerisque purus semper eget duis. Faucibus pulvinar elementum integer enim. Amet cursus sit amet dictum sit amet. Purus in massa tempor nec feugiat nisl pretium fusce. Sed tempus urna et pharetra pharetra. Amet risus nullam eget felis eget nunc.

+

+  Urna nunc id cursus metus aliquam eleifend. Nec feugiat nisl pretium fusce id velit ut tortor. Et malesuada fames ac turpis egestas integer eget. Aliquet sagittis id consectetur purus ut faucibus pulvinar. Tellus integer feugiat scelerisque varius morbi enim nunc. Suspendisse interdum consectetur libero id faucibus nisl tincidunt eget. At imperdiet dui accumsan sit amet. Vivamus at augue eget arcu dictum varius duis. Placerat orci nulla pellentesque dignissim enim sit amet venenatis urna. Risus ultricies tristique nulla aliquet enim. Suspendisse interdum consectetur libero id faucibus nisl tincidunt eget nullam. Ac placerat vestibulum lectus mauris ultrices.

+

+  Enim ut tellus elementum sagittis vitae et leo duis ut. Sit amet purus gravida quis blandit turpis cursus. Aliquam ut porttitor leo a diam sollicitudin tempor id eu. Auctor augue mauris augue neque gravida. Tellus rutrum tellus pellentesque eu tincidunt tortor aliquam nulla. Adipiscing at in tellus integer feugiat scelerisque. Fermentum leo vel orci porta non pulvinar neque laoreet. At elementum eu facilisis sed odio morbi. Aliquam ultrices sagittis orci a scelerisque purus semper. Volutpat est velit egestas dui id. Euismod quis viverra nibh cras pulvinar mattis nunc sed blandit. Sed elementum tempus egestas sed sed.

+

+  Quisque sagittis purus sit amet volutpat consequat mauris nunc. Erat imperdiet sed euismod nisi porta lorem. Massa tempor nec feugiat nisl pretium. Erat nam at lectus urna. Fusce id velit ut tortor pretium viverra suspendisse. In vitae turpis massa sed elementum tempus egestas sed sed. Sem nulla pharetra diam sit amet nisl suscipit. In nisl nisi scelerisque eu ultrices vitae auctor. Non diam phasellus vestibulum lorem sed risus. Urna porttitor rhoncus dolor purus non enim.

+

+  Mi bibendum neque egestas congue. Ac tortor vitae purus faucibus ornare suspendisse sed nisi lacus. Quam viverra orci sagittis eu volutpat odio. Mi tempus imperdiet nulla malesuada pellentesque elit. Ultricies lacus sed turpis tincidunt. In ornare quam viverra orci sagittis eu volutpat odio facilisis. Ut eu sem integer vitae justo eget magna fermentum. Sed augue lacus viverra vitae. Quam nulla porttitor massa id neque. Ut aliquam purus sit amet luctus. Ullamcorper eget nulla facilisi etiam dignissim.

+

+  Sed faucibus turpis in eu. Massa sapien faucibus et molestie. Sed vulputate odio ut enim blandit volutpat maecenas volutpat. Quis vel eros donec ac odio tempor orci dapibus. Odio euismod lacinia at quis. Sit amet consectetur adipiscing elit duis tristique sollicitudin. Malesuada nunc vel risus commodo viverra maecenas accumsan lacus vel. Sed tempus urna et pharetra pharetra massa. Donec massa sapien faucibus et molestie ac feugiat. Convallis convallis tellus id interdum velit. Et odio pellentesque diam volutpat commodo. Aliquet lectus proin nibh nisl condimentum id venenatis. Sed nisi lacus sed viverra tellus in hac habitasse. At lectus urna duis convallis convallis tellus id interdum. Elit pellentesque habitant morbi tristique senectus et. Lorem ipsum dolor sit amet. Mus mauris vitae ultricies leo integer malesuada nunc vel risus. Imperdiet massa tincidunt nunc pulvinar sapien et ligula ullamcorper. Ut pharetra sit amet aliquam id diam.

+

+  Euismod elementum nisi quis eleifend quam adipiscing vitae proin sagittis. Sit amet tellus cras adipiscing enim eu turpis egestas. Netus et malesuada fames ac turpis. Quis vel eros donec ac. Et malesuada fames ac turpis egestas integer eget. Amet est placerat in egestas erat imperdiet. Nec nam aliquam sem et tortor. Ac turpis egestas sed tempus urna et. Massa eget egestas purus viverra accumsan. Condimentum id venenatis a condimentum vitae sapien. Sagittis orci a scelerisque purus semper eget. Aliquet sagittis id consectetur purus ut faucibus pulvinar. Tempor id eu nisl nunc mi ipsum faucibus. Sed faucibus turpis in eu mi bibendum neque egestas congue. Morbi tincidunt augue interdum velit euismod in pellentesque. Amet nisl suscipit adipiscing bibendum est ultricies integer. Ut eu sem integer vitae justo eget magna fermentum. Nisi lacus sed viverra tellus. Scelerisque varius morbi enim nunc faucibus a pellentesque. Vitae purus faucibus ornare suspendisse sed nisi lacus sed viverra.

+

+  Ut placerat orci nulla pellentesque dignissim enim. Tristique senectus et netus et malesuada. Diam in arcu cursus euismod quis viverra nibh cras pulvinar. Lobortis mattis aliquam faucibus purus in massa tempor. Libero id faucibus nisl tincidunt eget nullam non nisi est. Mauris pellentesque pulvinar pellentesque habitant. Est pellentesque elit ullamcorper dignissim cras tincidunt. Egestas sed sed risus pretium quam vulputate. Bibendum at varius vel pharetra. Libero nunc consequat interdum varius. Tincidunt vitae semper quis lectus nulla at volutpat diam. Augue eget arcu dictum varius duis. Varius vel pharetra vel turpis. Quam lacus suspendisse faucibus interdum posuere. Pulvinar neque laoreet suspendisse interdum consectetur libero id. Gravida arcu ac tortor dignissim convallis aenean et. Sit amet porttitor eget dolor morbi non arcu risus.

+

+  Imperdiet sed euismod nisi porta lorem mollis aliquam ut. Sit amet nulla facilisi morbi tempus iaculis. Eleifend mi in nulla posuere sollicitudin aliquam. Sed vulputate odio ut enim. Pellentesque pulvinar pellentesque habitant morbi tristique senectus et netus et. Lectus arcu bibendum at varius vel pharetra vel. Est ultricies integer quis auctor elit sed. Nulla facilisi cras fermentum odio eu feugiat pretium nibh. Nascetur ridiculus mus mauris vitae ultricies leo integer. Faucibus ornare suspendisse sed nisi. Netus et malesuada fames ac turpis. Scelerisque purus semper eget duis at tellus at urna condimentum. Mauris a diam maecenas sed.

+

+  Tortor id aliquet lectus proin nibh nisl condimentum. Urna nunc id cursus metus aliquam eleifend mi in. Risus commodo viverra maecenas accumsan lacus vel facilisis volutpat est. Vitae tempus quam pellentesque nec nam aliquam. Amet aliquam id diam maecenas ultricies mi. Morbi non arcu risus quis. Pharetra vel turpis nunc eget lorem. Tincidunt vitae semper quis lectus nulla at volutpat. Massa placerat duis ultricies lacus. Augue mauris augue neque gravida in fermentum. Viverra justo nec ultrices dui sapien. Semper auctor neque vitae tempus quam pellentesque. Ipsum consequat nisl vel pretium lectus quam id leo in. Dignissim cras tincidunt lobortis feugiat vivamus at augue eget arcu. Platea dictumst vestibulum rhoncus est pellentesque. Ipsum suspendisse ultrices gravida dictum fusce ut.

+

+  Euismod nisi porta lorem mollis aliquam ut porttitor leo. Ac turpis egestas integer eget aliquet nibh praesent tristique. Aliquet nec ullamcorper sit amet risus nullam eget. Id venenatis a condimentum vitae sapien pellentesque habitant morbi tristique. Placerat duis ultricies lacus sed turpis tincidunt id. Laoreet suspendisse interdum consectetur libero id faucibus nisl tincidunt eget. Convallis a cras semper auctor. Ornare aenean euismod elementum nisi quis eleifend quam adipiscing vitae. Arcu cursus vitae congue mauris rhoncus aenean vel elit scelerisque. Nec nam aliquam sem et tortor consequat id.

+

+  Risus viverra adipiscing at in tellus integer feugiat scelerisque varius. Aliquam sem et tortor consequat id. Nisi scelerisque eu ultrices vitae auctor eu augue ut. Ut morbi tincidunt augue interdum velit euismod. A scelerisque purus semper eget. Felis eget velit aliquet sagittis id consectetur purus. Blandit turpis cursus in hac habitasse platea dictumst quisque sagittis. Senectus et netus et malesuada fames ac turpis egestas integer. Urna nec tincidunt praesent semper. Quis viverra nibh cras pulvinar. Purus semper eget duis at tellus. Ante metus dictum at tempor. Eleifend mi in nulla posuere sollicitudin aliquam ultrices sagittis orci. Tincidunt eget nullam non nisi est. Dignissim sodales ut eu sem integer.

+

+  Euismod elementum nisi quis eleifend quam adipiscing vitae proin sagittis. Sit amet tellus cras adipiscing enim eu turpis egestas. Netus et malesuada fames ac turpis. Quis vel eros donec ac. Et malesuada fames ac turpis egestas integer eget. Amet est placerat in egestas erat imperdiet. Nec nam aliquam sem et tortor. Ac turpis egestas sed tempus urna et. Massa eget egestas purus viverra accumsan. Condimentum id venenatis a condimentum vitae sapien. Sagittis orci a scelerisque purus semper eget. Aliquet sagittis id consectetur purus ut faucibus pulvinar. Tempor id eu nisl nunc mi ipsum faucibus. Sed faucibus turpis in eu mi bibendum neque egestas congue. Morbi tincidunt augue interdum velit euismod in pellentesque. Amet nisl suscipit adipiscing bibendum est ultricies integer. Ut eu sem integer vitae justo eget magna fermentum. Nisi lacus sed viverra tellus. Scelerisque varius morbi enim nunc faucibus a pellentesque. Vitae purus faucibus ornare suspendisse sed nisi lacus sed viverra.

+

+  Ut placerat orci nulla pellentesque dignissim enim. Tristique senectus et netus et malesuada. Diam in arcu cursus euismod quis viverra nibh cras pulvinar. Lobortis mattis aliquam faucibus purus in massa tempor. Libero id faucibus nisl tincidunt eget nullam non nisi est. Mauris pellentesque pulvinar pellentesque habitant. Est pellentesque elit ullamcorper dignissim cras tincidunt. Egestas sed sed risus pretium quam vulputate. Bibendum at varius vel pharetra. Libero nunc consequat interdum varius. Tincidunt vitae semper quis lectus nulla at volutpat diam. Augue eget arcu dictum varius duis. Varius vel pharetra vel turpis. Quam lacus suspendisse faucibus interdum posuere. Pulvinar neque laoreet suspendisse interdum consectetur libero id. Gravida arcu ac tortor dignissim convallis aenean et. Sit amet porttitor eget dolor morbi non arcu risus.

+

+  Imperdiet sed euismod nisi porta lorem mollis aliquam ut. Sit amet nulla facilisi morbi tempus iaculis. Eleifend mi in nulla posuere sollicitudin aliquam. Sed vulputate odio ut enim. Pellentesque pulvinar pellentesque habitant morbi tristique senectus et netus et. Lectus arcu bibendum at varius vel pharetra vel. Est ultricies integer quis auctor elit sed. Nulla facilisi cras fermentum odio eu feugiat pretium nibh. Nascetur ridiculus mus mauris vitae ultricies leo integer. Faucibus ornare suspendisse sed nisi. Netus et malesuada fames ac turpis. Scelerisque purus semper eget duis at tellus at urna condimentum. Mauris a diam maecenas sed.

+

+</home>

diff --git a/third_party/WebKit/LayoutTests/xmlviewer/resources/long-multi-byte-char.xslt b/third_party/WebKit/LayoutTests/xmlviewer/resources/long-multi-byte-char.xslt
new file mode 100644
index 0000000..76054cab2
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/xmlviewer/resources/long-multi-byte-char.xslt
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>

+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"  version="1.0" xmlns:v="urn:schemas-microsoft-com:vml">

+  <xsl:output method="html" encoding="utf-8" doctype-system="about:legacy-compat" />

+

+  <xsl:template match="/">

+    <html xmlns:v="urn:schemas-microsoft-com:vml">

+      <head>

+      </head>

+      <body id="test-body">

+        Test passes if you see this line, and this line alone.

+      </body>

+    </html>

+  </xsl:template>

+</xsl:stylesheet>

diff --git a/third_party/WebKit/Source/bindings/core/v8/LocalWindowProxy.cpp b/third_party/WebKit/Source/bindings/core/v8/LocalWindowProxy.cpp
index 72de729a..33d958f 100644
--- a/third_party/WebKit/Source/bindings/core/v8/LocalWindowProxy.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/LocalWindowProxy.cpp
@@ -77,9 +77,6 @@
   // The embedder could run arbitrary code in response to the
   // willReleaseScriptContext callback, so all disposing should happen after
   // it returns.
-  // TODO(yukishiino): Apparently, we can create context for a detached frame
-  // (see comment in CreateContext), but then we do not dispose it. We should
-  // make sure that create/dispose operations are balanced.
   GetFrame()->Client()->WillReleaseScriptContext(context, world_->GetWorldId());
   MainThreadDebugger::Instance()->ContextWillBeDestroyed(script_state_.get());
 
@@ -173,12 +170,7 @@
                  GetFrame()->IsMainFrame());
     MainThreadDebugger::Instance()->ContextCreated(script_state_.get(),
                                                    GetFrame(), origin);
-    // TODO(yukishiino): Remove this client check, we should not create context
-    // on a frame without client.
-    if (GetFrame()->Client()) {
-      GetFrame()->Client()->DidCreateScriptContext(context,
-                                                   world_->GetWorldId());
-    }
+    GetFrame()->Client()->DidCreateScriptContext(context, world_->GetWorldId());
   }
 
   InstallConditionalFeatures();
@@ -197,9 +189,7 @@
 
   Vector<const char*> extension_names;
   // Dynamically tell v8 about our extensions now.
-  // TODO(yukishiino): Remove this client check, we should not create context
-  // on a frame without client.
-  if (GetFrame()->Client() && GetFrame()->Client()->AllowScriptExtensions()) {
+  if (GetFrame()->Client()->AllowScriptExtensions()) {
     const V8Extensions& extensions = ScriptController::RegisteredExtensions();
     extension_names.ReserveInitialCapacity(extensions.size());
     for (const auto* extension : extensions)
diff --git a/third_party/WebKit/Source/core/animation/Animation.cpp b/third_party/WebKit/Source/core/animation/Animation.cpp
index 1be8787..cb07466e 100644
--- a/third_party/WebKit/Source/core/animation/Animation.cpp
+++ b/third_party/WebKit/Source/core/animation/Animation.cpp
@@ -117,7 +117,7 @@
     : ContextLifecycleObserver(execution_context),
       play_state_(kIdle),
       playback_rate_(1),
-      start_time_(NullValue()),
+      start_time_(),
       hold_time_(0),
       sequence_number_(NextSequenceNumber()),
       content_(content),
@@ -200,14 +200,14 @@
   bool old_held = held_;
   bool outdated = false;
   bool is_limited = Limited(new_current_time);
-  held_ = paused_ || !playback_rate_ || is_limited || std::isnan(start_time_);
+  held_ = paused_ || !playback_rate_ || is_limited || !start_time_;
   if (held_) {
     if (!old_held || hold_time_ != new_current_time)
       outdated = true;
     hold_time_ = new_current_time;
     if (paused_ || !playback_rate_) {
-      start_time_ = NullValue();
-    } else if (is_limited && std::isnan(start_time_) &&
+      start_time_ = WTF::nullopt;
+    } else if (is_limited && !start_time_ &&
                reason == kTimingUpdateForAnimationFrame) {
       start_time_ = CalculateStartTime(new_current_time);
     }
@@ -229,7 +229,7 @@
     return;
   if (held_) {
     double new_current_time = hold_time_;
-    if (play_state_ == kFinished && !IsNull(start_time_) && timeline_) {
+    if (play_state_ == kFinished && start_time_ && timeline_) {
       // Add hystersis due to floating point error accumulation
       if (!Limited(CalculateCurrentTime() + 0.001 * playback_rate_)) {
         // The current time became unlimited, eg. due to a backwards
@@ -250,13 +250,14 @@
 }
 
 double Animation::startTime(bool& is_null) const {
-  double result = startTime();
-  is_null = std::isnan(result);
-  return result;
+  WTF::Optional<double> result = startTime();
+  is_null = !result;
+  return result.value_or(0);
 }
 
-double Animation::startTime() const {
-  return start_time_ * 1000;
+WTF::Optional<double> Animation::startTime() const {
+  return start_time_ ? WTF::make_optional(start_time_.value() * 1000)
+                     : WTF::nullopt;
 }
 
 double Animation::currentTime(bool& is_null) {
@@ -268,7 +269,7 @@
 double Animation::currentTime() {
   PlayStateUpdateScope update_scope(*this, kTimingUpdateOnDemand);
 
-  if (PlayStateInternal() == kIdle || (!held_ && !HasStartTime()))
+  if (PlayStateInternal() == kIdle || (!held_ && !start_time_))
     return std::numeric_limits<double>::quiet_NaN();
 
   return CurrentTimeInternal() * 1000;
@@ -292,7 +293,7 @@
 #if DCHECK_IS_ON()
   CurrentTimeInternal();
 #endif
-  return PlayStateInternal() == kPaused || IsNull(start_time_)
+  return PlayStateInternal() == kPaused || !start_time_
              ? CurrentTimeInternal()
              : CalculateCurrentTime();
 }
@@ -309,7 +310,8 @@
       (Paused() || compositor_state_->playback_rate != playback_rate_);
   bool hard_change =
       compositor_state_ && (compositor_state_->effect_changed ||
-                            compositor_state_->start_time != start_time_);
+                            compositor_state_->start_time != start_time_ ||
+                            !compositor_state_->start_time || !start_time_);
 
   // FIXME: softChange && !hardChange should generate a Pause/ThenStart,
   // not a Cancel, but we can't communicate these to the compositor yet.
@@ -329,7 +331,7 @@
     compositor_state_ = nullptr;
   }
 
-  DCHECK(!compositor_state_ || !std::isnan(compositor_state_->start_time));
+  DCHECK(!compositor_state_ || compositor_state_->start_time);
 
   if (!should_start) {
     current_time_pending_ = false;
@@ -382,17 +384,18 @@
 
   switch (compositor_state_->pending_action) {
     case kStart:
-      if (!std::isnan(compositor_state_->start_time)) {
-        DCHECK_EQ(start_time_, compositor_state_->start_time);
+      if (compositor_state_->start_time) {
+        DCHECK_EQ(start_time_.value(), compositor_state_->start_time.value());
         compositor_state_->pending_action = kNone;
       }
       break;
     case kPause:
     case kPauseThenStart:
-      DCHECK(std::isnan(start_time_));
+      DCHECK(!start_time_);
       compositor_state_->pending_action = kNone;
       SetCurrentTimeInternal(
-          (timeline_time - compositor_state_->start_time) * playback_rate_,
+          (timeline_time - compositor_state_->start_time.value()) *
+              playback_rate_,
           kTimingUpdateForAnimationFrame);
       current_time_pending_ = false;
       break;
@@ -407,12 +410,14 @@
 
   if (compositor_state_) {
     DCHECK_EQ(compositor_state_->pending_action, kStart);
-    DCHECK(std::isnan(compositor_state_->start_time));
+    DCHECK(!compositor_state_->start_time);
 
     double initial_compositor_hold_time = compositor_state_->hold_time;
     compositor_state_->pending_action = kNone;
+    // TODO(crbug.com/791086): Determine whether this can ever be null.
+    double start_time = timeline_time + CurrentTimeInternal() / -playback_rate_;
     compositor_state_->start_time =
-        timeline_time + CurrentTimeInternal() / -playback_rate_;
+        IsNull(start_time) ? WTF::nullopt : WTF::make_optional(start_time);
 
     if (start_time_ == timeline_time) {
       // The start time was set to the incoming compositor start time.
@@ -423,8 +428,7 @@
       return;
     }
 
-    if (!std::isnan(start_time_) ||
-        CurrentTimeInternal() != initial_compositor_hold_time) {
+    if (start_time_ || CurrentTimeInternal() != initial_compositor_hold_time) {
       // A new start time or current time was set while starting.
       SetCompositorPending(true);
       return;
@@ -436,7 +440,7 @@
 
 void Animation::NotifyStartTime(double timeline_time) {
   if (Playing()) {
-    DCHECK(std::isnan(start_time_));
+    DCHECK(!start_time_);
     DCHECK(held_);
 
     if (playback_rate_ == 0) {
@@ -465,17 +469,22 @@
          effect->Affects(PropertyHandle(property));
 }
 
-double Animation::CalculateStartTime(double current_time) const {
-  return timeline_->EffectiveTime() - current_time / playback_rate_;
+WTF::Optional<double> Animation::CalculateStartTime(double current_time) const {
+  WTF::Optional<double> start_time =
+      timeline_->EffectiveTime() - current_time / playback_rate_;
+  DCHECK(!IsNull(start_time.value()));
+  return start_time;
 }
 
 double Animation::CalculateCurrentTime() const {
   // TODO(crbug.com/818196): By spec, this should be unresolved, not 0.
-  if (IsNull(start_time_) || !timeline_)
+  if (!start_time_ || !timeline_)
     return 0;
-  return (timeline_->EffectiveTime() - start_time_) * playback_rate_;
+  return (timeline_->EffectiveTime() - start_time_.value()) * playback_rate_;
 }
 
+// TODO(crbug.com/771722): This doesn't handle anim.startTime = null; we just
+// silently convert that to anim.startTime = 0.
 void Animation::setStartTime(double start_time, bool is_null) {
   PlayStateUpdateScope update_scope(*this, kTimingUpdateOnDemand);
 
@@ -488,12 +497,12 @@
   SetStartTimeInternal(start_time / 1000);
 }
 
-void Animation::SetStartTimeInternal(double new_start_time) {
+void Animation::SetStartTimeInternal(WTF::Optional<double> new_start_time) {
   DCHECK(!paused_);
-  DCHECK(std::isfinite(new_start_time));
-  DCHECK_NE(new_start_time, start_time_);
+  DCHECK(new_start_time.has_value());
+  DCHECK(new_start_time != start_time_);
 
-  bool had_start_time = HasStartTime();
+  bool had_start_time = start_time_.has_value();
   double previous_current_time = CurrentTimeInternal();
   start_time_ = new_start_time;
   if (held_ && playback_rate_) {
@@ -565,12 +574,12 @@
   return play_state_;
 }
 
-Animation::AnimationPlayState Animation::CalculatePlayState() {
+Animation::AnimationPlayState Animation::CalculatePlayState() const {
   if (paused_ && !current_time_pending_)
     return kPaused;
   if (play_state_ == kIdle)
     return kIdle;
-  if (current_time_pending_ || (IsNull(start_time_) && playback_rate_ != 0))
+  if (current_time_pending_ || (!start_time_ && playback_rate_ != 0))
     return kPending;
   if (Limited())
     return kFinished;
@@ -631,7 +640,7 @@
   }
 
   if (!Playing()) {
-    start_time_ = NullValue();
+    start_time_ = WTF::nullopt;
   }
 
   if (PlayStateInternal() == kIdle) {
@@ -644,11 +653,11 @@
   UnpauseInternal();
 
   if (playback_rate_ > 0 && (current_time < 0 || current_time >= EffectEnd())) {
-    start_time_ = NullValue();
+    start_time_ = WTF::nullopt;
     SetCurrentTimeInternal(0, kTimingUpdateOnDemand);
   } else if (playback_rate_ < 0 &&
              (current_time <= 0 || current_time > EffectEnd())) {
-    start_time_ = NullValue();
+    start_time_ = WTF::nullopt;
     SetCurrentTimeInternal(EffectEnd(), kTimingUpdateOnDemand);
   }
 }
@@ -753,12 +762,12 @@
 
   PlayStateUpdateScope update_scope(*this, kTimingUpdateOnDemand);
 
-  double start_time_before = start_time_;
+  WTF::Optional<double> start_time_before = start_time_;
   SetPlaybackRateInternal(playback_rate);
 
   // Adds a UseCounter to check if setting playbackRate causes a compensatory
   // seek forcing a change in start_time_
-  if (!std::isnan(start_time_before) && start_time_ != start_time_before &&
+  if (start_time_before && start_time_ != start_time_before &&
       play_state_ != kFinished) {
     UseCounter::Count(GetExecutionContext(),
                       WebFeature::kAnimationSetPlaybackRateCompensatorySeek);
@@ -769,7 +778,7 @@
   DCHECK(std::isfinite(playback_rate));
   DCHECK_NE(playback_rate, playback_rate_);
 
-  if (!Limited() && !Paused() && HasStartTime())
+  if (!Limited() && !Paused() && start_time_)
     current_time_pending_ = true;
 
   double stored_current_time = CurrentTimeInternal();
@@ -778,7 +787,7 @@
     finished_ = false;
 
   playback_rate_ = playback_rate;
-  start_time_ = std::numeric_limits<double>::quiet_NaN();
+  start_time_ = WTF::nullopt;
   SetCurrentTimeInternal(stored_current_time, kTimingUpdateOnDemand);
 }
 
@@ -858,7 +867,7 @@
 
   // If the optional element id set has no value we must be in SPv1 mode in
   // which case we trust the compositing logic will create a layer if needed.
-  if (composited_element_ids.has_value()) {
+  if (composited_element_ids) {
     DCHECK(RuntimeEnabledFeatures::SlimmingPaintV2Enabled());
     Element* target_element =
         ToKeyframeEffectReadOnly(content_.Get())->target();
@@ -899,17 +908,19 @@
 
   bool reversed = playback_rate_ < 0;
 
-  double start_time = TimelineInternal()->ZeroTime() + StartTimeInternal();
-  if (reversed) {
-    start_time -= EffectEnd() / fabs(playback_rate_);
-  }
-
+  // TODO(crbug.com/791086): Make StartAnimationOnCompositor use WTF::Optional.
+  double start_time = NullValue();
   double time_offset = 0;
-  if (std::isnan(start_time)) {
+  if (start_time_) {
+    start_time = TimelineInternal()->ZeroTime() + start_time_.value();
+    if (reversed)
+      start_time -= EffectEnd() / fabs(playback_rate_);
+  } else {
     time_offset =
         reversed ? EffectEnd() - CurrentTimeInternal() : CurrentTimeInternal();
     time_offset = time_offset / fabs(playback_rate_);
   }
+
   DCHECK_NE(compositor_group_, 0);
   ToKeyframeEffectReadOnly(content_.Get())
       ->StartAnimationOnCompositor(compositor_group_, start_time, time_offset,
@@ -928,9 +939,16 @@
   if (compositor_pending_ || is_paused_for_testing_) {
     return;
   }
+  // In general, we need to update the compositor-side if anything has changed
+  // on the blink version of the animation. There is also an edge case; if
+  // neither the compositor nor blink side have a start time we still have to
+  // sync them. This can happen if the blink side animation was started, the
+  // compositor side hadn't started on its side yet, and then the blink side
+  // start time was cleared (e.g. by setting current time).
   if (!compositor_state_ || compositor_state_->effect_changed ||
       compositor_state_->playback_rate != playback_rate_ ||
-      compositor_state_->start_time != start_time_) {
+      compositor_state_->start_time != start_time_ ||
+      !compositor_state_->start_time || !start_time_) {
     compositor_pending_ = true;
     TimelineInternal()->GetDocument()->GetPendingAnimations().Add(this);
   }
@@ -986,7 +1004,7 @@
   }
 
   if ((idle || Limited()) && !finished_) {
-    if (reason == kTimingUpdateForAnimationFrame && (idle || HasStartTime())) {
+    if (reason == kTimingUpdateForAnimationFrame && (idle || start_time_)) {
       if (idle) {
         const AtomicString& event_type = EventTypeNames::cancel;
         if (GetExecutionContext() && HasEventListeners(event_type)) {
@@ -1032,12 +1050,12 @@
 }
 
 bool Animation::IsEventDispatchAllowed() const {
-  return Paused() || HasStartTime();
+  return Paused() || start_time_;
 }
 
 double Animation::TimeToEffectChange() {
   DCHECK(!outdated_);
-  if (!HasStartTime() || held_)
+  if (!start_time_ || held_)
     return std::numeric_limits<double>::infinity();
 
   if (!content_)
@@ -1061,7 +1079,7 @@
   held_ = false;
   paused_ = false;
   play_state_ = kIdle;
-  start_time_ = NullValue();
+  start_time_ = WTF::nullopt;
   current_time_pending_ = false;
   ForceServiceOnNextFrame();
 }
diff --git a/third_party/WebKit/Source/core/animation/Animation.h b/third_party/WebKit/Source/core/animation/Animation.h
index c0f99ce..d5fe968 100644
--- a/third_party/WebKit/Source/core/animation/Animation.h
+++ b/third_party/WebKit/Source/core/animation/Animation.h
@@ -52,6 +52,7 @@
 #include "platform/animation/CompositorAnimationDelegate.h"
 #include "platform/graphics/CompositorElementId.h"
 #include "platform/heap/Handle.h"
+#include "platform/wtf/Optional.h"
 
 namespace blink {
 
@@ -157,13 +158,10 @@
   const DocumentTimeline* TimelineInternal() const { return timeline_; }
   DocumentTimeline* TimelineInternal() { return timeline_; }
 
-  double CalculateStartTime(double current_time) const;
-  bool HasStartTime() const { return !IsNull(start_time_); }
   double startTime(bool& is_null) const;
-  double startTime() const;
-  double StartTimeInternal() const { return start_time_; }
+  WTF::Optional<double> startTime() const;
+  WTF::Optional<double> StartTimeInternal() const { return start_time_; }
   void setStartTime(double, bool is_null);
-  void SetStartTimeInternal(double);
 
   const AnimationEffectReadOnly* effect() const { return content_.Get(); }
   AnimationEffectReadOnly* effect() { return content_.Get(); }
@@ -228,6 +226,8 @@
 
   void Trace(blink::Visitor*) override;
 
+  bool CompositorPendingForTesting() const { return compositor_pending_; }
+
  protected:
   DispatchEventResult DispatchEventInternal(Event*) override;
   void AddedEventListener(const AtomicString& event_type,
@@ -242,11 +242,13 @@
   double EffectEnd() const;
   bool Limited(double current_time) const;
 
-  AnimationPlayState CalculatePlayState();
+  AnimationPlayState CalculatePlayState() const;
+  WTF::Optional<double> CalculateStartTime(double current_time) const;
   double CalculateCurrentTime() const;
 
   void UnpauseInternal();
   void SetPlaybackRateInternal(double);
+  void SetStartTimeInternal(WTF::Optional<double>);
   void UpdateCurrentTimingState(TimingUpdateReason);
 
   void BeginUpdatingState();
@@ -276,7 +278,7 @@
 
   AnimationPlayState play_state_;
   double playback_rate_;
-  double start_time_;
+  WTF::Optional<double> start_time_;
   double hold_time_;
 
   unsigned sequence_number_;
@@ -317,7 +319,7 @@
           playback_rate(animation.playback_rate_),
           effect_changed(false),
           pending_action(kStart) {}
-    double start_time;
+    WTF::Optional<double> start_time;
     double hold_time;
     double playback_rate;
     bool effect_changed;
diff --git a/third_party/WebKit/Source/core/animation/AnimationTest.cpp b/third_party/WebKit/Source/core/animation/AnimationTest.cpp
index 70777eb6..260de5e 100644
--- a/third_party/WebKit/Source/core/animation/AnimationTest.cpp
+++ b/third_party/WebKit/Source/core/animation/AnimationTest.cpp
@@ -108,8 +108,7 @@
   EXPECT_EQ(0, animation->CurrentTimeInternal());
   EXPECT_FALSE(animation->Paused());
   EXPECT_EQ(1, animation->playbackRate());
-  EXPECT_FALSE(animation->HasStartTime());
-  EXPECT_TRUE(IsNull(animation->StartTimeInternal()));
+  EXPECT_FALSE(animation->StartTimeInternal());
 
   StartTimeline();
   EXPECT_EQ(Animation::kFinished, animation->PlayStateInternal());
@@ -118,7 +117,6 @@
   EXPECT_FALSE(animation->Paused());
   EXPECT_EQ(1, animation->playbackRate());
   EXPECT_EQ(0, animation->StartTimeInternal());
-  EXPECT_TRUE(animation->HasStartTime());
 }
 
 TEST_F(AnimationAnimationTest, CurrentTimeDoesNotSetOutdated) {
@@ -253,7 +251,7 @@
   NonThrowableExceptionState exception_state;
   animation->pause();
   EXPECT_EQ(Animation::kPending, animation->PlayStateInternal());
-  EXPECT_TRUE(std::isnan(animation->startTime()));
+  EXPECT_FALSE(animation->startTime());
   animation->finish(exception_state);
   EXPECT_EQ(Animation::kFinished, animation->PlayStateInternal());
   EXPECT_EQ(-30000, animation->startTime());
@@ -274,13 +272,13 @@
   animation->finish(exception_state);
   EXPECT_EQ(-30 * 1000, animation->startTime());
   animation->pause();
-  EXPECT_TRUE(std::isnan(animation->startTime()));
+  EXPECT_FALSE(animation->startTime());
 }
 
 TEST_F(AnimationAnimationTest, StartTimeWithZeroPlaybackRate) {
   animation->setPlaybackRate(0);
   EXPECT_EQ(Animation::kPending, animation->PlayStateInternal());
-  EXPECT_TRUE(std::isnan(animation->startTime()));
+  EXPECT_FALSE(animation->startTime());
   SimulateFrame(10);
   EXPECT_EQ(Animation::kRunning, animation->PlayStateInternal());
 }
@@ -733,11 +731,11 @@
   animation->cancel();
   EXPECT_EQ(Animation::kIdle, animation->PlayStateInternal());
   EXPECT_TRUE(std::isnan(animation->currentTime()));
-  EXPECT_TRUE(std::isnan(animation->startTime()));
+  EXPECT_FALSE(animation->startTime());
   animation->play();
   EXPECT_EQ(Animation::kPending, animation->PlayStateInternal());
   EXPECT_EQ(0, animation->currentTime());
-  EXPECT_TRUE(std::isnan(animation->startTime()));
+  EXPECT_FALSE(animation->startTime());
   SimulateFrame(10);
   EXPECT_EQ(Animation::kRunning, animation->PlayStateInternal());
   EXPECT_EQ(0, animation->currentTime());
@@ -751,11 +749,11 @@
   animation->cancel();
   EXPECT_EQ(Animation::kIdle, animation->PlayStateInternal());
   EXPECT_TRUE(std::isnan(animation->currentTime()));
-  EXPECT_TRUE(std::isnan(animation->startTime()));
+  EXPECT_FALSE(animation->startTime());
   animation->play();
   EXPECT_EQ(Animation::kPending, animation->PlayStateInternal());
   EXPECT_EQ(30 * 1000, animation->currentTime());
-  EXPECT_TRUE(std::isnan(animation->startTime()));
+  EXPECT_FALSE(animation->startTime());
   SimulateFrame(10);
   EXPECT_EQ(Animation::kRunning, animation->PlayStateInternal());
   EXPECT_EQ(30 * 1000, animation->currentTime());
@@ -766,11 +764,11 @@
   animation->cancel();
   EXPECT_EQ(Animation::kIdle, animation->PlayStateInternal());
   EXPECT_TRUE(std::isnan(animation->currentTime()));
-  EXPECT_TRUE(std::isnan(animation->startTime()));
+  EXPECT_FALSE(animation->startTime());
   animation->reverse();
   EXPECT_EQ(Animation::kPending, animation->PlayStateInternal());
   EXPECT_EQ(30 * 1000, animation->currentTime());
-  EXPECT_TRUE(std::isnan(animation->startTime()));
+  EXPECT_FALSE(animation->startTime());
   SimulateFrame(10);
   EXPECT_EQ(Animation::kRunning, animation->PlayStateInternal());
   EXPECT_EQ(30 * 1000, animation->currentTime());
@@ -782,7 +780,7 @@
   animation->cancel();
   EXPECT_EQ(Animation::kIdle, animation->PlayStateInternal());
   EXPECT_TRUE(std::isnan(animation->currentTime()));
-  EXPECT_TRUE(std::isnan(animation->startTime()));
+  EXPECT_FALSE(animation->startTime());
   animation->finish(exception_state);
   EXPECT_EQ(30000, animation->currentTime());
   EXPECT_EQ(-30000, animation->startTime());
@@ -793,11 +791,11 @@
   animation->cancel();
   EXPECT_EQ(Animation::kIdle, animation->PlayStateInternal());
   EXPECT_TRUE(std::isnan(animation->currentTime()));
-  EXPECT_TRUE(std::isnan(animation->startTime()));
+  EXPECT_FALSE(animation->startTime());
   animation->pause();
   EXPECT_EQ(Animation::kPending, animation->PlayStateInternal());
   EXPECT_EQ(0, animation->currentTime());
-  EXPECT_TRUE(std::isnan(animation->startTime()));
+  EXPECT_FALSE(animation->startTime());
 }
 
 TEST_F(AnimationAnimationTest, NoCompositeWithoutCompositedElementId) {
@@ -841,4 +839,106 @@
           .Ok());
 }
 
+// Regression test for http://crbug.com/819591 . If a compositable animation is
+// played and then paused before any start time is set (either blink or
+// compositor side), the pausing must still set compositor pending or the pause
+// won't be synced.
+TEST_F(AnimationAnimationTest, SetCompositorPendingWithUnresolvedStartTimes) {
+  // Get rid of the default animation.
+  animation->cancel();
+
+  EnableCompositing();
+
+  SetBodyInnerHTML("<div id='target'></div>");
+
+  // Create a compositable animation; in this case opacity from 1 to 0.
+  Timing timing;
+  timing.iteration_duration = 30;
+
+  scoped_refptr<StringKeyframe> start_keyframe = StringKeyframe::Create();
+  start_keyframe->SetCSSPropertyValue(
+      CSSPropertyOpacity, "1.0", SecureContextMode::kInsecureContext, nullptr);
+  scoped_refptr<StringKeyframe> end_keyframe = StringKeyframe::Create();
+  end_keyframe->SetCSSPropertyValue(
+      CSSPropertyOpacity, "0.0", SecureContextMode::kInsecureContext, nullptr);
+
+  StringKeyframeVector keyframes;
+  keyframes.push_back(start_keyframe);
+  keyframes.push_back(end_keyframe);
+
+  auto* element = GetElementById("target");
+  StringKeyframeEffectModel* model =
+      StringKeyframeEffectModel::Create(keyframes);
+  KeyframeEffect* keyframe_effect_composited =
+      KeyframeEffect::Create(element, model, timing);
+  Animation* animation = timeline->Play(keyframe_effect_composited);
+
+  // After creating the animation we need to clean the lifecycle so that the
+  // animation can be pushed to the compositor.
+  UpdateAllLifecyclePhases();
+
+  document->GetAnimationClock().UpdateTime(0);
+  document->GetPendingAnimations().Update(WTF::nullopt, true);
+
+  // At this point, the animation exists on both the compositor and blink side,
+  // but no start time has arrived on either side. The compositor is currently
+  // synced, no update is pending.
+  EXPECT_FALSE(animation->CompositorPendingForTesting());
+
+  // However, if we pause the animation then the compositor should still be
+  // marked pending. This is required because otherwise the compositor will go
+  // ahead and start playing the animation once it receives a start time (e.g.
+  // on the next compositor frame).
+  animation->pause();
+
+  EXPECT_TRUE(animation->CompositorPendingForTesting());
+}
+
+TEST_F(AnimationAnimationTest, PreCommitWithUnresolvedStartTimes) {
+  // Get rid of the default animation.
+  animation->cancel();
+
+  EnableCompositing();
+
+  SetBodyInnerHTML("<div id='target'></div>");
+
+  // Create a compositable animation; in this case opacity from 1 to 0.
+  Timing timing;
+  timing.iteration_duration = 30;
+
+  scoped_refptr<StringKeyframe> start_keyframe = StringKeyframe::Create();
+  start_keyframe->SetCSSPropertyValue(
+      CSSPropertyOpacity, "1.0", SecureContextMode::kInsecureContext, nullptr);
+  scoped_refptr<StringKeyframe> end_keyframe = StringKeyframe::Create();
+  end_keyframe->SetCSSPropertyValue(
+      CSSPropertyOpacity, "0.0", SecureContextMode::kInsecureContext, nullptr);
+
+  StringKeyframeVector keyframes;
+  keyframes.push_back(start_keyframe);
+  keyframes.push_back(end_keyframe);
+
+  auto* element = GetElementById("target");
+  StringKeyframeEffectModel* model =
+      StringKeyframeEffectModel::Create(keyframes);
+  KeyframeEffect* keyframe_effect_composited =
+      KeyframeEffect::Create(element, model, timing);
+  Animation* animation = timeline->Play(keyframe_effect_composited);
+
+  // After creating the animation we need to clean the lifecycle so that the
+  // animation can be pushed to the compositor.
+  UpdateAllLifecyclePhases();
+
+  document->GetAnimationClock().UpdateTime(0);
+  document->GetPendingAnimations().Update(WTF::nullopt, true);
+
+  // At this point, the animation exists on both the compositor and blink side,
+  // but no start time has arrived on either side. The compositor is currently
+  // synced, no update is pending.
+  EXPECT_FALSE(animation->CompositorPendingForTesting());
+
+  // At this point, a call to PreCommit should bail out and tell us to wait for
+  // next commit because there are no resolved start times.
+  EXPECT_FALSE(animation->PreCommit(0, WTF::nullopt, true));
+}
+
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/animation/PendingAnimations.cpp b/third_party/WebKit/Source/core/animation/PendingAnimations.cpp
index af6ded87..a5688d4 100644
--- a/third_party/WebKit/Source/core/animation/PendingAnimations.cpp
+++ b/third_party/WebKit/Source/core/animation/PendingAnimations.cpp
@@ -76,14 +76,14 @@
         animation->HasActiveAnimationsOnCompositor();
     // Animations with a start time do not participate in compositor start-time
     // grouping.
-    if (animation->PreCommit(animation->HasStartTime() ? 1 : compositor_group,
+    if (animation->PreCommit(animation->startTime() ? 1 : compositor_group,
                              composited_element_ids, start_on_compositor)) {
       if (animation->HasActiveAnimationsOnCompositor() &&
           !had_compositor_animation) {
         started_synchronized_on_compositor = true;
       }
 
-      if (animation->Playing() && !animation->HasStartTime() &&
+      if (animation->Playing() && !animation->startTime() &&
           animation->TimelineInternal() &&
           animation->TimelineInternal()->IsActive()) {
         waiting_for_start_time.push_back(animation.Get());
@@ -98,13 +98,13 @@
   // start time. Otherwise they may start immediately.
   if (started_synchronized_on_compositor) {
     for (auto& animation : waiting_for_start_time) {
-      if (!animation->HasStartTime()) {
+      if (!animation->startTime()) {
         waiting_for_compositor_animation_start_.push_back(animation);
       }
     }
   } else {
     for (auto& animation : waiting_for_start_time) {
-      if (!animation->HasStartTime()) {
+      if (!animation->startTime()) {
         animation->NotifyCompositorStartTime(
             animation->TimelineInternal()->CurrentTimeInternal());
       }
@@ -148,7 +148,7 @@
   animations.swap(waiting_for_compositor_animation_start_);
 
   for (auto animation : animations) {
-    if (animation->HasStartTime() ||
+    if (animation->startTime() ||
         animation->PlayStateInternal() != Animation::kPending ||
         !animation->TimelineInternal() ||
         !animation->TimelineInternal()->IsActive()) {
diff --git a/third_party/WebKit/Source/core/animation/css/CSSAnimations.cpp b/third_party/WebKit/Source/core/animation/css/CSSAnimations.cpp
index af084f2..d95255ca 100644
--- a/third_party/WebKit/Source/core/animation/css/CSSAnimations.cpp
+++ b/third_party/WebKit/Source/core/animation/css/CSSAnimations.cpp
@@ -532,8 +532,9 @@
             pending_update_.NewTransitions().end() &&
         !animation->Limited()) {
       retargeted_compositor_transitions.insert(
-          property, std::pair<KeyframeEffectReadOnly*, double>(
-                        effect, animation->StartTimeInternal()));
+          property,
+          std::pair<KeyframeEffectReadOnly*, double>(
+              effect, animation->StartTimeInternal().value_or(NullValue())));
     }
     animation->cancel();
     // after cancelation, transitions must be downgraded or they'll fail
diff --git a/third_party/WebKit/Source/core/dom/Element.cpp b/third_party/WebKit/Source/core/dom/Element.cpp
index 13401b12..97f9d286 100644
--- a/third_party/WebKit/Source/core/dom/Element.cpp
+++ b/third_party/WebKit/Source/core/dom/Element.cpp
@@ -2069,7 +2069,8 @@
   }
 
   style->UpdateIsStackingContext(this == GetDocument().documentElement(),
-                                 IsInTopLayer());
+                                 IsInTopLayer(),
+                                 IsSVGForeignObjectElement(*this));
 
   return style;
 }
diff --git a/third_party/WebKit/Source/core/inspector/InspectorAnimationAgent.cpp b/third_party/WebKit/Source/core/inspector/InspectorAnimationAgent.cpp
index ce248a6..354b657 100644
--- a/third_party/WebKit/Source/core/inspector/InspectorAnimationAgent.cpp
+++ b/third_party/WebKit/Source/core/inspector/InspectorAnimationAgent.cpp
@@ -254,8 +254,8 @@
     *current_time = animation->currentTime();
   } else {
     // Use startTime where possible since currentTime is limited.
-    *current_time =
-        animation->TimelineInternal()->currentTime() - animation->startTime();
+    *current_time = animation->TimelineInternal()->currentTime() -
+                    animation->startTime().value_or(NullValue());
   }
   return Response::OK();
 }
@@ -274,8 +274,8 @@
       return Response::Error("Failed to clone detached animation");
     if (paused && !clone->Paused()) {
       // Ensure we restore a current time if the animation is limited.
-      double current_time =
-          clone->TimelineInternal()->currentTime() - clone->startTime();
+      double current_time = clone->TimelineInternal()->currentTime() -
+                            clone->startTime().value_or(NullValue());
       clone->pause();
       clone->setCurrentTime(current_time, false);
     } else if (!paused && clone->Paused()) {
@@ -323,7 +323,7 @@
     id_to_animation_clone_.Set(id, clone);
     id_to_animation_.Set(String::Number(clone->SequenceNumber()), clone);
     clone->play();
-    clone->setStartTime(animation->startTime(), false);
+    clone->setStartTime(animation->startTime().value_or(NullValue()), false);
 
     animation->SetEffectSuppressed(true);
   }
@@ -551,12 +551,14 @@
 double InspectorAnimationAgent::NormalizedStartTime(
     blink::Animation& animation) {
   if (ReferenceTimeline().PlaybackRate() == 0) {
-    return animation.startTime() + ReferenceTimeline().currentTime() -
+    return animation.startTime().value_or(NullValue()) +
+           ReferenceTimeline().currentTime() -
            animation.TimelineInternal()->currentTime();
   }
-  return animation.startTime() + (animation.TimelineInternal()->ZeroTime() -
-                                  ReferenceTimeline().ZeroTime()) *
-                                     1000 * ReferenceTimeline().PlaybackRate();
+  return animation.startTime().value_or(NullValue()) +
+         (animation.TimelineInternal()->ZeroTime() -
+          ReferenceTimeline().ZeroTime()) *
+             1000 * ReferenceTimeline().PlaybackRate();
 }
 
 void InspectorAnimationAgent::Trace(blink::Visitor* visitor) {
diff --git a/third_party/WebKit/Source/core/layout/ScrollbarsTest.cpp b/third_party/WebKit/Source/core/layout/ScrollbarsTest.cpp
index d34b364a..90c7d2a6 100644
--- a/third_party/WebKit/Source/core/layout/ScrollbarsTest.cpp
+++ b/third_party/WebKit/Source/core/layout/ScrollbarsTest.cpp
@@ -100,6 +100,11 @@
     WebView().Scheduler()->EnableVirtualTime();
   }
 
+  void TearDown() override {
+    WebView().Scheduler()->DisableVirtualTimeForTesting();
+    ScrollbarsTest::TearDown();
+  }
+
   void TimeAdvance() {
     WebView().Scheduler()->SetVirtualTimePolicy(
         PageScheduler::VirtualTimePolicy::kAdvance);
diff --git a/third_party/WebKit/Source/core/layout/svg/LayoutSVGBlock.cpp b/third_party/WebKit/Source/core/layout/svg/LayoutSVGBlock.cpp
index b207393..8de96f29 100644
--- a/third_party/WebKit/Source/core/layout/svg/LayoutSVGBlock.cpp
+++ b/third_party/WebKit/Source/core/layout/svg/LayoutSVGBlock.cpp
@@ -35,30 +35,6 @@
 LayoutSVGBlock::LayoutSVGBlock(SVGElement* element)
     : LayoutBlockFlow(element) {}
 
-bool LayoutSVGBlock::AllowsOverflowClip() const {
-  // LayoutSVGBlock, used by Layout(SVGText|ForeignObject), is not allowed to
-  // have overflow clip.
-  // LayoutBlock assumes a layer to be present when the overflow clip
-  // functionality is requested. Both Layout(SVGText|ForeignObject) return
-  // 'NoPaintLayer' on 'layerTypeRequired'.
-  // Fine for LayoutSVGText.
-  //
-  // If we want to support overflow rules for <foreignObject> we can choose
-  // between two solutions:
-  // a) make LayoutSVGForeignObject require layers and SVG layer aware
-  // b) refactor overflow logic out of Layer (as suggested by dhyatt), which is
-  //    a large task
-  //
-  // Until this is resolved, let this function return false, and create overflow
-  // clip in PaintPropertyTreeBuilder and apply overflow clip in
-  // SVGForeignObjectPainter.
-  //
-  // Note: This does NOT affect overflow handling on outer/inner <svg> elements
-  // - this is handled manually by LayoutSVGRoot - which owns the documents
-  // enclosing root layer and thus works fine.
-  return false;
-}
-
 void LayoutSVGBlock::AbsoluteRects(Vector<IntRect>&, const LayoutPoint&) const {
   // This code path should never be taken for SVG, as we're assuming
   // useTransforms=true everywhere, absoluteQuads should be used.
diff --git a/third_party/WebKit/Source/core/layout/svg/LayoutSVGBlock.h b/third_party/WebKit/Source/core/layout/svg/LayoutSVGBlock.h
index 1d68ecf..b5036a2 100644
--- a/third_party/WebKit/Source/core/layout/svg/LayoutSVGBlock.h
+++ b/third_party/WebKit/Source/core/layout/svg/LayoutSVGBlock.h
@@ -53,7 +53,7 @@
 
   AffineTransform LocalSVGTransform() const final { return local_transform_; }
 
-  PaintLayerType LayerTypeRequired() const final { return kNoPaintLayer; }
+  PaintLayerType LayerTypeRequired() const override { return kNoPaintLayer; }
 
  protected:
   void WillBeDestroyed() override;
@@ -73,8 +73,6 @@
  private:
   LayoutRect AbsoluteVisualRect() const final;
 
-  bool AllowsOverflowClip() const final;
-
   void AbsoluteRects(Vector<IntRect>&,
                      const LayoutPoint& accumulated_offset) const final;
 
diff --git a/third_party/WebKit/Source/core/layout/svg/LayoutSVGForeignObject.cpp b/third_party/WebKit/Source/core/layout/svg/LayoutSVGForeignObject.cpp
index 4a8e0805..688b250 100644
--- a/third_party/WebKit/Source/core/layout/svg/LayoutSVGForeignObject.cpp
+++ b/third_party/WebKit/Source/core/layout/svg/LayoutSVGForeignObject.cpp
@@ -152,6 +152,29 @@
                                   kHitTestChildBlockBackgrounds);
 }
 
+bool LayoutSVGForeignObject::NodeAtPoint(
+    HitTestResult& result,
+    const HitTestLocation& location_in_parent,
+    const LayoutPoint& accumulated_offset,
+    HitTestAction hit_test_action) {
+  if (RuntimeEnabledFeatures::SlimmingPaintV175Enabled()) {
+    return NodeAtFloatPoint(result, FloatPoint(accumulated_offset),
+                            hit_test_action);
+  }
+  NOTREACHED();
+  return false;
+}
+
+PaintLayerType LayoutSVGForeignObject::LayerTypeRequired() const {
+  if (RuntimeEnabledFeatures::SlimmingPaintV175Enabled())
+    return LayoutBlockFlow::LayerTypeRequired();
+  return kNoPaintLayer;
+}
+
+bool LayoutSVGForeignObject::AllowsOverflowClip() const {
+  return RuntimeEnabledFeatures::SlimmingPaintV175Enabled();
+}
+
 void LayoutSVGForeignObject::StyleDidChange(StyleDifference diff,
                                             const ComputedStyle* old_style) {
   LayoutSVGBlock::StyleDidChange(diff, old_style);
diff --git a/third_party/WebKit/Source/core/layout/svg/LayoutSVGForeignObject.h b/third_party/WebKit/Source/core/layout/svg/LayoutSVGForeignObject.h
index 1e46743..51aa3595 100644
--- a/third_party/WebKit/Source/core/layout/svg/LayoutSVGForeignObject.h
+++ b/third_party/WebKit/Source/core/layout/svg/LayoutSVGForeignObject.h
@@ -60,6 +60,11 @@
     return ObjectBoundingBox();
   }
 
+  bool NodeAtPoint(HitTestResult&,
+                   const HitTestLocation&,
+                   const LayoutPoint&,
+                   HitTestAction) override;
+
   bool NodeAtFloatPoint(HitTestResult&,
                         const FloatPoint& point_in_parent,
                         HitTestAction) override;
@@ -70,7 +75,10 @@
 
   void SetNeedsTransformUpdate() override { needs_transform_update_ = true; }
 
+  PaintLayerType LayerTypeRequired() const override;
+
  private:
+  bool AllowsOverflowClip() const override;
   LayoutUnit ElementX() const;
   LayoutUnit ElementY() const;
   LayoutUnit ElementWidth() const;
diff --git a/third_party/WebKit/Source/core/layout/svg/LayoutSVGText.h b/third_party/WebKit/Source/core/layout/svg/LayoutSVGText.h
index 30bc036..a9c2ff5 100644
--- a/third_party/WebKit/Source/core/layout/svg/LayoutSVGText.h
+++ b/third_party/WebKit/Source/core/layout/svg/LayoutSVGText.h
@@ -65,6 +65,8 @@
   const char* GetName() const override { return "LayoutSVGText"; }
 
  private:
+  bool AllowsOverflowClip() const override { return false; }
+
   bool IsOfType(LayoutObjectType type) const override {
     return type == kLayoutObjectSVGText || LayoutSVGBlock::IsOfType(type);
   }
diff --git a/third_party/WebKit/Source/core/layout/svg/SVGLayoutSupport.cpp b/third_party/WebKit/Source/core/layout/svg/SVGLayoutSupport.cpp
index 2bdb44c..c3be98d 100644
--- a/third_party/WebKit/Source/core/layout/svg/SVGLayoutSupport.cpp
+++ b/third_party/WebKit/Source/core/layout/svg/SVGLayoutSupport.cpp
@@ -189,8 +189,9 @@
   // to CSS box coordinates.
   // LayoutSVGRoot's mapLocalToAncestor method expects CSS box coordinates.
   if (parent->IsSVGRoot()) {
-    TransformationMatrix matrix(object->LocalToSVGParentTransform());
-    matrix.Multiply(ToLayoutSVGRoot(parent)->LocalToBorderBoxTransform());
+    TransformationMatrix matrix(
+        ToLayoutSVGRoot(parent)->LocalToBorderBoxTransform());
+    matrix.Multiply(object->LocalToSVGParentTransform());
     geometry_map.Push(object, matrix);
   } else {
     geometry_map.Push(object, object->LocalToSVGParentTransform());
diff --git a/third_party/WebKit/Source/core/messaging/MessagePort.cpp b/third_party/WebKit/Source/core/messaging/MessagePort.cpp
index eccbd639..1423d72 100644
--- a/third_party/WebKit/Source/core/messaging/MessagePort.cpp
+++ b/third_party/WebKit/Source/core/messaging/MessagePort.cpp
@@ -167,6 +167,7 @@
     return Vector<MessagePortChannel>();
 
   HeapHashSet<Member<MessagePort>> visited;
+  bool has_closed_ports = false;
 
   // Walk the incoming array - if there are any duplicate ports, or null ports
   // or cloned ports, throw an error (per section 8.3.3 of the HTML5 spec).
@@ -185,10 +186,14 @@
           "Port at index " + String::Number(i) + " is " + type + ".");
       return Vector<MessagePortChannel>();
     }
+    if (port->closed_)
+      has_closed_ports = true;
     visited.insert(port);
   }
 
   UseCounter::Count(context, WebFeature::kMessagePortsTransferred);
+  if (has_closed_ports)
+    UseCounter::Count(context, WebFeature::kMessagePortTransferClosedPort);
 
   // Passed-in ports passed validity checks, so we can disentangle them.
   Vector<MessagePortChannel> channels;
diff --git a/third_party/WebKit/Source/core/paint/BlockPainter.cpp b/third_party/WebKit/Source/core/paint/BlockPainter.cpp
index 93ee7dc..fb3c1ec 100644
--- a/third_party/WebKit/Source/core/paint/BlockPainter.cpp
+++ b/third_party/WebKit/Source/core/paint/BlockPainter.cpp
@@ -61,7 +61,8 @@
       original_phase != PaintPhase::kSelfOutlineOnly) {
     Optional<BoxClipper> clipper;
     // We have already applied clip in SVGForeignObjectClipper.
-    if (!layout_block_.IsSVGForeignObject()) {
+    if (!layout_block_.IsSVGForeignObject() ||
+        RuntimeEnabledFeatures::SlimmingPaintV175Enabled()) {
       clipper.emplace(layout_block_, local_paint_info, adjusted_paint_offset,
                       contents_clip_behavior);
     }
diff --git a/third_party/WebKit/Source/core/paint/BoxPainter.cpp b/third_party/WebKit/Source/core/paint/BoxPainter.cpp
index 124d9c3b..67f9bc78 100644
--- a/third_party/WebKit/Source/core/paint/BoxPainter.cpp
+++ b/third_party/WebKit/Source/core/paint/BoxPainter.cpp
@@ -41,8 +41,11 @@
                                const LayoutPoint& paint_offset) {
   PaintInfo child_info(paint_info);
   for (LayoutObject* child = layout_box_.SlowFirstChild(); child;
-       child = child->NextSibling())
-    child->Paint(child_info, paint_offset);
+       child = child->NextSibling()) {
+    if (!child->IsBoxModelObject() ||
+        !ToLayoutBoxModelObject(child)->HasSelfPaintingLayer())
+      child->Paint(child_info, paint_offset);
+  }
 }
 
 void BoxPainter::PaintBoxDecorationBackground(const PaintInfo& paint_info,
diff --git a/third_party/WebKit/Source/core/paint/PaintLayer.cpp b/third_party/WebKit/Source/core/paint/PaintLayer.cpp
index ff363094..edd561d 100644
--- a/third_party/WebKit/Source/core/paint/PaintLayer.cpp
+++ b/third_party/WebKit/Source/core/paint/PaintLayer.cpp
@@ -169,6 +169,7 @@
       has_non_isolated_descendant_with_blend_mode_(false),
       self_painting_status_changed_(false),
       filter_on_effect_node_dirty_(false),
+      is_under_svg_hidden_container_(false),
       layout_object_(layout_object),
       parent_(nullptr),
       previous_(nullptr),
diff --git a/third_party/WebKit/Source/core/paint/PaintLayer.h b/third_party/WebKit/Source/core/paint/PaintLayer.h
index 46d9076..995862a65 100644
--- a/third_party/WebKit/Source/core/paint/PaintLayer.h
+++ b/third_party/WebKit/Source/core/paint/PaintLayer.h
@@ -622,6 +622,11 @@
   void SetFilterOnEffectNodeDirty() { filter_on_effect_node_dirty_ = true; }
   void ClearFilterOnEffectNodeDirty() { filter_on_effect_node_dirty_ = false; }
 
+  void SetIsUnderSVGHiddenContainer(bool value) {
+    is_under_svg_hidden_container_ = value;
+  }
+  bool IsUnderSVGHiddenContainer() { return is_under_svg_hidden_container_; }
+
   CompositorFilterOperations CreateCompositorFilterOperationsForBackdropFilter()
       const;
 
@@ -1226,6 +1231,10 @@
   // It's cleared when the effect paint property node is updated.
   unsigned filter_on_effect_node_dirty_ : 1;
 
+  // True if the current subtree is underneath a LayoutSVGHiddenContainer
+  // ancestor.
+  unsigned is_under_svg_hidden_container_ : 1;
+
   LayoutBoxModelObject& layout_object_;
 
   PaintLayer* parent_;
diff --git a/third_party/WebKit/Source/core/paint/PaintLayerPainter.cpp b/third_party/WebKit/Source/core/paint/PaintLayerPainter.cpp
index bf31d5f..d512b61 100644
--- a/third_party/WebKit/Source/core/paint/PaintLayerPainter.cpp
+++ b/third_party/WebKit/Source/core/paint/PaintLayerPainter.cpp
@@ -448,9 +448,13 @@
 
   sk_sp<PaintFilter> image_filter = FilterPainter::GetImageFilter(paint_layer_);
 
-  bool should_paint_content = paint_layer_.HasVisibleContent() &&
-                              is_self_painting_layer &&
-                              !is_painting_overlay_scrollbars;
+  bool should_paint_content =
+      paint_layer_.HasVisibleContent() &&
+      // Content under a LayoutSVGHiddenContainer is auxiliary resources for
+      // painting. Foreign content should never paint in this situation, as it
+      // is primary, not auxiliary.
+      !paint_layer_.IsUnderSVGHiddenContainer() && is_self_painting_layer &&
+      !is_painting_overlay_scrollbars;
 
   PaintLayerFragments layer_fragments;
 
diff --git a/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.cpp b/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.cpp
index a1de7b0..e8c23c5 100644
--- a/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.cpp
+++ b/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.cpp
@@ -426,6 +426,17 @@
 static bool NeedsPaintOffsetTranslation(const LayoutObject& object) {
   if (!object.IsBoxModelObject())
     return false;
+
+  // <foreignObject> inherits no paint offset, because there is no such
+  // concept within SVG. However, the foreign object can have its own paint
+  // offset due to the x and y parameters of the element. This affects the
+  // offset of painting of the <foreignObject> element and its children.
+  // However, <foreignObject> otherwise behaves like other SVG elements, in
+  // that the x and y offset is applied *after* any transform, instead of
+  // before. Therefore there is no paint offset translation needed.
+  if (object.IsSVGForeignObject())
+    return false;
+
   const LayoutBoxModelObject& box_model = ToLayoutBoxModelObject(object);
 
   if (box_model.IsLayoutView()) {
@@ -1028,7 +1039,7 @@
   // special because it doesn't create a PaintLayer.
   // See LayoutSVGBlock::AllowsOverflowClip().
   if (RuntimeEnabledFeatures::SlimmingPaintV175Enabled() &&
-      (object.IsSVGForeignObject() || object.IsSVGViewportContainer()) &&
+      object.IsSVGViewportContainer() &&
       SVGLayoutSupport::IsOverflowHidden(object))
     return true;
 
@@ -1143,7 +1154,8 @@
     if (NeedsOverflowClip(object_)) {
       FloatRoundedRect clip_rect;
       FloatRoundedRect clip_rect_excluding_overlay_scrollbars;
-      if (object_.IsSVGForeignObject()) {
+      if (!RuntimeEnabledFeatures::SlimmingPaintV175Enabled() &&
+          object_.IsSVGForeignObject()) {
         clip_rect = ToClipRect(ToLayoutBox(object_).FrameRect());
         clip_rect_excluding_overlay_scrollbars = clip_rect;
       } else if (object_.IsBox()) {
@@ -2302,6 +2314,7 @@
     // trees, paint offset, etc.
     context_.fragments.clear();
     context_.fragments.Grow(1);
+    context_.has_svg_hidden_container_ancestor = true;
     PaintPropertyTreeBuilderFragmentContext& fragment_context =
         context_.fragments[0];
 
@@ -2312,6 +2325,11 @@
     object_.GetMutableForPainting().FirstFragment().ClearNextFragment();
   }
 
+  if (object_.HasLayer()) {
+    ToLayoutBoxModelObject(object_).Layer()->SetIsUnderSVGHiddenContainer(
+        context_.has_svg_hidden_container_ancestor);
+  }
+
   UpdateRepeatingPaintOffsetAdjustment();
 
   return needs_paint_properties != had_paint_properties;
diff --git a/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.h b/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.h
index 5fd944f..46384ad 100644
--- a/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.h
+++ b/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.h
@@ -148,6 +148,10 @@
   // object first appears.
   bool is_repeating_in_fragments = false;
 
+  // True if the current subtree is underneath a LayoutSVGHiddenContainer
+  // ancestor.
+  bool has_svg_hidden_container_ancestor = false;
+
   // The physical bounding box of all appearances of the repeating object
   // in the flow thread.
   LayoutRect repeating_bounding_box_in_flow_thread;
diff --git a/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilderTest.cpp b/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilderTest.cpp
index c6cba59..3d2efb2 100644
--- a/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilderTest.cpp
+++ b/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilderTest.cpp
@@ -1265,6 +1265,29 @@
             div_with_transform_properties->Transform()->Parent()->Parent());
 }
 
+TEST_P(PaintPropertyTreeBuilderTest, ForeignObjectWithTransformAndOffset) {
+  SetBodyInnerHTML(R"HTML(
+    <style> body { margin: 0px; } </style>
+    <svg id='svgWithTransform'>
+      <foreignObject id="foreignObject"
+          x="10" y="10" width="50" height="40" transform="scale(5)">
+        <div id='div'></div>
+      </foreignObject>
+    </svg>
+  )HTML");
+
+  LayoutObject& foreign_object = *GetLayoutObjectByElementId("foreignObject");
+  const ObjectPaintProperties* foreign_object_properties =
+      foreign_object.FirstFragment().PaintProperties();
+  EXPECT_EQ(TransformationMatrix().Scale(5),
+            foreign_object_properties->Transform()->Matrix());
+  EXPECT_EQ(LayoutPoint(10, 10), foreign_object.FirstFragment().PaintOffset());
+  EXPECT_EQ(nullptr, foreign_object_properties->PaintOffsetTranslation());
+
+  LayoutObject& div = *GetLayoutObjectByElementId("div");
+  EXPECT_EQ(LayoutPoint(10, 10), div.FirstFragment().PaintOffset());
+}
+
 TEST_P(PaintPropertyTreeBuilderTest, PaintOffsetTranslationSVGHTMLBoundary) {
   SetBodyInnerHTML(R"HTML(
     <svg id='svg'
@@ -2537,13 +2560,12 @@
   const auto* foreign_object_properties =
       foreign_object->FirstFragment().PaintProperties();
   EXPECT_EQ(nullptr, foreign_object_properties->PaintOffsetTranslation());
-  // Paint offset of foreignObject should be originated from SVG root and
-  // snapped to pixels.
+
   EXPECT_EQ(LayoutPoint(4, 5), foreign_object->FirstFragment().PaintOffset());
 
   const auto* div = GetLayoutObjectByElementId("div");
-  // Paint offset of descendant of foreignObject accumulates on paint offset of
-  // foreignObject.
+  // Paint offset of descendant of foreignObject accumulates on paint offset
+  // of foreignObject.
   EXPECT_EQ(LayoutPoint(LayoutUnit(4 + 5.6), LayoutUnit(5 + 7.3)),
             div->FirstFragment().PaintOffset());
 }
diff --git a/third_party/WebKit/Source/core/paint/SVGContainerPainter.cpp b/third_party/WebKit/Source/core/paint/SVGContainerPainter.cpp
index 18b7f39..e157a32 100644
--- a/third_party/WebKit/Source/core/paint/SVGContainerPainter.cpp
+++ b/third_party/WebKit/Source/core/paint/SVGContainerPainter.cpp
@@ -4,6 +4,7 @@
 
 #include "core/paint/SVGContainerPainter.h"
 
+#include "core/layout/LayoutBoxModelObject.h"
 #include "core/layout/svg/LayoutSVGContainer.h"
 #include "core/layout/svg/LayoutSVGViewportContainer.h"
 #include "core/layout/svg/SVGLayoutSupport.h"
@@ -81,8 +82,12 @@
 
     if (continue_rendering) {
       for (LayoutObject* child = layout_svg_container_.FirstChild(); child;
-           child = child->NextSibling())
-        child->Paint(paint_context.GetPaintInfo(), IntPoint());
+           child = child->NextSibling()) {
+        if (!child->IsBoxModelObject() ||
+            !ToLayoutBoxModelObject(child)->HasSelfPaintingLayer()) {
+          child->Paint(paint_context.GetPaintInfo(), IntPoint());
+        }
+      }
     }
   }
 
diff --git a/third_party/WebKit/Source/core/paint/SVGForeignObjectPainter.cpp b/third_party/WebKit/Source/core/paint/SVGForeignObjectPainter.cpp
index a402f37..e25516b3 100644
--- a/third_party/WebKit/Source/core/paint/SVGForeignObjectPainter.cpp
+++ b/third_party/WebKit/Source/core/paint/SVGForeignObjectPainter.cpp
@@ -10,6 +10,7 @@
 #include "core/paint/FloatClipRecorder.h"
 #include "core/paint/ObjectPainter.h"
 #include "core/paint/PaintInfo.h"
+#include "core/paint/PaintLayer.h"
 #include "core/paint/SVGPaintContext.h"
 #include "platform/wtf/Optional.h"
 
@@ -34,9 +35,11 @@
 }  // namespace
 
 void SVGForeignObjectPainter::Paint(const PaintInfo& paint_info) {
-  if (paint_info.phase != PaintPhase::kForeground &&
-      paint_info.phase != PaintPhase::kSelection)
-    return;
+  if (!RuntimeEnabledFeatures::SlimmingPaintV175Enabled()) {
+    if (paint_info.phase != PaintPhase::kForeground &&
+        paint_info.phase != PaintPhase::kSelection)
+      return;
+  }
 
   PaintInfo paint_info_before_filtering(paint_info);
   paint_info_before_filtering.UpdateCullRect(
@@ -45,29 +48,14 @@
       paint_info_before_filtering, layout_svg_foreign_object_,
       layout_svg_foreign_object_.LocalSVGTransform());
 
-  // In theory we should just let BlockPainter::paint() handle the clip, but for
-  // now we don't allow normal overflow clip for LayoutSVGBlock, so we have to
-  // apply clip manually. See LayoutSVGBlock::allowsOverflowClip() for details.
-  Optional<FloatClipRecorder> clip_recorder;
-  Optional<ScopedPaintChunkProperties> scoped_paint_chunk_properties;
-  if (SVGLayoutSupport::IsOverflowHidden(layout_svg_foreign_object_)) {
-    if (RuntimeEnabledFeatures::SlimmingPaintV175Enabled()) {
-      const auto* fragment =
-          paint_info.FragmentToPaint(layout_svg_foreign_object_);
-      if (!fragment)
-        return;
-      const auto* properties = fragment->PaintProperties();
-      // TODO(crbug.com/814815): The condition should be a DCHECK, but for now
-      // we may paint the object for filters during PrePaint before the
-      // properties are ready.
-      if (properties && properties->OverflowOrInnerBorderRadiusClip()) {
-        scoped_paint_chunk_properties.emplace(
-            paint_info.context.GetPaintController(),
-            properties->OverflowOrInnerBorderRadiusClip(),
-            layout_svg_foreign_object_,
-            paint_info.DisplayItemTypeForClipping());
-      }
-    } else {
+  if (!RuntimeEnabledFeatures::SlimmingPaintV175Enabled()) {
+    // In theory we should just let BlockPainter::paint() handle the clip, but
+    // for now we don't allow normal overflow clip for LayoutSVGBlock, so we
+    // have to apply clip manually. See LayoutSVGBlock::allowsOverflowClip() for
+    // details.
+    Optional<FloatClipRecorder> clip_recorder;
+    Optional<ScopedPaintChunkProperties> scoped_paint_chunk_properties;
+    if (SVGLayoutSupport::IsOverflowHidden(layout_svg_foreign_object_)) {
       clip_recorder.emplace(paint_info_before_filtering.context,
                             layout_svg_foreign_object_,
                             paint_info_before_filtering.phase,
@@ -77,11 +65,13 @@
 
   SVGPaintContext paint_context(layout_svg_foreign_object_,
                                 paint_info_before_filtering);
-  bool continue_rendering = true;
-  if (paint_context.GetPaintInfo().phase == PaintPhase::kForeground)
-    continue_rendering = paint_context.ApplyClipMaskAndFilterIfNecessary();
+  if (paint_context.GetPaintInfo().phase == PaintPhase::kForeground &&
+      !paint_context.ApplyClipMaskAndFilterIfNecessary())
+    return;
 
-  if (continue_rendering) {
+  if (RuntimeEnabledFeatures::SlimmingPaintV175Enabled()) {
+    BlockPainter(layout_svg_foreign_object_).Paint(paint_info, LayoutPoint());
+  } else {
     // Paint all phases of FO elements atomically as though the FO element
     // established its own stacking context.  The delegate forwards calls to
     // paint() in LayoutObject::paintAllPhasesAtomically() to
diff --git a/third_party/WebKit/Source/core/policy/Policy.cpp b/third_party/WebKit/Source/core/policy/Policy.cpp
index 3c1cf24..4056f05 100644
--- a/third_party/WebKit/Source/core/policy/Policy.cpp
+++ b/third_party/WebKit/Source/core/policy/Policy.cpp
@@ -52,16 +52,16 @@
 
 Vector<String> Policy::getAllowlistForFeature(const String& feature) const {
   if (GetDefaultFeatureNameMap().Contains(feature)) {
-    const FeaturePolicy::Whitelist whitelist =
-        GetPolicy()->GetWhitelistForFeature(
+    const FeaturePolicy::Allowlist allowlist =
+        GetPolicy()->GetAllowlistForFeature(
             GetDefaultFeatureNameMap().at(feature));
-    if (whitelist.MatchesAll())
+    if (allowlist.MatchesAll())
       return Vector<String>({"*"});
-    Vector<String> allowlist;
-    for (const auto& origin : whitelist.Origins()) {
-      allowlist.push_back(WTF::String::FromUTF8(origin.Serialize().c_str()));
+    Vector<String> result;
+    for (const auto& origin : allowlist.Origins()) {
+      result.push_back(WTF::String::FromUTF8(origin.Serialize().c_str()));
     }
-    return allowlist;
+    return result;
   }
 
   AddWarningForUnrecognizedFeature(feature);
diff --git a/third_party/WebKit/Source/core/style/ComputedStyle.cpp b/third_party/WebKit/Source/core/style/ComputedStyle.cpp
index 6dbf6b2e..f6f9afe4 100644
--- a/third_party/WebKit/Source/core/style/ComputedStyle.cpp
+++ b/third_party/WebKit/Source/core/style/ComputedStyle.cpp
@@ -906,7 +906,8 @@
 }
 
 void ComputedStyle::UpdateIsStackingContext(bool is_document_element,
-                                            bool is_in_top_layer) {
+                                            bool is_in_top_layer,
+                                            bool is_svg_stacking) {
   if (IsStackingContext())
     return;
 
@@ -931,6 +932,9 @@
       ContainsPaint()) {
     SetIsStackingContext(true);
   }
+
+  if (RuntimeEnabledFeatures::SlimmingPaintV175Enabled() && is_svg_stacking)
+    SetIsStackingContext(true);
 }
 
 void ComputedStyle::AddCallbackSelector(const String& selector) {
diff --git a/third_party/WebKit/Source/core/style/ComputedStyle.h b/third_party/WebKit/Source/core/style/ComputedStyle.h
index 97633250..58b462c 100644
--- a/third_party/WebKit/Source/core/style/ComputedStyle.h
+++ b/third_party/WebKit/Source/core/style/ComputedStyle.h
@@ -2060,7 +2060,8 @@
   // There are also other elements treated as stacking context during painting,
   // but not managed in stacks. See ObjectPainter::PaintAllPhasesAtomically().)
   CORE_EXPORT void UpdateIsStackingContext(bool is_document_element,
-                                           bool is_in_top_layer);
+                                           bool is_in_top_layer,
+                                           bool is_svg_stacking);
   bool IsStacked() const {
     return IsStackingContext() || GetPosition() != EPosition::kStatic;
   }
diff --git a/third_party/WebKit/Source/core/style/ComputedStyleTest.cpp b/third_party/WebKit/Source/core/style/ComputedStyleTest.cpp
index 33a9825..29d544a 100644
--- a/third_party/WebKit/Source/core/style/ComputedStyleTest.cpp
+++ b/third_party/WebKit/Source/core/style/ComputedStyleTest.cpp
@@ -8,6 +8,7 @@
 #include "core/style/ClipPathOperation.h"
 #include "core/style/ShapeValue.h"
 #include "core/style/StyleDifference.h"
+#include "platform/testing/runtime_enabled_features_test_helpers.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace blink {
@@ -74,12 +75,25 @@
 #endif
 }
 
+TEST(ComputedStyleTest, SVGStackingContext) {
+  scoped_refptr<ComputedStyle> style = ComputedStyle::Create();
+  style->UpdateIsStackingContext(false, false, true);
+  EXPECT_TRUE(style->IsStackingContext());
+}
+
+TEST(ComputedStyleTest, SVGStackingContextSPv1) {
+  ScopedSlimmingPaintV175ForTest spv175(false);
+  scoped_refptr<ComputedStyle> style = ComputedStyle::Create();
+  style->UpdateIsStackingContext(false, false, true);
+  EXPECT_FALSE(style->IsStackingContext());
+}
+
 TEST(ComputedStyleTest, Preserve3dForceStackingContext) {
   scoped_refptr<ComputedStyle> style = ComputedStyle::Create();
   style->SetTransformStyle3D(ETransformStyle3D::kPreserve3d);
   style->SetOverflowX(EOverflow::kHidden);
   style->SetOverflowY(EOverflow::kHidden);
-  style->UpdateIsStackingContext(false, false);
+  style->UpdateIsStackingContext(false, false, false);
   EXPECT_EQ(ETransformStyle3D::kFlat, style->UsedTransformStyle3D());
   EXPECT_TRUE(style->IsStackingContext());
 }
diff --git a/third_party/WebKit/Source/modules/accessibility/AXNodeObject.cpp b/third_party/WebKit/Source/modules/accessibility/AXNodeObject.cpp
index e3f6e0b3..47cc0b69 100644
--- a/third_party/WebKit/Source/modules/accessibility/AXNodeObject.cpp
+++ b/third_party/WebKit/Source/modules/accessibility/AXNodeObject.cpp
@@ -1533,7 +1533,7 @@
 
   if (IsNativeSlider() || IsNativeSpinButton()) {
     *out_value = ToHTMLInputElement(*GetNode()).valueAsNumber();
-    return isfinite(*out_value);
+    return std::isfinite(*out_value);
   }
 
   if (auto* meter = ToHTMLMeterElementOrNull(GetNode())) {
@@ -1579,7 +1579,7 @@
 
   if (IsNativeSlider() || IsNativeSpinButton()) {
     *out_value = static_cast<float>(ToHTMLInputElement(*GetNode()).Maximum());
-    return isfinite(*out_value);
+    return std::isfinite(*out_value);
   }
 
   if (auto* meter = ToHTMLMeterElementOrNull(GetNode())) {
@@ -1612,7 +1612,7 @@
 
   if (IsNativeSlider() || IsNativeSpinButton()) {
     *out_value = static_cast<float>(ToHTMLInputElement(*GetNode()).Minimum());
-    return isfinite(*out_value);
+    return std::isfinite(*out_value);
   }
 
   if (auto* meter = ToHTMLMeterElementOrNull(GetNode())) {
@@ -1641,7 +1641,7 @@
     Decimal step =
         ToHTMLInputElement(*GetNode()).CreateStepRange(kRejectAny).Step();
     *out_value = step.ToString().ToFloat();
-    return isfinite(*out_value);
+    return std::isfinite(*out_value);
   }
 
   switch (AriaRoleAttribute()) {
diff --git a/third_party/WebKit/Source/platform/heap/BUILD.gn b/third_party/WebKit/Source/platform/heap/BUILD.gn
index c711356..8e52bc0d 100644
--- a/third_party/WebKit/Source/platform/heap/BUILD.gn
+++ b/third_party/WebKit/Source/platform/heap/BUILD.gn
@@ -73,6 +73,7 @@
     "ThreadingTraits.h",
     "TraceTraits.h",
     "Visitor.h",
+    "Worklist.h",
   ]
 
   deps = [
@@ -112,6 +113,7 @@
     "ObjectStartBitmapTest.cpp",
     "PersistentTest.cpp",
     "RunAllTests.cpp",
+    "WorklistTest.cpp",
   ]
 
   configs += [
diff --git a/third_party/WebKit/Source/platform/heap/DEPS b/third_party/WebKit/Source/platform/heap/DEPS
index 9abd940a..47cca0a 100644
--- a/third_party/WebKit/Source/platform/heap/DEPS
+++ b/third_party/WebKit/Source/platform/heap/DEPS
@@ -1,7 +1,10 @@
 include_rules = [
     # To whitelist base/ stuff Blink is allowed to include, we list up all
     # directories and files instead of writing 'base/'.
+    "+base/atomicops.h",
     "+base/bits.h",
+    "+base/compiler_specific.h",
+    "+base/synchronization/lock.h",
     "+base/sys_info.h",
 ]
 
diff --git a/third_party/WebKit/Source/platform/heap/Heap.cpp b/third_party/WebKit/Source/platform/heap/Heap.cpp
index 749f6fc..084e2de 100644
--- a/third_party/WebKit/Source/platform/heap/Heap.cpp
+++ b/third_party/WebKit/Source/platform/heap/Heap.cpp
@@ -871,6 +871,15 @@
                     ThreadHeap::GcInfo(header->GcInfoIndex())->trace_);
 }
 
+void ThreadHeap::CheckObjectNotInCallbackStacks(const void* object) {
+#if DCHECK_IS_ON()
+  DCHECK(!MarkingStack()->HasCallbackForObject(object));
+  DCHECK(!PostMarkingCallbackStack()->HasCallbackForObject(object));
+  DCHECK(!WeakCallbackStack()->HasCallbackForObject(object));
+  DCHECK(!EphemeronStack()->HasCallbackForObject(object));
+#endif
+}
+
 ThreadHeap* ThreadHeap::main_thread_heap_ = nullptr;
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/platform/heap/Heap.h b/third_party/WebKit/Source/platform/heap/Heap.h
index a684ebb..b5f7008e 100644
--- a/third_party/WebKit/Source/platform/heap/Heap.h
+++ b/third_party/WebKit/Source/platform/heap/Heap.h
@@ -236,6 +236,8 @@
   }
   CallbackStack* EphemeronStack() const { return ephemeron_stack_.get(); }
 
+  void CheckObjectNotInCallbackStacks(const void*);
+
   void VisitPersistentRoots(Visitor*);
   void VisitStackRoots(MarkingVisitor*);
   void EnterSafePoint(ThreadState*);
diff --git a/third_party/WebKit/Source/platform/heap/HeapAllocator.cpp b/third_party/WebKit/Source/platform/heap/HeapAllocator.cpp
index bee4ef67..7d0bac8 100644
--- a/third_party/WebKit/Source/platform/heap/HeapAllocator.cpp
+++ b/third_party/WebKit/Source/platform/heap/HeapAllocator.cpp
@@ -27,10 +27,10 @@
   // free is disabled for surviving backings during lazy sweeping.
   if (header->IsMarked())
     return;
-  state->CheckObjectNotInCallbackStacks(address);
-  NormalPageArena* arena = static_cast<NormalPage*>(page)->ArenaForNormalPage();
+  state->Heap().CheckObjectNotInCallbackStacks(address);
   state->Heap().PromptlyFreed(header->GcInfoIndex());
-  arena->PromptlyFreeObject(header);
+  static_cast<NormalPage*>(page)->ArenaForNormalPage()->PromptlyFreeObject(
+      header);
 }
 
 void HeapAllocator::FreeVectorBacking(void* address) {
diff --git a/third_party/WebKit/Source/platform/heap/ThreadState.cpp b/third_party/WebKit/Source/platform/heap/ThreadState.cpp
index 559e071..80b58c8 100644
--- a/third_party/WebKit/Source/platform/heap/ThreadState.cpp
+++ b/third_party/WebKit/Source/platform/heap/ThreadState.cpp
@@ -1488,13 +1488,4 @@
   }
 }
 
-void ThreadState::CheckObjectNotInCallbackStacks(const void* object) {
-#if DCHECK_IS_ON()
-  DCHECK(!Heap().MarkingStack()->HasCallbackForObject(object));
-  DCHECK(!Heap().PostMarkingCallbackStack()->HasCallbackForObject(object));
-  DCHECK(!Heap().WeakCallbackStack()->HasCallbackForObject(object));
-  DCHECK(!Heap().EphemeronStack()->HasCallbackForObject(object));
-#endif
-}
-
 }  // namespace blink
diff --git a/third_party/WebKit/Source/platform/heap/ThreadState.h b/third_party/WebKit/Source/platform/heap/ThreadState.h
index 0c2a03c..43515f2 100644
--- a/third_party/WebKit/Source/platform/heap/ThreadState.h
+++ b/third_party/WebKit/Source/platform/heap/ThreadState.h
@@ -344,8 +344,6 @@
   bool IsIncrementalMarking() const { return incremental_marking_; }
   void SetIncrementalMarking(bool value) { incremental_marking_ = value; }
 
-  void CheckObjectNotInCallbackStacks(const void*);
-
   class MainThreadGCForbiddenScope final {
     STACK_ALLOCATED();
 
diff --git a/third_party/WebKit/Source/platform/heap/Worklist.h b/third_party/WebKit/Source/platform/heap/Worklist.h
new file mode 100644
index 0000000..30d5b68
--- /dev/null
+++ b/third_party/WebKit/Source/platform/heap/Worklist.h
@@ -0,0 +1,424 @@
+// 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.
+//
+// Copied and adopted from V8.
+//
+// Copyright 2017 the V8 project 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 Worklist_h
+#define Worklist_h
+
+#include <cstddef>
+#include <utility>
+
+#include "base/atomicops.h"
+#include "base/compiler_specific.h"
+#include "base/gtest_prod_util.h"
+#include "base/logging.h"
+#include "base/synchronization/lock.h"
+#include "platform/wtf/Allocator.h"
+
+namespace blink {
+
+constexpr int kMaxWorkerlistTasks = 8;
+
+// A concurrent worklist based on segments. Each tasks gets private
+// push and pop segments. Empty pop segments are swapped with their
+// corresponding push segments. Full push segments are published to a global
+// pool of segments and replaced with empty segments.
+//
+// Work stealing is best effort, i.e., there is no way to inform other tasks
+// of the need of items.
+template <typename EntryType,
+          int segment_size,
+          int max_tasks = kMaxWorkerlistTasks>
+class Worklist {
+  USING_FAST_MALLOC(Worklist);
+  using WorklistType = Worklist<EntryType, segment_size>;
+
+ public:
+  class View {
+   public:
+    View(WorklistType* worklist, int task_id)
+        : worklist_(worklist), task_id_(task_id) {}
+
+    // Pushes an entry onto the worklist.
+    bool Push(EntryType entry) { return worklist_->Push(task_id_, entry); }
+
+    // Pops an entry from the worklist.
+    bool Pop(EntryType* entry) { return worklist_->Pop(task_id_, entry); }
+
+    // Returns true if the local portion of the worklist is empty.
+    bool IsLocalEmpty() const { return worklist_->IsLocalEmpty(task_id_); }
+
+    // Returns true if the worklist is empty. Can only be used from the main
+    // thread without concurrent access.
+    bool IsGlobalEmpty() { return worklist_->IsGlobalEmpty(); }
+
+    bool IsGlobalPoolEmpty() { return worklist_->IsGlobalPoolEmpty(); }
+
+    size_t LocalPushSegmentSize() const {
+      return worklist_->LocalPushSegmentSize(task_id_);
+    }
+
+   private:
+    WorklistType* const worklist_;
+    const int task_id_;
+  };
+
+  static constexpr size_t kSegmentCapacity = segment_size;
+
+  Worklist() : Worklist(max_tasks) {}
+
+  explicit Worklist(int num_tasks) : num_tasks_(num_tasks) {
+    CHECK_LE(num_tasks, max_tasks);
+    for (int i = 0; i < num_tasks_; i++) {
+      private_push_segment(i) = NewSegment();
+      private_pop_segment(i) = NewSegment();
+    }
+  }
+
+  ~Worklist() {
+    CHECK(IsGlobalEmpty());
+    for (int i = 0; i < num_tasks_; i++) {
+      DCHECK(private_push_segment(i));
+      DCHECK(private_pop_segment(i));
+      delete private_push_segment(i);
+      delete private_pop_segment(i);
+    }
+  }
+
+  bool Push(int task_id, EntryType entry) {
+    DCHECK_LT(task_id, num_tasks_);
+    DCHECK(private_push_segment(task_id));
+    if (!private_push_segment(task_id)->Push(entry)) {
+      PublishPushSegmentToGlobal(task_id);
+      bool success = private_push_segment(task_id)->Push(entry);
+      ANALYZER_ALLOW_UNUSED(success);
+      DCHECK(success);
+    }
+    return true;
+  }
+
+  bool Pop(int task_id, EntryType* entry) {
+    DCHECK_LT(task_id, num_tasks_);
+    DCHECK(private_pop_segment(task_id));
+    if (!private_pop_segment(task_id)->Pop(entry)) {
+      if (!private_push_segment(task_id)->IsEmpty()) {
+        Segment* tmp = private_pop_segment(task_id);
+        private_pop_segment(task_id) = private_push_segment(task_id);
+        private_push_segment(task_id) = tmp;
+      } else if (!StealPopSegmentFromGlobal(task_id)) {
+        return false;
+      }
+      bool success = private_pop_segment(task_id)->Pop(entry);
+      ANALYZER_ALLOW_UNUSED(success);
+      DCHECK(success);
+    }
+    return true;
+  }
+
+  bool IsLocalEmpty(int task_id) const {
+    return private_pop_segment(task_id)->IsEmpty() &&
+           private_push_segment(task_id)->IsEmpty();
+  }
+
+  bool IsGlobalPoolEmpty() { return global_pool_.IsEmpty(); }
+
+  bool IsGlobalEmpty() {
+    for (int i = 0; i < num_tasks_; i++) {
+      if (!IsLocalEmpty(i))
+        return false;
+    }
+    return global_pool_.IsEmpty();
+  }
+
+  size_t LocalSize(int task_id) const {
+    return private_pop_segment(task_id)->Size() +
+           private_push_segment(task_id)->Size();
+  }
+
+  size_t LocalPushSegmentSize(int task_id) const {
+    return private_push_segment(task_id)->Size();
+  }
+
+  // Clears all segments. Frees the global segment pool.
+  //
+  // Assumes that no other tasks are running.
+  void Clear() {
+    for (int i = 0; i < num_tasks_; i++) {
+      private_pop_segment(i)->Clear();
+      private_push_segment(i)->Clear();
+    }
+    global_pool_.Clear();
+  }
+
+  // Calls the specified callback on each element of the deques and replaces
+  // the element with the result of the callback.
+  // The signature of the callback is
+  //   bool Callback(EntryType old, EntryType* new).
+  // If the callback returns |false| then the element is removed from the
+  // worklist. Otherwise the |new| entry is updated.
+  //
+  // Assumes that no other tasks are running.
+  template <typename Callback>
+  void Update(Callback callback) {
+    for (int i = 0; i < num_tasks_; i++) {
+      private_pop_segment(i)->Update(callback);
+      private_push_segment(i)->Update(callback);
+    }
+    global_pool_.Update(callback);
+  }
+
+  template <typename Callback>
+  void IterateGlobalPool(Callback callback) {
+    global_pool_.Iterate(callback);
+  }
+
+  void FlushToGlobal(int task_id) {
+    PublishPushSegmentToGlobal(task_id);
+    PublishPopSegmentToGlobal(task_id);
+  }
+
+  void MergeGlobalPool(Worklist* other) {
+    auto pair = other->global_pool_.Extract();
+    global_pool_.MergeList(pair.first, pair.second);
+  }
+
+ private:
+  FRIEND_TEST_ALL_PREFIXES(WorklistTest, SegmentCreate);
+  FRIEND_TEST_ALL_PREFIXES(WorklistTest, SegmentPush);
+  FRIEND_TEST_ALL_PREFIXES(WorklistTest, SegmentPushPop);
+  FRIEND_TEST_ALL_PREFIXES(WorklistTest, SegmentIsEmpty);
+  FRIEND_TEST_ALL_PREFIXES(WorklistTest, SegmentIsFull);
+  FRIEND_TEST_ALL_PREFIXES(WorklistTest, SegmentClear);
+  FRIEND_TEST_ALL_PREFIXES(WorklistTest, SegmentFullPushFails);
+  FRIEND_TEST_ALL_PREFIXES(WorklistTest, SegmentEmptyPopFails);
+  FRIEND_TEST_ALL_PREFIXES(WorklistTest, SegmentUpdateFalse);
+  FRIEND_TEST_ALL_PREFIXES(WorklistTest, SegmentUpdate);
+
+  class Segment {
+    USING_FAST_MALLOC(Segment);
+
+   public:
+    static const size_t kCapacity = kSegmentCapacity;
+
+    Segment() : index_(0) {}
+
+    bool Push(EntryType entry) {
+      if (IsFull())
+        return false;
+      entries_[index_++] = entry;
+      return true;
+    }
+
+    bool Pop(EntryType* entry) {
+      if (IsEmpty())
+        return false;
+      *entry = entries_[--index_];
+      return true;
+    }
+
+    size_t Size() const { return index_; }
+    bool IsEmpty() const { return index_ == 0; }
+    bool IsFull() const { return index_ == kCapacity; }
+    void Clear() { index_ = 0; }
+
+    template <typename Callback>
+    void Update(Callback callback) {
+      size_t new_index = 0;
+      for (size_t i = 0; i < index_; i++) {
+        if (callback(entries_[i], &entries_[new_index])) {
+          new_index++;
+        }
+      }
+      index_ = new_index;
+    }
+
+    template <typename Callback>
+    void Iterate(Callback callback) const {
+      for (size_t i = 0; i < index_; i++) {
+        callback(entries_[i]);
+      }
+    }
+
+    Segment* next() const { return next_; }
+    void set_next(Segment* segment) { next_ = segment; }
+
+   private:
+    Segment* next_;
+    size_t index_;
+    EntryType entries_[kCapacity];
+  };
+
+  struct PrivateSegmentHolder {
+    Segment* private_push_segment;
+    Segment* private_pop_segment;
+    char cache_line_padding[64];
+  };
+
+  class GlobalPool {
+   public:
+    GlobalPool() : top_(nullptr) {}
+
+    inline void Push(Segment* segment) {
+      base::AutoLock guard(lock_);
+      segment->set_next(top_);
+      set_top(segment);
+    }
+
+    inline bool Pop(Segment** segment) {
+      base::AutoLock guard(lock_);
+      if (top_) {
+        *segment = top_;
+        set_top(top_->next());
+        return true;
+      }
+      return false;
+    }
+
+    inline bool IsEmpty() {
+      return base::subtle::NoBarrier_Load(
+                 reinterpret_cast<base::subtle::AtomicWord*>(&top_)) == 0;
+    }
+
+    void Clear() {
+      base::AutoLock guard(lock_);
+      Segment* current = top_;
+      while (current) {
+        Segment* tmp = current;
+        current = current->next();
+        delete tmp;
+      }
+      set_top(nullptr);
+    }
+
+    // See Worklist::Update.
+    template <typename Callback>
+    void Update(Callback callback) {
+      base::AutoLock guard(lock_);
+      Segment* prev = nullptr;
+      Segment* current = top_;
+      while (current) {
+        current->Update(callback);
+        if (current->IsEmpty()) {
+          if (!prev) {
+            top_ = current->next();
+          } else {
+            prev->set_next(current->next());
+          }
+          Segment* tmp = current;
+          current = current->next();
+          delete tmp;
+        } else {
+          prev = current;
+          current = current->next();
+        }
+      }
+    }
+
+    // See Worklist::Iterate.
+    template <typename Callback>
+    void Iterate(Callback callback) {
+      base::AutoLock guard(lock_);
+      for (Segment* current = top_; current; current = current->next()) {
+        current->Iterate(callback);
+      }
+    }
+
+    std::pair<Segment*, Segment*> Extract() {
+      Segment* top = nullptr;
+      {
+        base::AutoLock guard(lock_);
+        if (!top_)
+          return std::make_pair(nullptr, nullptr);
+        top = top_;
+        set_top(nullptr);
+      }
+      Segment* end = top;
+      while (end->next())
+        end = end->next();
+      return std::make_pair(top, end);
+    }
+
+    void MergeList(Segment* start, Segment* end) {
+      if (!start)
+        return;
+      {
+        base::AutoLock guard(lock_);
+        end->set_next(top_);
+        set_top(start);
+      }
+    }
+
+   private:
+    void set_top(Segment* segment) {
+      return base::subtle::NoBarrier_Store(
+          reinterpret_cast<base::subtle::AtomicWord*>(&top_),
+          reinterpret_cast<base::subtle::AtomicWord>(segment));
+    }
+
+    base::Lock lock_;
+    Segment* top_;
+  };
+
+  ALWAYS_INLINE Segment*& private_push_segment(int task_id) {
+    return private_segments_[task_id].private_push_segment;
+  }
+
+  ALWAYS_INLINE Segment* const& private_push_segment(int task_id) const {
+    return const_cast<const PrivateSegmentHolder*>(private_segments_)[task_id]
+        .private_push_segment;
+  }
+
+  ALWAYS_INLINE Segment*& private_pop_segment(int task_id) {
+    return private_segments_[task_id].private_pop_segment;
+  }
+
+  ALWAYS_INLINE Segment* const& private_pop_segment(int task_id) const {
+    return const_cast<const PrivateSegmentHolder*>(private_segments_)[task_id]
+        .private_pop_segment;
+  }
+
+  ALWAYS_INLINE void PublishPushSegmentToGlobal(int task_id) {
+    if (!private_push_segment(task_id)->IsEmpty()) {
+      global_pool_.Push(private_push_segment(task_id));
+      private_push_segment(task_id) = NewSegment();
+    }
+  }
+
+  ALWAYS_INLINE void PublishPopSegmentToGlobal(int task_id) {
+    if (!private_pop_segment(task_id)->IsEmpty()) {
+      global_pool_.Push(private_pop_segment(task_id));
+      private_pop_segment(task_id) = NewSegment();
+    }
+  }
+
+  ALWAYS_INLINE bool StealPopSegmentFromGlobal(int task_id) {
+    if (global_pool_.IsEmpty())
+      return false;
+    Segment* new_segment = nullptr;
+    if (global_pool_.Pop(&new_segment)) {
+      delete private_pop_segment(task_id);
+      private_pop_segment(task_id) = new_segment;
+      return true;
+    }
+    return false;
+  }
+
+  ALWAYS_INLINE Segment* NewSegment() {
+    // Bottleneck for filtering in crash dumps.
+    return new Segment();
+  }
+
+  PrivateSegmentHolder private_segments_[max_tasks];
+  GlobalPool global_pool_;
+  int num_tasks_;
+};
+
+}  // namespace blink
+
+#endif  // Worklist_h
diff --git a/third_party/WebKit/Source/platform/heap/WorklistTest.cpp b/third_party/WebKit/Source/platform/heap/WorklistTest.cpp
new file mode 100644
index 0000000..5b05601
--- /dev/null
+++ b/third_party/WebKit/Source/platform/heap/WorklistTest.cpp
@@ -0,0 +1,337 @@
+// 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.
+//
+// Copied and adopted from V8.
+//
+// Copyright 2017 the V8 project 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 "platform/heap/Worklist.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace blink {
+
+namespace {
+class SomeObject {};
+}  // namespace
+
+using TestWorklist = Worklist<SomeObject*, 64>;
+
+TEST(WorklistTest, SegmentCreate) {
+  TestWorklist::Segment segment;
+  EXPECT_TRUE(segment.IsEmpty());
+  EXPECT_EQ(0u, segment.Size());
+  EXPECT_FALSE(segment.IsFull());
+}
+
+TEST(WorklistTest, SegmentPush) {
+  TestWorklist::Segment segment;
+  EXPECT_EQ(0u, segment.Size());
+  EXPECT_TRUE(segment.Push(nullptr));
+  EXPECT_EQ(1u, segment.Size());
+}
+
+TEST(WorklistTest, SegmentPushPop) {
+  TestWorklist::Segment segment;
+  EXPECT_TRUE(segment.Push(nullptr));
+  EXPECT_EQ(1u, segment.Size());
+  SomeObject dummy;
+  SomeObject* object = &dummy;
+  EXPECT_TRUE(segment.Pop(&object));
+  EXPECT_EQ(0u, segment.Size());
+  EXPECT_EQ(nullptr, object);
+}
+
+TEST(WorklistTest, SegmentIsEmpty) {
+  TestWorklist::Segment segment;
+  EXPECT_TRUE(segment.IsEmpty());
+  EXPECT_TRUE(segment.Push(nullptr));
+  EXPECT_FALSE(segment.IsEmpty());
+}
+
+TEST(WorklistTest, SegmentIsFull) {
+  TestWorklist::Segment segment;
+  EXPECT_FALSE(segment.IsFull());
+  for (size_t i = 0; i < TestWorklist::Segment::kCapacity; i++) {
+    EXPECT_TRUE(segment.Push(nullptr));
+  }
+  EXPECT_TRUE(segment.IsFull());
+}
+
+TEST(WorklistTest, SegmentClear) {
+  TestWorklist::Segment segment;
+  EXPECT_TRUE(segment.Push(nullptr));
+  EXPECT_FALSE(segment.IsEmpty());
+  segment.Clear();
+  EXPECT_TRUE(segment.IsEmpty());
+  for (size_t i = 0; i < TestWorklist::Segment::kCapacity; i++) {
+    EXPECT_TRUE(segment.Push(nullptr));
+  }
+}
+
+TEST(WorklistTest, SegmentFullPushFails) {
+  TestWorklist::Segment segment;
+  EXPECT_FALSE(segment.IsFull());
+  for (size_t i = 0; i < TestWorklist::Segment::kCapacity; i++) {
+    EXPECT_TRUE(segment.Push(nullptr));
+  }
+  EXPECT_TRUE(segment.IsFull());
+  EXPECT_FALSE(segment.Push(nullptr));
+}
+
+TEST(WorklistTest, SegmentEmptyPopFails) {
+  TestWorklist::Segment segment;
+  EXPECT_TRUE(segment.IsEmpty());
+  SomeObject* object;
+  EXPECT_FALSE(segment.Pop(&object));
+}
+
+TEST(WorklistTest, SegmentUpdateFalse) {
+  TestWorklist::Segment segment;
+  SomeObject* object;
+  object = reinterpret_cast<SomeObject*>(&object);
+  EXPECT_TRUE(segment.Push(object));
+  segment.Update([](SomeObject* object, SomeObject** out) { return false; });
+  EXPECT_TRUE(segment.IsEmpty());
+}
+
+TEST(WorklistTest, SegmentUpdate) {
+  TestWorklist::Segment segment;
+  SomeObject* objectA;
+  objectA = reinterpret_cast<SomeObject*>(&objectA);
+  SomeObject* objectB;
+  objectB = reinterpret_cast<SomeObject*>(&objectB);
+  EXPECT_TRUE(segment.Push(objectA));
+  segment.Update([objectB](SomeObject* object, SomeObject** out) {
+    *out = objectB;
+    return true;
+  });
+  SomeObject* object;
+  EXPECT_TRUE(segment.Pop(&object));
+  EXPECT_EQ(object, objectB);
+}
+
+TEST(WorklistTest, CreateEmpty) {
+  TestWorklist worklist;
+  TestWorklist::View worklist_view(&worklist, 0);
+  EXPECT_TRUE(worklist_view.IsLocalEmpty());
+  EXPECT_TRUE(worklist.IsGlobalEmpty());
+}
+
+TEST(WorklistTest, LocalPushPop) {
+  TestWorklist worklist;
+  TestWorklist::View worklist_view(&worklist, 0);
+  SomeObject dummy;
+  SomeObject* retrieved = nullptr;
+  EXPECT_TRUE(worklist_view.Push(&dummy));
+  EXPECT_FALSE(worklist_view.IsLocalEmpty());
+  EXPECT_TRUE(worklist_view.Pop(&retrieved));
+  EXPECT_EQ(&dummy, retrieved);
+}
+
+TEST(WorklistTest, LocalIsBasedOnId) {
+  TestWorklist worklist;
+  // Use the same id.
+  TestWorklist::View worklist_view1(&worklist, 0);
+  TestWorklist::View worklist_view2(&worklist, 0);
+  SomeObject dummy;
+  SomeObject* retrieved = nullptr;
+  EXPECT_TRUE(worklist_view1.Push(&dummy));
+  EXPECT_FALSE(worklist_view1.IsLocalEmpty());
+  EXPECT_FALSE(worklist_view2.IsLocalEmpty());
+  EXPECT_TRUE(worklist_view2.Pop(&retrieved));
+  EXPECT_EQ(&dummy, retrieved);
+  EXPECT_TRUE(worklist_view1.IsLocalEmpty());
+  EXPECT_TRUE(worklist_view2.IsLocalEmpty());
+}
+
+TEST(WorklistTest, LocalPushStaysPrivate) {
+  TestWorklist worklist;
+  TestWorklist::View worklist_view1(&worklist, 0);
+  TestWorklist::View worklist_view2(&worklist, 1);
+  SomeObject dummy;
+  SomeObject* retrieved = nullptr;
+  EXPECT_TRUE(worklist.IsGlobalEmpty());
+  EXPECT_TRUE(worklist_view1.Push(&dummy));
+  EXPECT_FALSE(worklist.IsGlobalEmpty());
+  EXPECT_FALSE(worklist_view2.Pop(&retrieved));
+  EXPECT_EQ(nullptr, retrieved);
+  EXPECT_TRUE(worklist_view1.Pop(&retrieved));
+  EXPECT_EQ(&dummy, retrieved);
+  EXPECT_TRUE(worklist.IsGlobalEmpty());
+}
+
+TEST(WorklistTest, GlobalUpdateNull) {
+  TestWorklist worklist;
+  TestWorklist::View worklist_view(&worklist, 0);
+  SomeObject* object;
+  object = reinterpret_cast<SomeObject*>(&object);
+  for (size_t i = 0; i < TestWorklist::kSegmentCapacity; i++) {
+    EXPECT_TRUE(worklist_view.Push(object));
+  }
+  EXPECT_TRUE(worklist_view.Push(object));
+  worklist.Update([](SomeObject* object, SomeObject** out) { return false; });
+  EXPECT_TRUE(worklist.IsGlobalEmpty());
+}
+
+TEST(WorklistTest, GlobalUpdate) {
+  TestWorklist worklist;
+  TestWorklist::View worklist_view(&worklist, 0);
+  SomeObject* objectA = nullptr;
+  objectA = reinterpret_cast<SomeObject*>(&objectA);
+  SomeObject* objectB = nullptr;
+  objectB = reinterpret_cast<SomeObject*>(&objectB);
+  SomeObject* objectC = nullptr;
+  objectC = reinterpret_cast<SomeObject*>(&objectC);
+  for (size_t i = 0; i < TestWorklist::kSegmentCapacity; i++) {
+    EXPECT_TRUE(worklist_view.Push(objectA));
+  }
+  for (size_t i = 0; i < TestWorklist::kSegmentCapacity; i++) {
+    EXPECT_TRUE(worklist_view.Push(objectB));
+  }
+  EXPECT_TRUE(worklist_view.Push(objectA));
+  worklist.Update([objectA, objectC](SomeObject* object, SomeObject** out) {
+    if (object != objectA) {
+      *out = objectC;
+      return true;
+    }
+    return false;
+  });
+  for (size_t i = 0; i < TestWorklist::kSegmentCapacity; i++) {
+    SomeObject* object;
+    EXPECT_TRUE(worklist_view.Pop(&object));
+    EXPECT_EQ(object, objectC);
+  }
+}
+
+TEST(WorklistTest, FlushToGlobalPushSegment) {
+  TestWorklist worklist;
+  TestWorklist::View worklist_view0(&worklist, 0);
+  TestWorklist::View worklist_view1(&worklist, 1);
+  SomeObject* object = nullptr;
+  SomeObject* objectA = nullptr;
+  objectA = reinterpret_cast<SomeObject*>(&objectA);
+  EXPECT_TRUE(worklist_view0.Push(objectA));
+  worklist.FlushToGlobal(0);
+  EXPECT_TRUE(worklist_view1.Pop(&object));
+}
+
+TEST(WorklistTest, FlushToGlobalPopSegment) {
+  TestWorklist worklist;
+  TestWorklist::View worklist_view0(&worklist, 0);
+  TestWorklist::View worklist_view1(&worklist, 1);
+  SomeObject* object = nullptr;
+  SomeObject* objectA = nullptr;
+  objectA = reinterpret_cast<SomeObject*>(&objectA);
+  EXPECT_TRUE(worklist_view0.Push(objectA));
+  EXPECT_TRUE(worklist_view0.Push(objectA));
+  EXPECT_TRUE(worklist_view0.Pop(&object));
+  worklist.FlushToGlobal(0);
+  EXPECT_TRUE(worklist_view1.Pop(&object));
+}
+
+TEST(WorklistTest, Clear) {
+  TestWorklist worklist;
+  TestWorklist::View worklist_view(&worklist, 0);
+  SomeObject* object;
+  object = reinterpret_cast<SomeObject*>(&object);
+  for (size_t i = 0; i < TestWorklist::kSegmentCapacity; i++) {
+    EXPECT_TRUE(worklist_view.Push(object));
+  }
+  EXPECT_TRUE(worklist_view.Push(object));
+  worklist.Clear();
+  EXPECT_TRUE(worklist.IsGlobalEmpty());
+}
+
+TEST(WorklistTest, SingleSegmentSteal) {
+  TestWorklist worklist;
+  TestWorklist::View worklist_view1(&worklist, 0);
+  TestWorklist::View worklist_view2(&worklist, 1);
+  SomeObject dummy;
+  for (size_t i = 0; i < TestWorklist::kSegmentCapacity; i++) {
+    EXPECT_TRUE(worklist_view1.Push(&dummy));
+  }
+  SomeObject* retrieved = nullptr;
+  // One more push/pop to publish the full segment.
+  EXPECT_TRUE(worklist_view1.Push(nullptr));
+  EXPECT_TRUE(worklist_view1.Pop(&retrieved));
+  EXPECT_EQ(nullptr, retrieved);
+  // Stealing.
+  for (size_t i = 0; i < TestWorklist::kSegmentCapacity; i++) {
+    EXPECT_TRUE(worklist_view2.Pop(&retrieved));
+    EXPECT_EQ(&dummy, retrieved);
+    EXPECT_FALSE(worklist_view1.Pop(&retrieved));
+  }
+  EXPECT_TRUE(worklist.IsGlobalEmpty());
+}
+
+TEST(WorklistTest, MultipleSegmentsStolen) {
+  TestWorklist worklist;
+  TestWorklist::View worklist_view1(&worklist, 0);
+  TestWorklist::View worklist_view2(&worklist, 1);
+  TestWorklist::View worklist_view3(&worklist, 2);
+  SomeObject dummy1;
+  SomeObject dummy2;
+  for (size_t i = 0; i < TestWorklist::kSegmentCapacity; i++) {
+    EXPECT_TRUE(worklist_view1.Push(&dummy1));
+  }
+  for (size_t i = 0; i < TestWorklist::kSegmentCapacity; i++) {
+    EXPECT_TRUE(worklist_view1.Push(&dummy2));
+  }
+  SomeObject* retrieved = nullptr;
+  SomeObject dummy3;
+  // One more push/pop to publish the full segment.
+  EXPECT_TRUE(worklist_view1.Push(&dummy3));
+  EXPECT_TRUE(worklist_view1.Pop(&retrieved));
+  EXPECT_EQ(&dummy3, retrieved);
+  // Stealing.
+  EXPECT_TRUE(worklist_view2.Pop(&retrieved));
+  SomeObject* const expect_bag2 = retrieved;
+  EXPECT_TRUE(worklist_view3.Pop(&retrieved));
+  SomeObject* const expect_bag3 = retrieved;
+  EXPECT_NE(expect_bag2, expect_bag3);
+  EXPECT_TRUE(expect_bag2 == &dummy1 || expect_bag2 == &dummy2);
+  EXPECT_TRUE(expect_bag3 == &dummy1 || expect_bag3 == &dummy2);
+  for (size_t i = 1; i < TestWorklist::kSegmentCapacity; i++) {
+    EXPECT_TRUE(worklist_view2.Pop(&retrieved));
+    EXPECT_EQ(expect_bag2, retrieved);
+    EXPECT_FALSE(worklist_view1.Pop(&retrieved));
+  }
+  for (size_t i = 1; i < TestWorklist::kSegmentCapacity; i++) {
+    EXPECT_TRUE(worklist_view3.Pop(&retrieved));
+    EXPECT_EQ(expect_bag3, retrieved);
+    EXPECT_FALSE(worklist_view1.Pop(&retrieved));
+  }
+  EXPECT_TRUE(worklist.IsGlobalEmpty());
+}
+
+TEST(WorklistTest, MergeGlobalPool) {
+  TestWorklist worklist1;
+  TestWorklist::View worklist_view1(&worklist1, 0);
+  SomeObject dummy;
+  for (size_t i = 0; i < TestWorklist::kSegmentCapacity; i++) {
+    EXPECT_TRUE(worklist_view1.Push(&dummy));
+  }
+  SomeObject* retrieved = nullptr;
+  // One more push/pop to publish the full segment.
+  EXPECT_TRUE(worklist_view1.Push(nullptr));
+  EXPECT_TRUE(worklist_view1.Pop(&retrieved));
+  EXPECT_EQ(nullptr, retrieved);
+  // Merging global pool into a new Worklist.
+  TestWorklist worklist2;
+  TestWorklist::View worklist_view2(&worklist2, 0);
+  worklist2.MergeGlobalPool(&worklist1);
+  EXPECT_FALSE(worklist2.IsGlobalEmpty());
+  for (size_t i = 0; i < TestWorklist::kSegmentCapacity; i++) {
+    EXPECT_TRUE(worklist_view2.Pop(&retrieved));
+    EXPECT_EQ(&dummy, retrieved);
+    EXPECT_FALSE(worklist_view1.Pop(&retrieved));
+  }
+  EXPECT_TRUE(worklist1.IsGlobalEmpty());
+  EXPECT_TRUE(worklist2.IsGlobalEmpty());
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/platform/wtf/experimental/ContainerTypeOperationsTest.cpp b/third_party/WebKit/Source/platform/wtf/experimental/ContainerTypeOperationsTest.cpp
index f3a3ac6..4033a3e 100644
--- a/third_party/WebKit/Source/platform/wtf/experimental/ContainerTypeOperationsTest.cpp
+++ b/third_party/WebKit/Source/platform/wtf/experimental/ContainerTypeOperationsTest.cpp
@@ -21,7 +21,7 @@
 
 bool operator==(const Pod& left, const Pod& right) {
   return left.a == right.a && left.b == right.b &&
-         std::memcmp(left.c, right.c, sizeof(left.c)) == 0;
+         memcmp(left.c, right.c, sizeof(left.c)) == 0;
 }
 
 }  // namespace
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 fd79812..4b22703 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
@@ -82,10 +82,6 @@
     [[MS_TRUETYPE_FONTS_DIR], 'Courier_New_Bold.ttf', MS_TRUETYPE_FONTS_PACKAGE],
     [[MS_TRUETYPE_FONTS_DIR], 'Courier_New_Bold_Italic.ttf', MS_TRUETYPE_FONTS_PACKAGE],
     [[MS_TRUETYPE_FONTS_DIR], 'Courier_New_Italic.ttf', MS_TRUETYPE_FONTS_PACKAGE],
-    [[MS_TRUETYPE_FONTS_DIR], 'Georgia.ttf', MS_TRUETYPE_FONTS_PACKAGE],
-    [[MS_TRUETYPE_FONTS_DIR], 'Georgia_Bold.ttf', MS_TRUETYPE_FONTS_PACKAGE],
-    [[MS_TRUETYPE_FONTS_DIR], 'Georgia_Bold_Italic.ttf', MS_TRUETYPE_FONTS_PACKAGE],
-    [[MS_TRUETYPE_FONTS_DIR], 'Georgia_Italic.ttf', MS_TRUETYPE_FONTS_PACKAGE],
     [[MS_TRUETYPE_FONTS_DIR], 'Impact.ttf', MS_TRUETYPE_FONTS_PACKAGE],
     [[MS_TRUETYPE_FONTS_DIR], 'Trebuchet_MS.ttf', MS_TRUETYPE_FONTS_PACKAGE],
     [[MS_TRUETYPE_FONTS_DIR], 'Trebuchet_MS_Bold.ttf', MS_TRUETYPE_FONTS_PACKAGE],
diff --git a/third_party/WebKit/common/feature_policy/feature_policy.cc b/third_party/WebKit/common/feature_policy/feature_policy.cc
index 3a72450..1993828 100644
--- a/third_party/WebKit/common/feature_policy/feature_policy.cc
+++ b/third_party/WebKit/common/feature_policy/feature_policy.cc
@@ -11,11 +11,11 @@
 namespace blink {
 namespace {
 
-// Extracts a Whitelist from a ParsedFeaturePolicyDeclaration.
-std::unique_ptr<FeaturePolicy::Whitelist> WhitelistFromDeclaration(
+// Extracts an Allowlist from a ParsedFeaturePolicyDeclaration.
+std::unique_ptr<FeaturePolicy::Allowlist> AllowlistFromDeclaration(
     const ParsedFeaturePolicyDeclaration& parsed_declaration) {
-  std::unique_ptr<FeaturePolicy::Whitelist> result =
-      base::WrapUnique(new FeaturePolicy::Whitelist());
+  std::unique_ptr<FeaturePolicy::Allowlist> result =
+      base::WrapUnique(new FeaturePolicy::Allowlist());
   if (parsed_declaration.matches_all_origins)
     result->AddAll();
   for (const auto& origin : parsed_declaration.origins)
@@ -49,30 +49,30 @@
   // This method returns true only when the arguments are actually identical,
   // including the order of elements in the origins vector.
   // TODO(iclelland): Consider making this return true when comparing equal-
-  // but-not-identical whitelists, or eliminate those comparisons by maintaining
-  // the whiteslists in a normalized form.
+  // but-not-identical allowlists, or eliminate those comparisons by maintaining
+  // the allowlists in a normalized form.
   // https://crbug.com/710324
   return std::tie(lhs.feature, lhs.matches_all_origins, lhs.origins) ==
          std::tie(rhs.feature, rhs.matches_all_origins, rhs.origins);
 }
 
-FeaturePolicy::Whitelist::Whitelist() : matches_all_origins_(false) {}
+FeaturePolicy::Allowlist::Allowlist() : matches_all_origins_(false) {}
 
-FeaturePolicy::Whitelist::Whitelist(const Whitelist& rhs) = default;
+FeaturePolicy::Allowlist::Allowlist(const Allowlist& rhs) = default;
 
-FeaturePolicy::Whitelist::~Whitelist() = default;
+FeaturePolicy::Allowlist::~Allowlist() = default;
 
-void FeaturePolicy::Whitelist::Add(const url::Origin& origin) {
+void FeaturePolicy::Allowlist::Add(const url::Origin& origin) {
   origins_.push_back(origin);
 }
 
-void FeaturePolicy::Whitelist::AddAll() {
+void FeaturePolicy::Allowlist::AddAll() {
   matches_all_origins_ = true;
 }
 
-bool FeaturePolicy::Whitelist::Contains(const url::Origin& origin) const {
+bool FeaturePolicy::Allowlist::Contains(const url::Origin& origin) const {
   // This does not handle the case where origin is an opaque origin, which is
-  // also supposed to exist in the whitelist. (The identical opaque origins
+  // also supposed to exist in the allowlist. (The identical opaque origins
   // should match in that case)
   // TODO(iclelland): Fix that, possibly by having another flag for
   // 'matches_self', which will explicitly match the policy's origin.
@@ -86,11 +86,11 @@
   return false;
 }
 
-bool FeaturePolicy::Whitelist::MatchesAll() const {
+bool FeaturePolicy::Allowlist::MatchesAll() const {
   return matches_all_origins_;
 }
 
-const std::vector<url::Origin>& FeaturePolicy::Whitelist::Origins() const {
+const std::vector<url::Origin>& FeaturePolicy::Allowlist::Origins() const {
   return origins_;
 }
 
@@ -110,9 +110,9 @@
   std::unique_ptr<FeaturePolicy> new_policy =
       base::WrapUnique(new FeaturePolicy(origin, policy.feature_list_));
   new_policy->inherited_policies_ = policy.inherited_policies_;
-  for (const auto& feature : policy.whitelists_) {
-    new_policy->whitelists_[feature.first] =
-        base::WrapUnique(new Whitelist(*feature.second));
+  for (const auto& feature : policy.allowlists_) {
+    new_policy->allowlists_[feature.first] =
+        base::WrapUnique(new Allowlist(*feature.second));
   }
   return new_policy;
 }
@@ -129,9 +129,9 @@
   DCHECK(base::ContainsKey(inherited_policies_, feature));
   if (!inherited_policies_.at(feature))
     return false;
-  auto whitelist = whitelists_.find(feature);
-  if (whitelist != whitelists_.end())
-    return whitelist->second->Contains(origin);
+  auto allowlist = allowlists_.find(feature);
+  if (allowlist != allowlists_.end())
+    return allowlist->second->Contains(origin);
 
   const FeaturePolicy::FeatureDefault default_policy =
       feature_list_.at(feature);
@@ -146,37 +146,37 @@
   return false;
 }
 
-const FeaturePolicy::Whitelist FeaturePolicy::GetWhitelistForFeature(
+const FeaturePolicy::Allowlist FeaturePolicy::GetAllowlistForFeature(
     mojom::FeaturePolicyFeature feature) const {
   DCHECK(base::ContainsKey(feature_list_, feature));
   DCHECK(base::ContainsKey(inherited_policies_, feature));
   // Disabled through inheritance.
   if (!inherited_policies_.at(feature))
-    return FeaturePolicy::Whitelist();
+    return FeaturePolicy::Allowlist();
 
   // Return defined policy if exists; otherwise return default policy.
-  auto whitelist = whitelists_.find(feature);
-  if (whitelist != whitelists_.end())
-    return FeaturePolicy::Whitelist(*(whitelist->second));
+  auto allowlist = allowlists_.find(feature);
+  if (allowlist != allowlists_.end())
+    return FeaturePolicy::Allowlist(*(allowlist->second));
 
   const FeaturePolicy::FeatureDefault default_policy =
       feature_list_.at(feature);
-  FeaturePolicy::Whitelist default_whitelist;
+  FeaturePolicy::Allowlist default_allowlist;
 
   if (default_policy == FeaturePolicy::FeatureDefault::EnableForAll)
-    default_whitelist.AddAll();
+    default_allowlist.AddAll();
   else if (default_policy == FeaturePolicy::FeatureDefault::EnableForSelf)
-    default_whitelist.Add(origin_);
-  return default_whitelist;
+    default_allowlist.Add(origin_);
+  return default_allowlist;
 }
 
 void FeaturePolicy::SetHeaderPolicy(const ParsedFeaturePolicy& parsed_header) {
-  DCHECK(whitelists_.empty());
+  DCHECK(allowlists_.empty());
   for (const ParsedFeaturePolicyDeclaration& parsed_declaration :
        parsed_header) {
     mojom::FeaturePolicyFeature feature = parsed_declaration.feature;
     DCHECK(feature != mojom::FeaturePolicyFeature::kNotFound);
-    whitelists_[feature] = WhitelistFromDeclaration(parsed_declaration);
+    allowlists_[feature] = AllowlistFromDeclaration(parsed_declaration);
   }
 }
 
@@ -226,7 +226,7 @@
     mojom::FeaturePolicyFeature feature = parsed_declaration.feature;
     if (feature == mojom::FeaturePolicyFeature::kNotFound)
       continue;
-    if (WhitelistFromDeclaration(parsed_declaration)->Contains(origin_) &&
+    if (AllowlistFromDeclaration(parsed_declaration)->Contains(origin_) &&
         parent_policy->IsFeatureEnabled(feature)) {
       inherited_policies_[feature] = true;
     } else {
diff --git a/third_party/WebKit/public/common/feature_policy/feature_policy.h b/third_party/WebKit/public/common/feature_policy/feature_policy.h
index 80234623..112fce3a 100644
--- a/third_party/WebKit/public/common/feature_policy/feature_policy.h
+++ b/third_party/WebKit/public/common/feature_policy/feature_policy.h
@@ -113,12 +113,11 @@
   // policy. This collection may be set to match every origin (corresponding to
   // the "*" syntax in the policy string, in which case the Contains() method
   // will always return true.
-  // TODO(crbug.com/822317): Rename to Allowlist
-  class BLINK_COMMON_EXPORT Whitelist final {
+  class BLINK_COMMON_EXPORT Allowlist final {
    public:
-    Whitelist();
-    Whitelist(const Whitelist& rhs);
-    ~Whitelist();
+    Allowlist();
+    Allowlist(const Allowlist& rhs);
+    ~Allowlist();
 
     // Adds a single origin to the allowlist.
     void Add(const url::Origin& origin);
@@ -180,7 +179,7 @@
                                  const url::Origin& origin) const;
 
   // Returns the allowlist of a given feature by this policy.
-  const Whitelist GetWhitelistForFeature(
+  const Allowlist GetAllowlistForFeature(
       mojom::FeaturePolicyFeature feature) const;
 
   // Sets the declared policy from the parsed Feature-Policy HTTP header.
@@ -212,7 +211,7 @@
 
   // Map of feature names to declared allowlists. Any feature which is missing
   // from this map should use the inherited policy.
-  std::map<mojom::FeaturePolicyFeature, std::unique_ptr<Whitelist>> whitelists_;
+  std::map<mojom::FeaturePolicyFeature, std::unique_ptr<Allowlist>> allowlists_;
 
   // Records whether or not each feature was enabled for this frame by its
   // parent frame.
diff --git a/third_party/WebKit/public/platform/modules/credentialmanager/credential_manager.mojom b/third_party/WebKit/public/platform/modules/credentialmanager/credential_manager.mojom
index 42c1b57..3ee3e8e2 100644
--- a/third_party/WebKit/public/platform/modules/credentialmanager/credential_manager.mojom
+++ b/third_party/WebKit/public/platform/modules/credentialmanager/credential_manager.mojom
@@ -4,6 +4,7 @@
 
 module password_manager.mojom;
 
+import "mojo/public/mojom/base/string16.mojom";
 import "url/mojom/origin.mojom";
 import "url/mojom/url.mojom";
 
@@ -32,10 +33,10 @@
 
 struct CredentialInfo {
   CredentialType type;
-  string? id;
-  string? name;
+  mojo_base.mojom.String16? id;
+  mojo_base.mojom.String16? name;
   url.mojom.Url icon;
-  string? password;
+  mojo_base.mojom.String16? password;
   url.mojom.Origin federation;
 };
 
diff --git a/third_party/WebKit/public/platform/web_feature.mojom b/third_party/WebKit/public/platform/web_feature.mojom
index fe7625ee..15539120 100644
--- a/third_party/WebKit/public/platform/web_feature.mojom
+++ b/third_party/WebKit/public/platform/web_feature.mojom
@@ -1881,6 +1881,7 @@
   kDistrustedLegacySymantecSubresource = 2389,
   kVRDisplayGetFrameData = 2390,
   kXMLHttpRequestResponseXML = 2391,
+  kMessagePortTransferClosedPort = 2392,
 
   // 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/widevine/cdm/BUILD.gn b/third_party/widevine/cdm/BUILD.gn
index bf66c97e..977005ec 100644
--- a/third_party/widevine/cdm/BUILD.gn
+++ b/third_party/widevine/cdm/BUILD.gn
@@ -22,15 +22,12 @@
 widevine_cdm_binary_files = []
 widevine_cdm_manifest_file = []
 
-if (is_android) {
-  # Always available on Android regardless of branding.
-  widevine_cdm_version_h_file = "android/widevine_cdm_version.h"
-} else if (is_chrome_branded) {
+if (should_bundle_widevine_cdm) {
   if (is_chromeos) {
     widevine_cdm_version_h_file =
         "chromeos/$widevine_arch/widevine_cdm_version.h"
     widevine_cdm_binary_files = [ "chromeos/$widevine_arch/libwidevinecdm.so" ]
-  } else if (is_linux) {
+  } else if (is_desktop_linux) {
     widevine_cdm_version_h_file = "linux/$widevine_arch/widevine_cdm_version.h"
     widevine_cdm_binary_files = [ "linux/$widevine_arch/libwidevinecdm.so" ]
   } else if (is_win) {
@@ -38,20 +35,18 @@
     widevine_cdm_binary_files = [
       "win/$widevine_arch/widevinecdm.dll",
       "win/$widevine_arch/widevinecdm.dll.lib",
-      "win/$widevine_arch/widevinecdm.dll.sig",
     ]
     widevine_cdm_manifest_file = [ "win/$widevine_arch/manifest.json" ]
   } else if (is_mac) {
     widevine_cdm_version_h_file = "mac/$widevine_arch/widevine_cdm_version.h"
-    widevine_cdm_binary_files = [
-      "mac/$widevine_arch/libwidevinecdm.dylib",
-      "mac/$widevine_arch/libwidevinecdm.dylib.sig",
-    ]
+    widevine_cdm_binary_files = [ "mac/$widevine_arch/libwidevinecdm.dylib" ]
     widevine_cdm_manifest_file = [ "mac/$widevine_arch/manifest.json" ]
   } else {
-    # Other platforms, use the default one.
-    widevine_cdm_version_h_file = "widevine_cdm_version.h"
+    assert(false, "Platform not supported to bundle Widevine CDM.")
   }
+} else if (is_android) {
+  # Always available on Android regardless of branding.
+  widevine_cdm_version_h_file = "android/widevine_cdm_version.h"
 } else if (enable_widevine) {
   # TODO(crbug.com/349182): Remove after we replace WIDEVINE_CDM_AVAILABLE with
   # ENABLE_WIDEVINE build flag.
@@ -61,6 +56,15 @@
   widevine_cdm_version_h_file = "widevine_cdm_version.h"
 }
 
+if (should_bundle_widevine_cdm && enable_widevine_cdm_host_verification) {
+  if (is_win) {
+    widevine_cdm_binary_files += [ "win/$widevine_arch/widevinecdm.dll.sig" ]
+  } else if (is_mac) {
+    widevine_cdm_binary_files +=
+        [ "mac/$widevine_arch/libwidevinecdm.dylib.sig" ]
+  }
+}
+
 copy("version_h") {
   visibility = [ ":*" ]  # Depend on ":headers" instead.
   sources = [
@@ -133,18 +137,3 @@
     ]
   }
 }
-
-if (is_chrome_branded) {
-  copy("widevine_signature_scripts") {
-    sources = [
-      "../scripts/signature_generator.py",
-      "../scripts/signer.py",
-    ]
-    outputs = [
-      "$root_out_dir/installer/widevine/{{source_file_part}}",
-    ]
-  }
-} else {
-  group("widevine_signature_scripts") {
-  }
-}
diff --git a/tools/mb/mb.py b/tools/mb/mb.py
index 2461777..4799b74a 100755
--- a/tools/mb/mb.py
+++ b/tools/mb/mb.py
@@ -1022,6 +1022,11 @@
       self.WriteFailureAndRaise('No command line for %s found (test type %s).'
                                 % (target, test_type), output_path=None)
 
+    if is_win and asan:
+      # Sandbox is not yet supported by ASAN for Windows.
+      # Perhaps this is only needed for tests that use the sandbox?
+      cmdline.append('--no-sandbox')
+
     cmdline += isolate_map[target].get('args', [])
 
     return cmdline, extra_files
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl
index 9b371ec..3f58e75 100644
--- a/tools/mb/mb_config.pyl
+++ b/tools/mb/mb_config.pyl
@@ -125,7 +125,7 @@
       'CrWinClangLLD64': 'clang_tot_shared_release_use_lld_dcheck',
       'CrWinClngLLD64dbg': 'clang_tot_full_symbols_shared_debug_use_lld',
       'CrWinClngLLDdbg': 'clang_tot_full_symbols_shared_debug_use_lld_x86',
-      'linux-win_cross-rel': 'win_release_cross',
+      'linux-win_cross-rel': 'clang_tot_win_release_cross',
       'ToTAndroid': 'android_clang_tot_release',
       'ToTAndroid64': 'android_clang_tot_release_arm64',
       'ToTAndroidASan': 'android_clang_tot_asan',
@@ -1741,8 +1741,8 @@
       'clang', 'release_bot', 'minimal_symbols', 'disable_nacl',
     ],
 
-    'win_release_cross': [
-      'win_cross', 'minimal_symbols', 'shared', 'release', 'dcheck_always_on',
+    'clang_tot_win_release_cross': [
+      'clang_tot', 'win_cross', 'minimal_symbols', 'shared', 'release', 'dcheck_always_on',
     ],
 
     'windows_analyze': [
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index bf5cc8cc..054a99ec 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -12667,6 +12667,7 @@
   <int value="428" label="MachineLevelUserCloudPolicyEnrollmentToken"/>
   <int value="429" label="SafeBrowsingExtendedReportingEnabled"/>
   <int value="430" label="AutoplayAllowed"/>
+  <int value="431" label="AutoplayWhitelist"/>
 </enum>
 
 <enum name="EnterprisePolicyInvalidations">
@@ -17973,6 +17974,7 @@
   <int value="2389" label="DistrustedLegacySymantecSubresource"/>
   <int value="2390" label="VRDisplayGetFrameData"/>
   <int value="2391" label="XMLHttpRequestResponseXML"/>
+  <int value="2392" label="MessagePortTransferClosedPort"/>
 </enum>
 
 <enum name="FeedbackSource">
@@ -19024,6 +19026,14 @@
   <int value="2" label="Others"/>
 </enum>
 
+<enum name="FirstRunSentinelResult">
+  <summary>Result of sentinel file has been written.</summary>
+  <int value="0" label="Written successfully"/>
+  <int value="1" label="Failed to get file path"/>
+  <int value="2" label="File exists"/>
+  <int value="3" label="File error"/>
+</enum>
+
 <enum name="FirstRunSignInResult">
   <summary>Result states for the first-run sign-in flow.</summary>
   <int value="0" label="Skipped Immediately"/>
@@ -19032,7 +19042,7 @@
   <int value="3" label="Have SSO account, Skipped Immediately"/>
   <int value="4" label="Have SSO account, Successful"/>
   <int value="5" label="Have SSO account, Gave Up"/>
-  <int value="6" label="Could not create FirstRun Sentinel"/>
+  <int value="6" label="Could not create FirstRun Sentinel - deprecated"/>
 </enum>
 
 <enum name="FirstUserActionType">
@@ -25691,6 +25701,7 @@
   <int value="-1963427770" label="EmojiHandwritingVoiceInput:disabled"/>
   <int value="-1963402827" label="enable-topchrome-md"/>
   <int value="-1962588488" label="SpeculativePreconnect:disabled"/>
+  <int value="-1961931929" label="ContextualSuggestionsBottomSheet:enabled"/>
   <int value="-1961648833" label="show_summary"/>
   <int value="-1961497025" label="tint-gl-composited-content"/>
   <int value="-1961062505" label="VrBrowsingInCustomTab:disabled"/>
@@ -26165,6 +26176,7 @@
   <int value="-879055117" label="ClipboardContentSetting:enabled"/>
   <int value="-879031960" label="FetchKeepaliveTimeoutSetting:disabled"/>
   <int value="-876148583" label="ArcBootCompletedBroadcast:disabled"/>
+  <int value="-872764392" label="ContextualSuggestionsBottomSheet:disabled"/>
   <int value="-867087281" label="enable-virtual-keyboard"/>
   <int value="-866993841" label="OfflinePagesCTV2:disabled"/>
   <int value="-865390600" label="NativeSmb:enabled"/>
@@ -31779,6 +31791,7 @@
   <int value="9" label="Opened a suggestion"/>
   <int value="10" label="Opened the Learn More link"/>
   <int value="11" label="Opened the Promo"/>
+  <int value="12" label="Opened a history entry"/>
 </enum>
 
 <enum name="NewTabPageBookmarkActionAndroid">
@@ -34207,6 +34220,12 @@
   <int value="2" label="Clicked do not collect URL"/>
 </enum>
 
+<enum name="PasswordManagerAndroidExportPasswordsProgressBarUsage">
+  <int value="0" label="Not hidden because not shown"/>
+  <int value="1" label="Hidden directly"/>
+  <int value="2" label="Hidden with a delay"/>
+</enum>
+
 <enum name="PasswordManagerAndroidPasswordActions">
   <int value="0" label="Copied"/>
   <int value="1" label="Displayed"/>
@@ -35235,6 +35254,7 @@
 </enum>
 
 <enum name="PlatformFileError">
+  <summary>Errors from base::File::Error</summary>
   <int value="0" label="OK"/>
   <int value="1" label="FAILED"/>
   <int value="2" label="IN_USE"/>
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index ab38b1bc..2a8da3c 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -12226,21 +12226,21 @@
   </summary>
 </histogram>
 
-<histogram name="Cookie.AgeForNonSecureCrossSiteRequest" units="days">
+<histogram base="true" name="Cookie.AgeFor" units="days">
   <owner>mkwst@chromium.org</owner>
+  <owner>tnagel@chromium.org</owner>
   <summary>
     Records the age (in days) of the oldest cookie delivered along with a
-    non-secure, cross-site request. Recorded when setting the `Cookie` header
-    for a given request.
+    request. Recorded when setting the `Cookie` header for a given request.
   </summary>
 </histogram>
 
-<histogram name="Cookie.AgeForNonSecureSameSiteRequest" units="days">
+<histogram base="true" name="Cookie.AllAgesFor" units="days">
   <owner>mkwst@chromium.org</owner>
+  <owner>tnagel@chromium.org</owner>
   <summary>
-    Records the age (in days) of the oldest cookie delivered along with a
-    non-secure, same-site request. Recorded when setting the `Cookie` header for
-    a given request.
+    Records the age (in days) of all cookies delivered along with a request.
+    Recorded when setting the `Cookie` header for a given request.
   </summary>
 </histogram>
 
@@ -13294,6 +13294,15 @@
   </summary>
 </histogram>
 
+<histogram name="CustomTabs.DetachedResourceRequest.RedirectsCount"
+    units="redirects">
+  <owner>lizeb@chromium.org</owner>
+  <summary>
+    Number of redirects followed by a detached resource request until success or
+    failure. Android only.
+  </summary>
+</histogram>
+
 <histogram name="CustomTabs.IntentToFirstCommitNavigationTime" units="ms">
   <obsolete>
     Deprecated 10/2016 in favor of .IntentToFirstCommitNavigationTime2.*.
@@ -27157,6 +27166,16 @@
   </summary>
 </histogram>
 
+<histogram name="FirstRun.Sentinel.Created" enum="FirstRunSentinelResult">
+  <owner>jlebel@chromium.org</owner>
+  <summary>Result of sentinel file has been written.</summary>
+</histogram>
+
+<histogram name="FirstRun.Sentinel.CreatedFileError" enum="PlatformFileError">
+  <owner>jlebel@chromium.org</owner>
+  <summary>File error when the sentinel file was not written.</summary>
+</histogram>
+
 <histogram name="FirstRun.SignIn" enum="FirstRunSignInResult">
   <owner>msarda@chromium.org</owner>
   <summary>Result of the sign in flow during Mobile first run.</summary>
@@ -61918,6 +61937,15 @@
   <summary>Why was &quot;Allow to collect URL?&quot; bubble closed?</summary>
 </histogram>
 
+<histogram name="PasswordManager.Android.ExportPasswordsProgressBarUsage"
+    enum="PasswordManagerAndroidExportPasswordsProgressBarUsage">
+  <owner>vabr@chromium.org</owner>
+  <summary>
+    Records what happened to the progress bar during exporting passwords when
+    its dismissal was requested.
+  </summary>
+</histogram>
+
 <histogram name="PasswordManager.Android.PasswordCredentialEntry"
     enum="PasswordManagerAndroidPasswordEntryActions">
   <owner>jdoerrie@chromium.org</owner>
@@ -85650,6 +85678,9 @@
 </histogram>
 
 <histogram name="SiteIsolation.XSD.DataLength" units="byte">
+  <obsolete>
+    Removed in March 2018; in M67+, browser-process CORB policy is enabled.
+  </obsolete>
   <owner>creis@chromium.org</owner>
   <summary>
     The number of bytes in the first network packet for a response with headers
@@ -85659,6 +85690,9 @@
 </histogram>
 
 <histogram name="SiteIsolation.XSD.HTML.Blocked">
+  <obsolete>
+    Removed in March 2018; in M67+, browser-process CORB policy is enabled.
+  </obsolete>
   <owner>creis@chromium.org</owner>
   <summary>
     The count of blocked cross-site document responses due to having HTML
@@ -85668,6 +85702,9 @@
 </histogram>
 
 <histogram name="SiteIsolation.XSD.HTML.Blocked.NonRenderableStatusCode">
+  <obsolete>
+    Removed in March 2018; in M67+, browser-process CORB policy is enabled.
+  </obsolete>
   <owner>creis@chromium.org</owner>
   <summary>
     The count of responses with a nonrenderable HTTP status code among blocked
@@ -85694,6 +85731,9 @@
 
 <histogram name="SiteIsolation.XSD.HTML.Blocked.RenderableStatusCode2"
     enum="ContentResourceType2">
+  <obsolete>
+    Removed in March 2018; in M67+, browser-process CORB policy is enabled.
+  </obsolete>
   <owner>creis@chromium.org</owner>
   <summary>
     The count of responses with a renderable HTTP status code sub-categorized by
@@ -85705,6 +85745,9 @@
 </histogram>
 
 <histogram name="SiteIsolation.XSD.HTML.NoSniffBlocked.NonRenderableStatusCode">
+  <obsolete>
+    Removed in March 2018; in M67+, browser-process CORB policy is enabled.
+  </obsolete>
   <owner>creis@chromium.org</owner>
   <summary>
     The count of responses with a nonrenderable HTTP status code among blocked
@@ -85732,6 +85775,9 @@
 
 <histogram name="SiteIsolation.XSD.HTML.NoSniffBlocked.RenderableStatusCode2"
     enum="ContentResourceType2">
+  <obsolete>
+    Removed in March 2018; in M67+, browser-process CORB policy is enabled.
+  </obsolete>
   <owner>creis@chromium.org</owner>
   <summary>
     The count of responses with a renderable HTTP status code sub-categorized by
@@ -85743,6 +85789,9 @@
 </histogram>
 
 <histogram name="SiteIsolation.XSD.HTML.NotBlocked">
+  <obsolete>
+    Removed in March 2018; in M67+, browser-process CORB policy is enabled.
+  </obsolete>
   <owner>creis@chromium.org</owner>
   <summary>
     The count of not blocked responses despite having an HTML content type
@@ -85752,6 +85801,9 @@
 </histogram>
 
 <histogram name="SiteIsolation.XSD.HTML.NotBlocked.MaybeJS">
+  <obsolete>
+    Removed in March 2018; in M67+, browser-process CORB policy is enabled.
+  </obsolete>
   <owner>creis@chromium.org</owner>
   <summary>
     The count of responses that may be parsed as JavaScript among not blocked
@@ -85761,6 +85813,9 @@
 </histogram>
 
 <histogram name="SiteIsolation.XSD.JSON.Blocked">
+  <obsolete>
+    Removed in March 2018; in M67+, browser-process CORB policy is enabled.
+  </obsolete>
   <owner>creis@chromium.org</owner>
   <summary>
     The count of blocked cross-site document responses due to having JSON
@@ -85770,6 +85825,9 @@
 </histogram>
 
 <histogram name="SiteIsolation.XSD.JSON.Blocked.NonRenderableStatusCode">
+  <obsolete>
+    Removed in March 2018; in M67+, browser-process CORB policy is enabled.
+  </obsolete>
   <owner>creis@chromium.org</owner>
   <summary>
     The count of responses with a nonrenderable HTTP status code among blocked
@@ -85796,6 +85854,9 @@
 
 <histogram name="SiteIsolation.XSD.JSON.Blocked.RenderableStatusCode2"
     enum="ContentResourceType2">
+  <obsolete>
+    Removed in March 2018; in M67+, browser-process CORB policy is enabled.
+  </obsolete>
   <owner>creis@chromium.org</owner>
   <summary>
     The count of responses with a renderable HTTP status code sub-categorized by
@@ -85807,6 +85868,9 @@
 </histogram>
 
 <histogram name="SiteIsolation.XSD.JSON.NoSniffBlocked.NonRenderableStatusCode">
+  <obsolete>
+    Removed in March 2018; in M67+, browser-process CORB policy is enabled.
+  </obsolete>
   <owner>creis@chromium.org</owner>
   <summary>
     The count of responses with a nonrenderable HTTP status code among blocked
@@ -85834,6 +85898,9 @@
 
 <histogram name="SiteIsolation.XSD.JSON.NoSniffBlocked.RenderableStatusCode2"
     enum="ContentResourceType2">
+  <obsolete>
+    Removed in March 2018; in M67+, browser-process CORB policy is enabled.
+  </obsolete>
   <owner>creis@chromium.org</owner>
   <summary>
     The count of responses with a renderable HTTP status code sub-categorized by
@@ -85845,6 +85912,9 @@
 </histogram>
 
 <histogram name="SiteIsolation.XSD.JSON.NotBlocked">
+  <obsolete>
+    Removed in March 2018; in M67+, browser-process CORB policy is enabled.
+  </obsolete>
   <owner>creis@chromium.org</owner>
   <summary>
     The count of not blocked responses despite having an JSON content type
@@ -85854,6 +85924,9 @@
 </histogram>
 
 <histogram name="SiteIsolation.XSD.JSON.NotBlocked.MaybeJS">
+  <obsolete>
+    Removed in March 2018; in M67+, browser-process CORB policy is enabled.
+  </obsolete>
   <owner>creis@chromium.org</owner>
   <summary>
     The count of responses that may be parsed as JavaScript among not blocked
@@ -85863,6 +85936,9 @@
 </histogram>
 
 <histogram name="SiteIsolation.XSD.MimeType" enum="SiteIsolationMimeType">
+  <obsolete>
+    Removed in March 2018; in M67+, browser-process CORB policy is enabled.
+  </obsolete>
   <owner>creis@chromium.org</owner>
   <summary>
     MIME type codes for content type header values of potentially cross-site
@@ -85873,6 +85949,9 @@
 </histogram>
 
 <histogram name="SiteIsolation.XSD.Plain.HTML.Blocked">
+  <obsolete>
+    Removed in March 2018; in M67+, browser-process CORB policy is enabled.
+  </obsolete>
   <owner>creis@chromium.org</owner>
   <summary>
     The count of blocked cross-site document responses due to having Plain
@@ -85882,6 +85961,9 @@
 </histogram>
 
 <histogram name="SiteIsolation.XSD.Plain.HTML.Blocked.NonRenderableStatusCode">
+  <obsolete>
+    Removed in March 2018; in M67+, browser-process CORB policy is enabled.
+  </obsolete>
   <owner>creis@chromium.org</owner>
   <summary>
     The count of responses with a nonrenderable HTTP status code among blocked
@@ -85908,6 +85990,9 @@
 
 <histogram name="SiteIsolation.XSD.Plain.HTML.Blocked.RenderableStatusCode2"
     enum="ContentResourceType2">
+  <obsolete>
+    Removed in March 2018; in M67+, browser-process CORB policy is enabled.
+  </obsolete>
   <owner>creis@chromium.org</owner>
   <summary>
     The count of responses with a renderable HTTP status code sub-categorized by
@@ -85919,6 +86004,9 @@
 </histogram>
 
 <histogram name="SiteIsolation.XSD.Plain.JSON.Blocked">
+  <obsolete>
+    Removed in March 2018; in M67+, browser-process CORB policy is enabled.
+  </obsolete>
   <owner>creis@chromium.org</owner>
   <summary>
     The count of blocked cross-site document responses due to having Plain
@@ -85928,6 +86016,9 @@
 </histogram>
 
 <histogram name="SiteIsolation.XSD.Plain.JSON.Blocked.NonRenderableStatusCode">
+  <obsolete>
+    Removed in March 2018; in M67+, browser-process CORB policy is enabled.
+  </obsolete>
   <owner>creis@chromium.org</owner>
   <summary>
     The count of responses with a nonrenderable HTTP status code among blocked
@@ -85955,6 +86046,9 @@
 
 <histogram name="SiteIsolation.XSD.Plain.JSON.Blocked.RenderableStatusCode2"
     enum="ContentResourceType2">
+  <obsolete>
+    Removed in March 2018; in M67+, browser-process CORB policy is enabled.
+  </obsolete>
   <owner>creis@chromium.org</owner>
   <summary>
     The count of responses with a renderable HTTP status code sub-categorized by
@@ -85967,6 +86061,9 @@
 
 <histogram
     name="SiteIsolation.XSD.Plain.NoSniffBlocked.NonRenderableStatusCode">
+  <obsolete>
+    Removed in March 2018; in M67+, browser-process CORB policy is enabled.
+  </obsolete>
   <owner>creis@chromium.org</owner>
   <summary>
     The count of responses with a nonrenderable HTTP status code among blocked
@@ -85994,6 +86091,9 @@
 
 <histogram name="SiteIsolation.XSD.Plain.NoSniffBlocked.RenderableStatusCode2"
     enum="ContentResourceType2">
+  <obsolete>
+    Removed in March 2018; in M67+, browser-process CORB policy is enabled.
+  </obsolete>
   <owner>creis@chromium.org</owner>
   <summary>
     The count of responses with a renderable HTTP status code sub-categorized by
@@ -86005,6 +86105,9 @@
 </histogram>
 
 <histogram name="SiteIsolation.XSD.Plain.NotBlocked">
+  <obsolete>
+    Removed in March 2018; in M67+, browser-process CORB policy is enabled.
+  </obsolete>
   <owner>creis@chromium.org</owner>
   <summary>
     The count of not blocked responses despite having an Plain content type
@@ -86014,6 +86117,9 @@
 </histogram>
 
 <histogram name="SiteIsolation.XSD.Plain.NotBlocked.MaybeJS">
+  <obsolete>
+    Removed in March 2018; in M67+, browser-process CORB policy is enabled.
+  </obsolete>
   <owner>creis@chromium.org</owner>
   <summary>
     The count of responses that may be parsed as JavaScript among not blocked
@@ -86023,6 +86129,9 @@
 </histogram>
 
 <histogram name="SiteIsolation.XSD.Plain.XML.Blocked">
+  <obsolete>
+    Removed in March 2018; in M67+, browser-process CORB policy is enabled.
+  </obsolete>
   <owner>creis@chromium.org</owner>
   <summary>
     The count of blocked cross-site document responses due to having Plain
@@ -86032,6 +86141,9 @@
 </histogram>
 
 <histogram name="SiteIsolation.XSD.Plain.XML.Blocked.NonRenderableStatusCode">
+  <obsolete>
+    Removed in March 2018; in M67+, browser-process CORB policy is enabled.
+  </obsolete>
   <owner>creis@chromium.org</owner>
   <summary>
     The count of responses with a nonrenderable HTTP status code among blocked
@@ -86059,6 +86171,9 @@
 
 <histogram name="SiteIsolation.XSD.Plain.XML.Blocked.RenderableStatusCode2"
     enum="ContentResourceType2">
+  <obsolete>
+    Removed in March 2018; in M67+, browser-process CORB policy is enabled.
+  </obsolete>
   <owner>creis@chromium.org</owner>
   <summary>
     The count of responses with renderable HTTP status codes sub-categorized by
@@ -86070,6 +86185,9 @@
 </histogram>
 
 <histogram name="SiteIsolation.XSD.XML.Blocked">
+  <obsolete>
+    Removed in March 2018; in M67+, browser-process CORB policy is enabled.
+  </obsolete>
   <owner>creis@chromium.org</owner>
   <summary>
     The count of blocked cross-site document responses due to having XML content
@@ -86079,6 +86197,9 @@
 </histogram>
 
 <histogram name="SiteIsolation.XSD.XML.Blocked.NonRenderableStatusCode">
+  <obsolete>
+    Removed in March 2018; in M67+, browser-process CORB policy is enabled.
+  </obsolete>
   <owner>creis@chromium.org</owner>
   <summary>
     The count of responses with nonrenderable HTTP status codes among blocked
@@ -86105,6 +86226,9 @@
 
 <histogram name="SiteIsolation.XSD.XML.Blocked.RenderableStatusCode2"
     enum="ContentResourceType2">
+  <obsolete>
+    Removed in March 2018; in M67+, browser-process CORB policy is enabled.
+  </obsolete>
   <owner>creis@chromium.org</owner>
   <summary>
     The count of responses with renderable HTTP status codes sub-categorized by
@@ -86116,6 +86240,9 @@
 </histogram>
 
 <histogram name="SiteIsolation.XSD.XML.NoSniffBlocked.NonRenderableStatusCode">
+  <obsolete>
+    Removed in March 2018; in M67+, browser-process CORB policy is enabled.
+  </obsolete>
   <owner>creis@chromium.org</owner>
   <summary>
     The count of responses with a nonrenderable HTTP status code among blocked
@@ -86143,6 +86270,9 @@
 
 <histogram name="SiteIsolation.XSD.XML.NoSniffBlocked.RenderableStatusCode2"
     enum="ContentResourceType2">
+  <obsolete>
+    Removed in March 2018; in M67+, browser-process CORB policy is enabled.
+  </obsolete>
   <owner>creis@chromium.org</owner>
   <summary>
     The count of responses with a renderable HTTP status code sub-categorized by
@@ -86154,6 +86284,9 @@
 </histogram>
 
 <histogram name="SiteIsolation.XSD.XML.NotBlocked">
+  <obsolete>
+    Removed in March 2018; in M67+, browser-process CORB policy is enabled.
+  </obsolete>
   <owner>creis@chromium.org</owner>
   <summary>
     The count of not blocked responses despite having an XML content type header
@@ -86163,6 +86296,9 @@
 </histogram>
 
 <histogram name="SiteIsolation.XSD.XML.NotBlocked.MaybeJS">
+  <obsolete>
+    Removed in March 2018; in M67+, browser-process CORB policy is enabled.
+  </obsolete>
   <owner>creis@chromium.org</owner>
   <summary>
     The count of responses that may be parsed as JavaScript among not blocked
@@ -105652,6 +105788,22 @@
   <affected-histogram name="Search.ContextualSearchQuickActions.ResultsSeen"/>
 </histogram_suffixes>
 
+<histogram_suffixes name="CookieConnectionType" separator="">
+  <suffix name="NonSecure" label="For non-secure,"/>
+  <suffix name="Secure" label="For secure,"/>
+  <affected-histogram name="Cookie.AgeFor"/>
+  <affected-histogram name="Cookie.AllAgesFor"/>
+</histogram_suffixes>
+
+<histogram_suffixes name="CookieSiteAffinity" separator="">
+  <suffix name="CrossSiteRequest" label="cross-site requests."/>
+  <suffix name="SameSiteRequest" label="same-site requests."/>
+  <affected-histogram name="Cookie.AgeForNonSecure"/>
+  <affected-histogram name="Cookie.AgeForSecure"/>
+  <affected-histogram name="Cookie.AllAgesForNonSecure"/>
+  <affected-histogram name="Cookie.AllAgesForSecure"/>
+</histogram_suffixes>
+
 <histogram_suffixes name="CreditCardScanSuccess" separator="_">
   <suffix name="Completed" label="Credit card scan completed."/>
   <suffix name="Cancelled" label="Credit card scan was cancelled."/>
@@ -105686,11 +105838,12 @@
   <suffix name="Other" label="CustomTab opened by other apps."/>
 </histogram_suffixes>
 
-<histogram_suffixes name="CustomTabs.DetachedResourceRequest.Duration"
+<histogram_suffixes name="CustomTabs.DetachedResourceRequestFinalStatus"
     separator=".">
   <suffix name="Success" label="Successful detached request"/>
   <suffix name="Failure" label="Failed detached request"/>
   <affected-histogram name="CustomTabs.DetachedResourceRequest.Duration"/>
+  <affected-histogram name="CustomTabs.DetachedResourceRequest.RedirectsCount"/>
 </histogram_suffixes>
 
 <histogram_suffixes name="DataReductionProxy" separator="_">
diff --git a/tools/perf/core/perf_data_generator.py b/tools/perf/core/perf_data_generator.py
index e149fd996..d4f7169 100755
--- a/tools/perf/core/perf_data_generator.py
+++ b/tools/perf/core/perf_data_generator.py
@@ -1059,6 +1059,10 @@
     'One Buildbot Step Test Builder': {
       'isolate': 'telemetry_perf_tests_experimental',
       'platform': 'linux',
+      'dimension': {
+        'pool': 'Chrome-perf-fyi',
+        'os': 'Linux',
+      },
       'testing': True,
       'device_ids': [
           'swarm823-c4',
@@ -1069,6 +1073,11 @@
     'Mac 10.12 Laptop Low End': {
       'isolate': 'performance_test_suite',
       'platform': 'mac',
+      'dimension': {
+        'pool': 'Chrome-perf-fyi',
+        'os': 'Mac-10.12',
+        'gpu': '8086:1626'
+      },
       'device_ids': [
           'build195-a9', 'build196-a9', 'build197-a9', 'build198-a9',
           'build199-a9', 'build200-a9', 'build201-a9', 'build202-a9',
@@ -1158,9 +1167,7 @@
     'ignore_task_failure': False,
     'io_timeout': 30 * 60, # 30 minutes
     'dimension_sets': [
-      {
-        'pool': 'Chrome-perf-fyi',
-      }
+      tester_config['dimension']
     ],
     'upload_test_results': True,
     'shards': shards,
diff --git a/ui/android/java/src/org/chromium/ui/base/SelectFileDialog.java b/ui/android/java/src/org/chromium/ui/base/SelectFileDialog.java
index 4fdd56c6..e1e41c5 100644
--- a/ui/android/java/src/org/chromium/ui/base/SelectFileDialog.java
+++ b/ui/android/java/src/org/chromium/ui/base/SelectFileDialog.java
@@ -28,7 +28,6 @@
 import org.chromium.base.VisibleForTesting;
 import org.chromium.base.annotations.CalledByNative;
 import org.chromium.base.annotations.JNINamespace;
-import org.chromium.base.annotations.MainDex;
 import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.ui.PhotoPickerListener;
 import org.chromium.ui.R;
@@ -46,7 +45,6 @@
  * a set of accepted file types. The path of the selected file is passed to the native dialog.
  */
 @JNINamespace("ui")
-@MainDex
 public class SelectFileDialog implements WindowAndroid.IntentCallback,
                                          WindowAndroid.PermissionCallback, PhotoPickerListener {
     private static final String TAG = "SelectFileDialog";
diff --git a/ui/app_list/views/folder_header_view.cc b/ui/app_list/views/folder_header_view.cc
index 59f23555..3c686c7 100644
--- a/ui/app_list/views/folder_header_view.cc
+++ b/ui/app_list/views/folder_header_view.cc
@@ -34,7 +34,11 @@
 
 class FolderHeaderView::FolderNameView : public views::Textfield {
  public:
-  FolderNameView() { SetBorder(views::CreateEmptyBorder(1, 1, 1, 1)); }
+  explicit FolderNameView(FolderHeaderView* folder_header_view)
+      : folder_header_view_(folder_header_view) {
+    DCHECK(folder_header_view_);
+    SetBorder(views::CreateEmptyBorder(1, 1, 1, 1));
+  }
 
   ~FolderNameView() override = default;
 
@@ -43,13 +47,23 @@
     Textfield::OnFocus();
   }
 
+  void OnBlur() override {
+    // Collapse whitespace when FolderNameView loses focus.
+    SetText(base::CollapseWhitespace(text(), false));
+    folder_header_view_->ContentsChanged(this, text());
+    Textfield::OnBlur();
+  }
+
  private:
+  // The parent FolderHeaderView, owns this.
+  FolderHeaderView* folder_header_view_;
+
   DISALLOW_COPY_AND_ASSIGN(FolderNameView);
 };
 
 FolderHeaderView::FolderHeaderView(FolderHeaderViewDelegate* delegate)
     : folder_item_(nullptr),
-      folder_name_view_(new FolderNameView),
+      folder_name_view_(new FolderNameView(this)),
       folder_name_placeholder_text_(
           ui::ResourceBundle::GetSharedInstance().GetLocalizedString(
               IDS_APP_LIST_FOLDER_NAME_PLACEHOLDER)),
diff --git a/ui/app_list/views/folder_header_view_unittest.cc b/ui/app_list/views/folder_header_view_unittest.cc
index d469a2d..ee30076 100644
--- a/ui/app_list/views/folder_header_view_unittest.cc
+++ b/ui/app_list/views/folder_header_view_unittest.cc
@@ -60,13 +60,24 @@
   // testing::Test overrides:
   void SetUp() override {
     views::ViewsTestBase::SetUp();
-    model_.reset(new AppListTestModel);
+    model_ = std::make_unique<AppListTestModel>();
+    delegate_ = std::make_unique<TestFolderHeaderViewDelegate>();
 
-    delegate_.reset(new TestFolderHeaderViewDelegate);
-    folder_header_view_.reset(new FolderHeaderView(delegate_.get()));
+    // Create a widget so that the FolderNameView can be focused.
+    widget_ = std::make_unique<views::Widget>();
+    views::Widget::InitParams params = views::ViewsTestBase::CreateParams(
+        views::Widget::InitParams::TYPE_POPUP);
+    params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+    params.bounds = gfx::Rect(0, 0, 650, 650);
+    widget_->Init(params);
+    widget_->Show();
+
+    folder_header_view_ = std::make_unique<FolderHeaderView>(delegate_.get());
+    widget_->SetContentsView(folder_header_view_.get());
   }
 
   void TearDown() override {
+    widget_->Close();
     folder_header_view_.reset();  // Release apps grid view before models.
     delegate_.reset();
     views::ViewsTestBase::TearDown();
@@ -90,6 +101,7 @@
   std::unique_ptr<AppListTestModel> model_;
   std::unique_ptr<FolderHeaderView> folder_header_view_;
   std::unique_ptr<TestFolderHeaderViewDelegate> delegate_;
+  std::unique_ptr<views::Widget> widget_;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(FolderHeaderViewTest);
@@ -107,6 +119,20 @@
   EXPECT_EQ("test folder", delegate_->folder_name());
 }
 
+TEST_F(FolderHeaderViewTest, WhitespaceCollapsedWhenFolderNameViewLosesFocus) {
+  AppListFolderItem* folder_item = model_->CreateAndPopulateFolderWithApps(2);
+  folder_header_view_->SetFolderItem(folder_item);
+  views::View* name_view = folder_header_view_->GetFolderNameViewForTest();
+
+  name_view->RequestFocus();
+  UpdateFolderName("  N     A  ");
+  widget_->GetFocusManager()->ClearFocus();
+
+  // Expect that the folder name contains the same string with collapsed
+  // whitespace.
+  EXPECT_EQ("N A", delegate_->folder_name());
+}
+
 TEST_F(FolderHeaderViewTest, MaxFoldernNameLength) {
   // Creating a folder with empty folder name.
   AppListFolderItem* folder_item = model_->CreateAndPopulateFolderWithApps(2);
diff --git a/ui/events/blink/input_handler_proxy.cc b/ui/events/blink/input_handler_proxy.cc
index b5d3aaf..946facc 100644
--- a/ui/events/blink/input_handler_proxy.cc
+++ b/ui/events/blink/input_handler_proxy.cc
@@ -709,6 +709,9 @@
                            "InputHandlerProxy::handle_input gesture scroll",
                            TRACE_EVENT_SCOPE_THREAD);
       gesture_scroll_on_impl_thread_ = true;
+      if (input_handler_->IsCurrentlyScrollingViewport())
+        client_->DidStartScrollingViewport();
+
       if (scroll_status.bubble)
         result = DID_HANDLE_SHOULD_BUBBLE;
       else
@@ -830,8 +833,9 @@
 
 InputHandlerProxy::EventDisposition InputHandlerProxy::HandleGestureFlingStart(
     const WebGestureEvent& gesture_event) {
-  // Touchpad flings are handled on browser.
-  DCHECK(!(gesture_event.SourceDevice() == blink::kWebGestureDeviceTouchpad));
+  // Touchpad and touchscreen flings are handled on browser.
+  DCHECK_NE(blink::kWebGestureDeviceTouchpad, gesture_event.SourceDevice());
+  DCHECK_NE(blink::kWebGestureDeviceTouchscreen, gesture_event.SourceDevice());
 #ifndef NDEBUG
   expect_scroll_update_end_ = false;
 #endif
@@ -844,7 +848,6 @@
   scroll_status.main_thread_scrolling_reasons =
       cc::MainThreadScrollingReason::kNotScrollingOnMain;
   switch (gesture_event.SourceDevice()) {
-    case blink::kWebGestureDeviceTouchscreen:
     case blink::kWebGestureDeviceSyntheticAutoscroll:
       if (!gesture_scroll_on_impl_thread_) {
         scroll_status.thread = cc::InputHandler::SCROLL_ON_MAIN_THREAD;
@@ -854,6 +857,7 @@
         scroll_status = input_handler_->FlingScrollBegin();
       }
       break;
+    case blink::kWebGestureDeviceTouchscreen:
     case blink::kWebGestureDeviceTouchpad:
     case blink::kWebGestureDeviceUninitialized:
     case blink::kWebGestureDeviceCount:
@@ -1285,7 +1289,6 @@
   bool did_scroll = false;
 
   switch (fling_parameters_.source_device) {
-    case blink::kWebGestureDeviceTouchscreen:
     case blink::kWebGestureDeviceSyntheticAutoscroll: {
       clipped_increment = ToClientScrollIncrement(clipped_increment);
       cc::ScrollStateData scroll_state_data;
@@ -1300,6 +1303,7 @@
       HandleOverscroll(fling_parameters_.point, scroll_result, false);
       did_scroll = scroll_result.did_scroll;
     } break;
+    case blink::kWebGestureDeviceTouchscreen:
     case blink::kWebGestureDeviceTouchpad:
     case blink::kWebGestureDeviceUninitialized:
     case blink::kWebGestureDeviceCount:
@@ -1345,10 +1349,10 @@
     const WebGestureEvent& fling_start_event,
     const gfx::Vector2dF& velocity) {
   DCHECK_EQ(WebInputEvent::kGestureFlingStart, fling_start_event.GetType());
-  // When wheel scroll latching is enabled touchpad flings are handled on
-  // browser.
-  DCHECK(fling_start_event.SourceDevice() != blink::kWebGestureDeviceTouchpad ||
-         !touchpad_and_wheel_scroll_latching_enabled_);
+  // Flings with touchpad and touchscreen source devices are handled on browser.
+  DCHECK(fling_start_event.SourceDevice() != blink::kWebGestureDeviceTouchpad &&
+         fling_start_event.SourceDevice() !=
+             blink::kWebGestureDeviceTouchscreen);
   current_fling_velocity_ = velocity;
   fling_curve_ = client_->CreateFlingAnimationCurve(
       fling_start_event.SourceDevice(),
diff --git a/ui/events/blink/input_handler_proxy_client.h b/ui/events/blink/input_handler_proxy_client.h
index 3d992cd12..d6d44c93 100644
--- a/ui/events/blink/input_handler_proxy_client.h
+++ b/ui/events/blink/input_handler_proxy_client.h
@@ -49,6 +49,8 @@
 
   virtual void DidAnimateForInput() = 0;
 
+  virtual void DidStartScrollingViewport() = 0;
+
   // Used to send a GSB to the main thread when the wheel scroll latching is
   // enabled and the scrolling should switch to the main thread.
   virtual void GenerateScrollBeginAndSendToMainThread(
diff --git a/ui/events/blink/input_handler_proxy_unittest.cc b/ui/events/blink/input_handler_proxy_unittest.cc
index 3e5a074f..ba19984 100644
--- a/ui/events/blink/input_handler_proxy_unittest.cc
+++ b/ui/events/blink/input_handler_proxy_unittest.cc
@@ -100,15 +100,6 @@
   return fling;
 }
 
-WebGestureEvent CreateFling(WebGestureDevice source_device,
-                            WebFloatPoint velocity,
-                            WebFloatPoint point,
-                            WebFloatPoint global_point,
-                            int modifiers) {
-  return CreateFling(base::TimeTicks(), source_device, velocity, point,
-                     global_point, modifiers);
-}
-
 WebScopedInputEvent CreateGestureScrollFlingPinch(
     WebInputEvent::Type type,
     WebGestureDevice source_device,
@@ -290,6 +281,7 @@
                     const cc::OverscrollBehavior& overscroll_behavior));
   void DidStopFlinging() override {}
   void DidAnimateForInput() override {}
+  void DidStartScrollingViewport() override {}
   MOCK_METHOD3(SetWhiteListedTouchAction,
                void(cc::TouchAction touch_action,
                     uint32_t unique_touch_event_id,
@@ -1028,279 +1020,8 @@
   ScrollHandlingSwitchedToMainThread();
 }
 
-TEST_P(InputHandlerProxyTest, GestureFlingStartedTouchscreen) {
-  // We shouldn't send any events to the widget for this gesture.
-  expected_disposition_ = InputHandlerProxy::DID_HANDLE;
-  VERIFY_AND_RESET_MOCKS();
-
-  EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
-      .WillOnce(testing::Return(kImplThreadScrollState));
-  gesture_.SetType(WebInputEvent::kGestureScrollBegin);
-  gesture_.SetSourceDevice(blink::kWebGestureDeviceTouchscreen);
-  EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
-
-  VERIFY_AND_RESET_MOCKS();
-
-  EXPECT_CALL(mock_input_handler_, FlingScrollBegin())
-      .WillOnce(testing::Return(kImplThreadScrollState));
-  EXPECT_SET_NEEDS_ANIMATE_INPUT(1);
-
-  gesture_.SetType(WebInputEvent::kGestureFlingStart);
-  gesture_.data.fling_start.velocity_x = 10;
-  EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
-
-  VERIFY_AND_RESET_MOCKS();
-
-  EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_, false));
-
-  // Verify that a GestureFlingCancel during an animation cancels it.
-  gesture_.SetType(WebInputEvent::kGestureFlingCancel);
-  gesture_.SetSourceDevice(blink::kWebGestureDeviceTouchscreen);
-  EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
-
-  VERIFY_AND_RESET_MOCKS();
-}
-
-TEST_P(InputHandlerProxyTest, GestureFlingOnMainThreadTouchscreen) {
-  // We should send all events to the widget for this gesture.
-  expected_disposition_ = InputHandlerProxy::DID_NOT_HANDLE;
-  VERIFY_AND_RESET_MOCKS();
-
-  EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
-      .WillOnce(testing::Return(kMainThreadScrollState));
-
-  gesture_.SetType(WebInputEvent::kGestureScrollBegin);
-  EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
-
-  VERIFY_AND_RESET_MOCKS();
-
-  EXPECT_CALL(mock_input_handler_, FlingScrollBegin()).Times(0);
-
-  gesture_.SetType(WebInputEvent::kGestureFlingStart);
-  gesture_.SetSourceDevice(blink::kWebGestureDeviceTouchscreen);
-  EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
-
-  VERIFY_AND_RESET_MOCKS();
-
-  // Even if we didn't start a fling ourselves, we still need to send the cancel
-  // event to the widget.
-  gesture_.SetType(WebInputEvent::kGestureFlingCancel);
-  gesture_.SetSourceDevice(blink::kWebGestureDeviceTouchscreen);
-  EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
-}
-
-TEST_P(InputHandlerProxyTest, GestureFlingIgnoredTouchscreen) {
-  expected_disposition_ = InputHandlerProxy::DID_HANDLE;
-  VERIFY_AND_RESET_MOCKS();
-
-  EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
-      .WillOnce(testing::Return(kImplThreadScrollState));
-
-  gesture_.SetType(WebInputEvent::kGestureScrollBegin);
-  gesture_.SetSourceDevice(blink::kWebGestureDeviceTouchscreen);
-  EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
-
-  expected_disposition_ = InputHandlerProxy::DROP_EVENT;
-  VERIFY_AND_RESET_MOCKS();
-
-  // Flings ignored by the InputHandler should be dropped, signalling the end
-  // of the touch scroll sequence.
-  EXPECT_CALL(mock_input_handler_, FlingScrollBegin())
-      .WillOnce(testing::Return(kScrollIgnoredScrollState));
-
-  gesture_.SetType(WebInputEvent::kGestureFlingStart);
-  gesture_.SetSourceDevice(blink::kWebGestureDeviceTouchscreen);
-  EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
-
-  VERIFY_AND_RESET_MOCKS();
-
-  // Subsequent scrolls should behave normally, even without an intervening
-  // GestureFlingCancel, as the original GestureFlingStart was dropped.
-  expected_disposition_ = InputHandlerProxy::DID_HANDLE;
-  EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
-      .WillOnce(testing::Return(kImplThreadScrollState));
-  gesture_.SetType(WebInputEvent::kGestureScrollBegin);
-  gesture_.SetSourceDevice(blink::kWebGestureDeviceTouchscreen);
-  EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
-
-  VERIFY_AND_RESET_MOCKS();
-}
-
-TEST_P(InputHandlerProxyTest, GestureFlingAnimatesTouchscreen) {
-  // We shouldn't send any events to the widget for this gesture.
-  expected_disposition_ = InputHandlerProxy::DID_HANDLE;
-  VERIFY_AND_RESET_MOCKS();
-
-  EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
-      .WillOnce(testing::Return(kImplThreadScrollState));
-
-  gesture_.SetType(WebInputEvent::kGestureScrollBegin);
-  gesture_.SetSourceDevice(blink::kWebGestureDeviceTouchscreen);
-  EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
-
-  VERIFY_AND_RESET_MOCKS();
-
-  // On the fling start, we should schedule an animation but not actually start
-  // scrolling.
-  WebFloatPoint fling_delta = WebFloatPoint(100, 0);
-  WebFloatPoint fling_point = WebFloatPoint(7, 13);
-  WebFloatPoint fling_global_point = WebFloatPoint(17, 23);
-  // Note that for touchscreen the control modifier is not special.
-  int modifiers = WebInputEvent::kControlKey;
-  gesture_ = CreateFling(blink::kWebGestureDeviceTouchscreen, fling_delta,
-                         fling_point, fling_global_point, modifiers);
-  EXPECT_SET_NEEDS_ANIMATE_INPUT(1);
-  EXPECT_CALL(mock_input_handler_, FlingScrollBegin())
-      .WillOnce(testing::Return(kImplThreadScrollState));
-  EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
-
-  VERIFY_AND_RESET_MOCKS();
-  // The first animate call should let us pick up an animation start time, but
-  // we shouldn't actually move anywhere just yet. The first frame after the
-  // fling start will typically include the last scroll from the gesture that
-  // lead to the scroll (either wheel or gesture scroll), so there should be no
-  // visible hitch.
-  EXPECT_SET_NEEDS_ANIMATE_INPUT(1);
-  base::TimeTicks time = base::TimeTicks() + base::TimeDelta::FromSeconds(10);
-  Animate(time);
-
-  VERIFY_AND_RESET_MOCKS();
-
-  // The second call should start scrolling in the -X direction.
-  EXPECT_SET_NEEDS_ANIMATE_INPUT(1);
-  EXPECT_CALL(
-      mock_input_handler_,
-      ScrollBy(testing::Property(&cc::ScrollState::delta_x, testing::Lt(0))))
-      .WillOnce(testing::Return(scroll_result_did_scroll_));
-  time += base::TimeDelta::FromMilliseconds(100);
-  Animate(time);
-
-  VERIFY_AND_RESET_MOCKS();
-
-  EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_, false));
-  gesture_.SetType(WebInputEvent::kGestureFlingCancel);
-  EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
-
-  VERIFY_AND_RESET_MOCKS();
-}
-
-TEST_P(InputHandlerProxyTest, GestureFlingWithValidTimestamp) {
-  // We shouldn't send any events to the widget for this gesture.
-  expected_disposition_ = InputHandlerProxy::DID_HANDLE;
-  VERIFY_AND_RESET_MOCKS();
-
-  EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
-      .WillOnce(testing::Return(kImplThreadScrollState));
-
-  gesture_.SetType(WebInputEvent::kGestureScrollBegin);
-  gesture_.SetSourceDevice(blink::kWebGestureDeviceTouchscreen);
-  EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
-
-  VERIFY_AND_RESET_MOCKS();
-
-  // On the fling start, we should schedule an animation but not actually start
-  // scrolling.
-  base::TimeDelta dt = base::TimeDelta::FromMilliseconds(10);
-  base::TimeTicks time = base::TimeTicks() + dt;
-  WebFloatPoint fling_delta = WebFloatPoint(100, 0);
-  WebFloatPoint fling_point = WebFloatPoint(7, 13);
-  WebFloatPoint fling_global_point = WebFloatPoint(17, 23);
-  int modifiers = WebInputEvent::kControlKey;
-  gesture_ = CreateFling(time, blink::kWebGestureDeviceTouchscreen, fling_delta,
-                         fling_point, fling_global_point, modifiers);
-  EXPECT_SET_NEEDS_ANIMATE_INPUT(1);
-  EXPECT_CALL(mock_input_handler_, FlingScrollBegin())
-      .WillOnce(testing::Return(kImplThreadScrollState));
-  EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
-
-  VERIFY_AND_RESET_MOCKS();
-  // With a valid time stamp, the first animate call should skip start time
-  // initialization and immediately begin scroll update production. This reduces
-  // the likelihood of a hitch between the scroll preceding the fling and
-  // the first scroll generated by the fling.
-  // Scrolling should start in the -X direction.
-  EXPECT_SET_NEEDS_ANIMATE_INPUT(1);
-  EXPECT_CALL(
-      mock_input_handler_,
-      ScrollBy(testing::Property(&cc::ScrollState::delta_x, testing::Lt(0))))
-      .WillOnce(testing::Return(scroll_result_did_scroll_));
-  time += dt;
-  Animate(time);
-
-  VERIFY_AND_RESET_MOCKS();
-
-  EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_, false));
-  gesture_.SetType(WebInputEvent::kGestureFlingCancel);
-  EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
-
-  VERIFY_AND_RESET_MOCKS();
-}
-
-TEST_P(InputHandlerProxyTest, GestureFlingWithInvalidTimestamp) {
-  // We shouldn't send any events to the widget for this gesture.
-  expected_disposition_ = InputHandlerProxy::DID_HANDLE;
-  VERIFY_AND_RESET_MOCKS();
-
-  EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
-      .WillOnce(testing::Return(kImplThreadScrollState));
-
-  gesture_.SetType(WebInputEvent::kGestureScrollBegin);
-  gesture_.SetSourceDevice(blink::kWebGestureDeviceTouchscreen);
-  EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
-
-  VERIFY_AND_RESET_MOCKS();
-
-  // On the fling start, we should schedule an animation but not actually start
-  // scrolling.
-  base::TimeDelta start_time_offset = base::TimeDelta::FromMilliseconds(10);
-  gesture_ = WebGestureEvent(
-      WebInputEvent::kGestureFlingStart, WebInputEvent::kControlKey,
-      start_time_offset.InSecondsF(), blink::kWebGestureDeviceTouchscreen);
-  WebFloatPoint fling_delta = WebFloatPoint(100, 0);
-  WebFloatPoint fling_point = WebFloatPoint(7, 13);
-  WebFloatPoint fling_global_point = WebFloatPoint(17, 23);
-  int modifiers = WebInputEvent::kControlKey;
-  gesture_.SetTimeStampSeconds(start_time_offset.InSecondsF());
-  gesture_.data.fling_start.velocity_x = fling_delta.x;
-  gesture_.data.fling_start.velocity_y = fling_delta.y;
-  gesture_.SetPositionInWidget(fling_point);
-  gesture_.SetPositionInScreen(fling_global_point);
-  gesture_.SetModifiers(modifiers);
-  EXPECT_SET_NEEDS_ANIMATE_INPUT(1);
-  EXPECT_CALL(mock_input_handler_, FlingScrollBegin())
-      .WillOnce(testing::Return(kImplThreadScrollState));
-  EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
-
-  VERIFY_AND_RESET_MOCKS();
-  // Event though a time stamp was provided for the fling event, it will be
-  // ignored as its too far in the past relative to the first animate call's
-  // timestamp.
-  EXPECT_SET_NEEDS_ANIMATE_INPUT(1);
-  base::TimeTicks time =
-      base::TimeTicks() + start_time_offset + base::TimeDelta::FromSeconds(1);
-  Animate(time);
-
-  VERIFY_AND_RESET_MOCKS();
-
-  // Further animation ticks should update the fling as usual.
-  EXPECT_SET_NEEDS_ANIMATE_INPUT(1);
-  EXPECT_CALL(
-      mock_input_handler_,
-      ScrollBy(testing::Property(&cc::ScrollState::delta_x, testing::Lt(0))))
-      .WillOnce(testing::Return(scroll_result_did_scroll_));
-  time += base::TimeDelta::FromMilliseconds(10);
-  Animate(time);
-
-  VERIFY_AND_RESET_MOCKS();
-
-  EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_, false));
-  gesture_.SetType(WebInputEvent::kGestureFlingCancel);
-  EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
-
-  VERIFY_AND_RESET_MOCKS();
-}
-
-TEST_P(InputHandlerProxyTest, GestureScrollOnImplThreadFlagClearedAfterFling) {
+TEST_P(InputHandlerProxyTest,
+       GestureScrollOnImplThreadFlagClearedAfterScrollEnd) {
   // We shouldn't send any events to the widget for this gesture.
   expected_disposition_ = InputHandlerProxy::DID_HANDLE;
   VERIFY_AND_RESET_MOCKS();
@@ -1315,56 +1036,15 @@
   // |gesture_scroll_on_impl_thread_| should be true.
   EXPECT_TRUE(input_handler_->gesture_scroll_on_impl_thread_for_testing());
 
-  expected_disposition_ = InputHandlerProxy::DID_HANDLE;
   VERIFY_AND_RESET_MOCKS();
 
-  // On the fling start, we should schedule an animation but not actually start
-  // scrolling.
-  WebFloatPoint fling_delta = WebFloatPoint(100, 0);
-  WebFloatPoint fling_point = WebFloatPoint(7, 13);
-  WebFloatPoint fling_global_point = WebFloatPoint(17, 23);
-  int modifiers = WebInputEvent::kControlKey | WebInputEvent::kAltKey;
-  gesture_ = CreateFling(blink::kWebGestureDeviceTouchscreen, fling_delta,
-                         fling_point, fling_global_point, modifiers);
-  EXPECT_SET_NEEDS_ANIMATE_INPUT(1);
-  EXPECT_CALL(mock_input_handler_, FlingScrollBegin())
-      .WillOnce(testing::Return(kImplThreadScrollState));
+  EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_, true));
+  gesture_.SetType(WebInputEvent::kGestureScrollEnd);
   EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
 
-  // |gesture_scroll_on_impl_thread_| should still be true after
-  // a GestureFlingStart is sent.
-  EXPECT_TRUE(input_handler_->gesture_scroll_on_impl_thread_for_testing());
-
-  VERIFY_AND_RESET_MOCKS();
-  // The first animate call should let us pick up an animation start time, but
-  // we shouldn't actually move anywhere just yet. The first frame after the
-  // fling start will typically include the last scroll from the gesture that
-  // lead to the scroll (either wheel or gesture scroll), so there should be no
-  // visible hitch.
-  EXPECT_SET_NEEDS_ANIMATE_INPUT(1);
-  base::TimeTicks time = base::TimeTicks() + base::TimeDelta::FromSeconds(10);
-  Animate(time);
-
-  VERIFY_AND_RESET_MOCKS();
-
-  // The second call should start scrolling in the -X direction.
-  EXPECT_SET_NEEDS_ANIMATE_INPUT(1);
-  EXPECT_CALL(
-      mock_input_handler_,
-      ScrollBy(testing::Property(&cc::ScrollState::delta_x, testing::Lt(0))))
-      .WillOnce(testing::Return(scroll_result_did_scroll_));
-  time += base::TimeDelta::FromMilliseconds(100);
-  Animate(time);
-
-  VERIFY_AND_RESET_MOCKS();
-
-  EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_, false));
-  gesture_.SetType(WebInputEvent::kGestureFlingCancel);
-  EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
-
-  // |gesture_scroll_on_impl_thread_| should be false once
-  // the fling has finished (note no GestureScrollEnd has been sent).
-  EXPECT_TRUE(!input_handler_->gesture_scroll_on_impl_thread_for_testing());
+  // |gesture_scroll_on_impl_thread_| should be false once a GestureScrollEnd
+  // gets handled.
+  EXPECT_FALSE(input_handler_->gesture_scroll_on_impl_thread_for_testing());
 
   VERIFY_AND_RESET_MOCKS();
 }
@@ -1387,290 +1067,6 @@
 
   expected_disposition_ = InputHandlerProxy::DID_HANDLE;
   VERIFY_AND_RESET_MOCKS();
-
-  // On the fling start, we should schedule an animation but not actually start
-  // scrolling.
-  WebFloatPoint fling_delta = WebFloatPoint(100, 0);
-  WebFloatPoint fling_point = WebFloatPoint(7, 13);
-  WebFloatPoint fling_global_point = WebFloatPoint(17, 23);
-  int modifiers = WebInputEvent::kControlKey | WebInputEvent::kAltKey;
-  gesture_ = CreateFling(blink::kWebGestureDeviceTouchscreen, fling_delta,
-                         fling_point, fling_global_point, modifiers);
-  EXPECT_SET_NEEDS_ANIMATE_INPUT(1);
-  EXPECT_CALL(mock_input_handler_, FlingScrollBegin())
-      .WillOnce(testing::Return(kImplThreadScrollState));
-  EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
-
-  // |gesture_scroll_on_impl_thread_| should still be true after
-  // a GestureFlingStart is sent.
-  EXPECT_TRUE(input_handler_->gesture_scroll_on_impl_thread_for_testing());
-
-  VERIFY_AND_RESET_MOCKS();
-
-  // gesture_scroll_on_impl_thread_ is still true when this scroll begins. As a
-  // result, this scroll begin will cancel the previous fling.
-  EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_, false));
-  EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
-      .WillOnce(testing::Return(kImplThreadScrollState));
-
-  gesture_.SetType(WebInputEvent::kGestureScrollBegin);
-  EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
-
-  // After sending a GestureScrollBegin, the member variable
-  // |gesture_scroll_on_impl_thread_| should be true.
-  EXPECT_TRUE(input_handler_->gesture_scroll_on_impl_thread_for_testing());
-  VERIFY_AND_RESET_MOCKS();
-}
-
-TEST_P(InputHandlerProxyTest, GestureFlingStopsAtContentEdgeTouchscreen) {
-  gesture_.SetSourceDevice(blink::kWebGestureDeviceTouchscreen);
-  // We shouldn't send any events to the widget for this gesture.
-  expected_disposition_ = InputHandlerProxy::DID_HANDLE;
-  VERIFY_AND_RESET_MOCKS();
-
-  EXPECT_CALL(mock_input_handler_, ScrollBegin(::testing::_, ::testing::_))
-      .WillOnce(testing::Return(kImplThreadScrollState));
-
-  // HandleGestureScrollBegin will set gesture_scroll_on_impl_thread_.
-  gesture_.SetType(WebInputEvent::kGestureScrollBegin);
-  EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
-  EXPECT_TRUE(input_handler_->gesture_scroll_on_impl_thread_for_testing());
-
-  VERIFY_AND_RESET_MOCKS();
-
-  EXPECT_CALL(mock_input_handler_, FlingScrollBegin())
-      .WillOnce(testing::Return(kImplThreadScrollState));
-
-  // On the fling start, we should schedule an animation but not actually start
-  // scrolling.
-  gesture_.SetType(WebInputEvent::kGestureFlingStart);
-  WebFloatPoint fling_delta = WebFloatPoint(100, 100);
-  gesture_.data.fling_start.velocity_x = fling_delta.x;
-  gesture_.data.fling_start.velocity_y = fling_delta.y;
-  EXPECT_SET_NEEDS_ANIMATE_INPUT(1);
-  EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
-  VERIFY_AND_RESET_MOCKS();
-
-  // The first animate doesn't cause any scrolling.
-  EXPECT_SET_NEEDS_ANIMATE_INPUT(1);
-  base::TimeTicks time = base::TimeTicks() + base::TimeDelta::FromSeconds(10);
-  Animate(time);
-  VERIFY_AND_RESET_MOCKS();
-
-  // The second animate starts scrolling in the positive X and Y directions.
-  EXPECT_CALL(
-      mock_input_handler_,
-      ScrollBy(testing::Property(&cc::ScrollState::delta_y, testing::Lt(0))))
-      .WillOnce(testing::Return(scroll_result_did_scroll_));
-  EXPECT_SET_NEEDS_ANIMATE_INPUT(1);
-  time += base::TimeDelta::FromMilliseconds(100);
-  Animate(time);
-  VERIFY_AND_RESET_MOCKS();
-
-  // The third animate overscrolls in the positive Y direction but scrolls
-  // somewhat.
-  cc::InputHandlerScrollResult overscroll;
-  overscroll.did_scroll = true;
-  overscroll.did_overscroll_root = true;
-  overscroll.accumulated_root_overscroll = gfx::Vector2dF(0, 100);
-  overscroll.unused_scroll_delta = gfx::Vector2dF(0, 10);
-  EXPECT_CALL(
-      mock_input_handler_,
-      ScrollBy(testing::Property(&cc::ScrollState::delta_y, testing::Lt(0))))
-      .WillOnce(testing::Return(overscroll));
-  EXPECT_CALL(
-      mock_client_,
-      DidOverscroll(overscroll.accumulated_root_overscroll,
-                    overscroll.unused_scroll_delta,
-                    testing::Property(&gfx::Vector2dF::y, testing::Lt(0)),
-                    testing::_, overscroll.overscroll_behavior));
-  EXPECT_SET_NEEDS_ANIMATE_INPUT(1);
-  time += base::TimeDelta::FromMilliseconds(100);
-  Animate(time);
-  VERIFY_AND_RESET_MOCKS();
-
-  // The next call to animate will no longer scroll vertically.
-  EXPECT_SET_NEEDS_ANIMATE_INPUT(1);
-  EXPECT_CALL(
-      mock_input_handler_,
-      ScrollBy(testing::Property(&cc::ScrollState::delta_y, testing::Eq(0))))
-      .WillOnce(testing::Return(scroll_result_did_scroll_));
-  time += base::TimeDelta::FromMilliseconds(100);
-  Animate(time);
-  VERIFY_AND_RESET_MOCKS();
-}
-
-TEST_P(InputHandlerProxyTest, GestureFlingNotCancelledBySmallTimeDelta) {
-  // We shouldn't send any events to the widget for this gesture.
-  expected_disposition_ = InputHandlerProxy::DID_HANDLE;
-  VERIFY_AND_RESET_MOCKS();
-
-  EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
-      .WillOnce(testing::Return(kImplThreadScrollState));
-
-  gesture_.SetType(WebInputEvent::kGestureScrollBegin);
-  gesture_.SetSourceDevice(blink::kWebGestureDeviceTouchscreen);
-  EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
-
-  VERIFY_AND_RESET_MOCKS();
-
-  // On the fling start, we should schedule an animation but not actually start
-  // scrolling.
-  base::TimeDelta dt = base::TimeDelta::FromMilliseconds(10);
-  base::TimeTicks time = base::TimeTicks() + dt;
-  WebFloatPoint fling_delta = WebFloatPoint(100, 0);
-  WebFloatPoint fling_point = WebFloatPoint(7, 13);
-  WebFloatPoint fling_global_point = WebFloatPoint(17, 23);
-  int modifiers = WebInputEvent::kControlKey;
-  gesture_ = CreateFling(time, blink::kWebGestureDeviceTouchscreen, fling_delta,
-                         fling_point, fling_global_point, modifiers);
-  EXPECT_SET_NEEDS_ANIMATE_INPUT(1);
-  EXPECT_CALL(mock_input_handler_, FlingScrollBegin())
-      .WillOnce(testing::Return(kImplThreadScrollState));
-  EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
-
-  VERIFY_AND_RESET_MOCKS();
-  // With an animation timestamp equivalent to the starting timestamp, the
-  // animation will simply be rescheduled.
-  EXPECT_SET_NEEDS_ANIMATE_INPUT(1);
-  Animate(time);
-
-  VERIFY_AND_RESET_MOCKS();
-  EXPECT_TRUE(input_handler_->gesture_scroll_on_impl_thread_for_testing());
-
-  // A small time delta should not stop the fling, even if the client
-  // reports no scrolling.
-  EXPECT_SET_NEEDS_ANIMATE_INPUT(1);
-  EXPECT_CALL(
-      mock_input_handler_,
-      ScrollBy(testing::Property(&cc::ScrollState::delta_x, testing::Lt(0))))
-      .WillOnce(testing::Return(scroll_result_did_not_scroll_));
-  time += base::TimeDelta::FromMicroseconds(5);
-  Animate(time);
-
-  VERIFY_AND_RESET_MOCKS();
-  EXPECT_TRUE(input_handler_->gesture_scroll_on_impl_thread_for_testing());
-
-  // A time delta of zero should not stop the fling, and neither should it
-  // trigger scrolling on the client.
-  EXPECT_SET_NEEDS_ANIMATE_INPUT(1);
-  Animate(time);
-
-  VERIFY_AND_RESET_MOCKS();
-  EXPECT_TRUE(input_handler_->gesture_scroll_on_impl_thread_for_testing());
-
-  // Lack of movement on the client, with a non-trivial scroll delta, should
-  // terminate the fling.
-  EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_, false));
-  EXPECT_CALL(
-      mock_input_handler_,
-      ScrollBy(testing::Property(&cc::ScrollState::delta_x, testing::Lt(1))))
-      .WillOnce(testing::Return(scroll_result_did_not_scroll_));
-  time += base::TimeDelta::FromMilliseconds(100);
-  Animate(time);
-
-  VERIFY_AND_RESET_MOCKS();
-  EXPECT_FALSE(input_handler_->gesture_scroll_on_impl_thread_for_testing());
-}
-
-TEST_P(InputHandlerProxyTest, GestureFlingCancelledAfterBothAxesStopScrolling) {
-  cc::InputHandlerScrollResult overscroll;
-  overscroll.did_scroll = true;
-  overscroll.did_overscroll_root = true;
-
-  // We shouldn't send any events to the widget for this gesture.
-  expected_disposition_ = InputHandlerProxy::DID_HANDLE;
-  VERIFY_AND_RESET_MOCKS();
-
-  EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
-      .WillOnce(testing::Return(kImplThreadScrollState));
-  gesture_.SetType(WebInputEvent::kGestureScrollBegin);
-  gesture_.SetSourceDevice(blink::kWebGestureDeviceTouchscreen);
-  EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
-  VERIFY_AND_RESET_MOCKS();
-
-  // On the fling start, we should schedule an animation but not actually start
-  // scrolling.
-  gesture_.SetType(WebInputEvent::kGestureFlingStart);
-  WebFloatPoint fling_delta = WebFloatPoint(100, 100);
-  gesture_.data.fling_start.velocity_x = fling_delta.x;
-  gesture_.data.fling_start.velocity_y = fling_delta.y;
-  EXPECT_CALL(mock_input_handler_, FlingScrollBegin())
-      .WillOnce(testing::Return(kImplThreadScrollState));
-  EXPECT_SET_NEEDS_ANIMATE_INPUT(1);
-  EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
-  VERIFY_AND_RESET_MOCKS();
-
-  // The first animate doesn't cause any scrolling.
-  EXPECT_SET_NEEDS_ANIMATE_INPUT(1);
-  base::TimeTicks time = base::TimeTicks() + base::TimeDelta::FromSeconds(10);
-  Animate(time);
-  VERIFY_AND_RESET_MOCKS();
-
-  // The second animate starts scrolling in the positive X and Y directions.
-  EXPECT_SET_NEEDS_ANIMATE_INPUT(1);
-  EXPECT_CALL(
-      mock_input_handler_,
-      ScrollBy(testing::Property(&cc::ScrollState::delta_y, testing::Lt(0))))
-      .WillOnce(testing::Return(scroll_result_did_scroll_));
-  time += base::TimeDelta::FromMilliseconds(10);
-  Animate(time);
-  VERIFY_AND_RESET_MOCKS();
-
-  // The third animate hits the bottom content edge.
-  overscroll.accumulated_root_overscroll = gfx::Vector2dF(0, 100);
-  overscroll.unused_scroll_delta = gfx::Vector2dF(0, 100);
-  EXPECT_CALL(
-      mock_input_handler_,
-      ScrollBy(testing::Property(&cc::ScrollState::delta_y, testing::Lt(0))))
-      .WillOnce(testing::Return(overscroll));
-  EXPECT_CALL(
-      mock_client_,
-      DidOverscroll(overscroll.accumulated_root_overscroll,
-                    overscroll.unused_scroll_delta,
-                    testing::Property(&gfx::Vector2dF::y, testing::Lt(0)),
-                    testing::_, overscroll.overscroll_behavior));
-  EXPECT_SET_NEEDS_ANIMATE_INPUT(1);
-  time += base::TimeDelta::FromMilliseconds(10);
-  Animate(time);
-  VERIFY_AND_RESET_MOCKS();
-
-  // The next call to animate will no longer scroll vertically.
-  EXPECT_SET_NEEDS_ANIMATE_INPUT(1);
-  EXPECT_CALL(
-      mock_input_handler_,
-      ScrollBy(testing::Property(&cc::ScrollState::delta_y, testing::Eq(0))))
-      .WillOnce(testing::Return(scroll_result_did_scroll_));
-  time += base::TimeDelta::FromMilliseconds(10);
-  Animate(time);
-  VERIFY_AND_RESET_MOCKS();
-
-  // The next call will hit the right edge.
-  overscroll.accumulated_root_overscroll = gfx::Vector2dF(100, 100);
-  overscroll.unused_scroll_delta = gfx::Vector2dF(100, 0);
-  EXPECT_CALL(
-      mock_input_handler_,
-      ScrollBy(testing::Property(&cc::ScrollState::delta_x, testing::Lt(0))))
-      .WillOnce(testing::Return(overscroll));
-  EXPECT_CALL(
-      mock_client_,
-      DidOverscroll(overscroll.accumulated_root_overscroll,
-                    overscroll.unused_scroll_delta,
-                    testing::Property(&gfx::Vector2dF::x, testing::Lt(0)),
-                    testing::_, overscroll.overscroll_behavior));
-  EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_, false));
-  time += base::TimeDelta::FromMilliseconds(10);
-  Animate(time);
-  VERIFY_AND_RESET_MOCKS();
-
-  // The next call to animate will no longer scroll horizontally or vertically,
-  // and the fling should be cancelled.
-  EXPECT_SET_NEEDS_ANIMATE_INPUT(0);
-  EXPECT_CALL(mock_input_handler_, ScrollBy(testing::_)).Times(0);
-  time += base::TimeDelta::FromMilliseconds(10);
-  Animate(time);
-  VERIFY_AND_RESET_MOCKS();
-  EXPECT_FALSE(input_handler_->gesture_scroll_on_impl_thread_for_testing());
 }
 
 TEST_P(InputHandlerProxyTest, HitTestTouchEventNonNullTouchAction) {
@@ -1978,620 +1374,6 @@
   VERIFY_AND_RESET_MOCKS();
 }
 
-TEST_P(InputHandlerProxyTest, GestureFlingCancelledByKeyboardEvent) {
-  // We shouldn't send any events to the widget for this gesture.
-  VERIFY_AND_RESET_MOCKS();
-
-  EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
-      .WillOnce(testing::Return(kImplThreadScrollState));
-  gesture_.SetType(WebInputEvent::kGestureScrollBegin);
-  gesture_.SetSourceDevice(blink::kWebGestureDeviceTouchscreen);
-  EXPECT_EQ(InputHandlerProxy::DID_HANDLE,
-            input_handler_->HandleInputEvent(gesture_));
-  EXPECT_TRUE(input_handler_->gesture_scroll_on_impl_thread_for_testing());
-  VERIFY_AND_RESET_MOCKS();
-
-  // Keyboard events received during a scroll should have no effect.
-  WebKeyboardEvent key_event(WebInputEvent::kKeyDown,
-                             WebInputEvent::kNoModifiers,
-                             WebInputEvent::GetStaticTimeStampForTests());
-  EXPECT_EQ(InputHandlerProxy::DID_NOT_HANDLE,
-            input_handler_->HandleInputEvent(key_event));
-  EXPECT_TRUE(input_handler_->gesture_scroll_on_impl_thread_for_testing());
-  VERIFY_AND_RESET_MOCKS();
-
-  // On the fling start, animation should be scheduled, but no scrolling occurs.
-  gesture_.SetType(WebInputEvent::kGestureFlingStart);
-  WebFloatPoint fling_delta = WebFloatPoint(100, 100);
-  gesture_.data.fling_start.velocity_x = fling_delta.x;
-  gesture_.data.fling_start.velocity_y = fling_delta.y;
-  EXPECT_CALL(mock_input_handler_, FlingScrollBegin())
-      .WillOnce(testing::Return(kImplThreadScrollState));
-  EXPECT_SET_NEEDS_ANIMATE_INPUT(1);
-  EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
-  EXPECT_TRUE(input_handler_->gesture_scroll_on_impl_thread_for_testing());
-  VERIFY_AND_RESET_MOCKS();
-
-  // Keyboard events received during a fling should cancel the active fling.
-  EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_, false));
-  EXPECT_EQ(InputHandlerProxy::DID_NOT_HANDLE,
-            input_handler_->HandleInputEvent(key_event));
-  EXPECT_FALSE(input_handler_->gesture_scroll_on_impl_thread_for_testing());
-  VERIFY_AND_RESET_MOCKS();
-
-  // The call to animate should have no effect, as the fling was cancelled.
-  base::TimeTicks time = base::TimeTicks() + base::TimeDelta::FromSeconds(10);
-  Animate(time);
-  VERIFY_AND_RESET_MOCKS();
-
-  // A fling cancel should be dropped, as there is nothing to cancel.
-  gesture_.SetType(WebInputEvent::kGestureFlingCancel);
-  EXPECT_EQ(InputHandlerProxy::DROP_EVENT,
-            input_handler_->HandleInputEvent(gesture_));
-  EXPECT_FALSE(input_handler_->gesture_scroll_on_impl_thread_for_testing());
-}
-
-TEST_P(InputHandlerProxyTest, GestureFlingCancelledByWheelEvent) {
-  // We shouldn't send any events to the widget for this gesture.
-  expected_disposition_ = InputHandlerProxy::DID_HANDLE;
-  VERIFY_AND_RESET_MOCKS();
-
-  EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
-      .WillOnce(testing::Return(kImplThreadScrollState));
-
-  gesture_.SetType(WebInputEvent::kGestureScrollBegin);
-  gesture_.SetSourceDevice(blink::kWebGestureDeviceTouchscreen);
-  EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
-  EXPECT_TRUE(input_handler_->gesture_scroll_on_impl_thread_for_testing());
-  VERIFY_AND_RESET_MOCKS();
-
-  // Wheel events received during a scroll shouldn't cancel the fling, but will
-  // cause scrolling.
-  cc::InputHandlerScrollResult result;
-
-  EXPECT_CALL(mock_input_handler_,
-              GetEventListenerProperties(cc::EventListenerClass::kMouseWheel))
-      .WillOnce(testing::Return(cc::EventListenerProperties::kBlocking));
-
-  WebMouseWheelEvent wheel_event(WebInputEvent::kMouseWheel,
-                                 WebInputEvent::kNoModifiers,
-                                 WebInputEvent::GetStaticTimeStampForTests());
-  input_handler_->HandleInputEvent(wheel_event);
-  EXPECT_TRUE(input_handler_->gesture_scroll_on_impl_thread_for_testing());
-  VERIFY_AND_RESET_MOCKS();
-
-  // On the fling start, animation should be scheduled, but no scrolling occurs.
-  gesture_.SetType(WebInputEvent::kGestureFlingStart);
-  WebFloatPoint fling_delta = WebFloatPoint(100, 100);
-  gesture_.data.fling_start.velocity_x = fling_delta.x;
-  gesture_.data.fling_start.velocity_y = fling_delta.y;
-  EXPECT_CALL(mock_input_handler_, FlingScrollBegin())
-      .WillOnce(testing::Return(kImplThreadScrollState));
-  EXPECT_SET_NEEDS_ANIMATE_INPUT(1);
-  EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
-  EXPECT_TRUE(input_handler_->gesture_scroll_on_impl_thread_for_testing());
-  VERIFY_AND_RESET_MOCKS();
-
-  // Wheel events received during a fling should cancel the active fling, and
-  // cause a scroll.
-  EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_, false));
-
-  EXPECT_CALL(mock_input_handler_,
-              GetEventListenerProperties(cc::EventListenerClass::kMouseWheel))
-      .WillOnce(testing::Return(cc::EventListenerProperties::kBlocking));
-
-  input_handler_->HandleInputEvent(wheel_event);
-  EXPECT_FALSE(input_handler_->gesture_scroll_on_impl_thread_for_testing());
-  VERIFY_AND_RESET_MOCKS();
-
-  // The call to animate should have no effect, as the fling was cancelled.
-  base::TimeTicks time = base::TimeTicks() + base::TimeDelta::FromSeconds(10);
-  Animate(time);
-  VERIFY_AND_RESET_MOCKS();
-
-  // A fling cancel should be dropped, as there is nothing to cancel.
-  gesture_.SetType(WebInputEvent::kGestureFlingCancel);
-  EXPECT_EQ(InputHandlerProxy::DROP_EVENT,
-            input_handler_->HandleInputEvent(gesture_));
-  EXPECT_FALSE(input_handler_->gesture_scroll_on_impl_thread_for_testing());
-}
-
-TEST_P(InputHandlerProxyTest, GestureFlingWithNegativeTimeDelta) {
-  // We shouldn't send any events to the widget for this gesture.
-  expected_disposition_ = InputHandlerProxy::DID_HANDLE;
-  VERIFY_AND_RESET_MOCKS();
-
-  EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
-      .WillOnce(testing::Return(kImplThreadScrollState));
-
-  gesture_.SetType(WebInputEvent::kGestureScrollBegin);
-  gesture_.SetSourceDevice(blink::kWebGestureDeviceTouchscreen);
-  EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
-
-  VERIFY_AND_RESET_MOCKS();
-
-  // On the fling start, we should schedule an animation but not actually start
-  // scrolling.
-  base::TimeDelta dt = base::TimeDelta::FromMilliseconds(10);
-  base::TimeTicks time = base::TimeTicks() + dt;
-  WebFloatPoint fling_delta = WebFloatPoint(100, 0);
-  WebFloatPoint fling_point = WebFloatPoint(7, 13);
-  WebFloatPoint fling_global_point = WebFloatPoint(17, 23);
-  int modifiers = WebInputEvent::kControlKey;
-  gesture_ = CreateFling(time, blink::kWebGestureDeviceTouchscreen, fling_delta,
-                         fling_point, fling_global_point, modifiers);
-  EXPECT_SET_NEEDS_ANIMATE_INPUT(1);
-  EXPECT_CALL(mock_input_handler_, FlingScrollBegin())
-      .WillOnce(testing::Return(kImplThreadScrollState));
-  EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
-
-  VERIFY_AND_RESET_MOCKS();
-
-  // If we get a negative time delta, that is, the Animation tick time happens
-  // before the fling's start time then we should *not* try scrolling and
-  // instead reset the fling start time.
-  EXPECT_SET_NEEDS_ANIMATE_INPUT(1);
-  EXPECT_CALL(mock_input_handler_, ScrollBy(testing::_)).Times(0);
-  time -= base::TimeDelta::FromMilliseconds(5);
-  Animate(time);
-
-  VERIFY_AND_RESET_MOCKS();
-
-  // The first call should have reset the start time so subsequent calls should
-  // generate scroll events.
-  EXPECT_SET_NEEDS_ANIMATE_INPUT(1);
-  EXPECT_CALL(
-      mock_input_handler_,
-      ScrollBy(testing::Property(&cc::ScrollState::delta_x, testing::Lt(0))))
-      .WillOnce(testing::Return(scroll_result_did_scroll_));
-
-  Animate(time + base::TimeDelta::FromMilliseconds(1));
-
-  VERIFY_AND_RESET_MOCKS();
-
-  EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_, false));
-  gesture_.SetType(WebInputEvent::kGestureFlingCancel);
-  EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
-
-  VERIFY_AND_RESET_MOCKS();
-}
-
-TEST_P(InputHandlerProxyTest, FlingBoost) {
-  base::TimeDelta dt = base::TimeDelta::FromMilliseconds(10);
-  base::TimeTicks time = base::TimeTicks() + dt;
-  base::TimeTicks last_animate_time = time;
-  WebFloatPoint fling_delta = WebFloatPoint(1000, 0);
-  WebFloatPoint fling_point = WebFloatPoint(7, 13);
-  StartFling(time, blink::kWebGestureDeviceTouchscreen, fling_delta,
-             fling_point);
-
-  // Now cancel the fling.  The fling cancellation should be deferred to allow
-  // fling boosting events to arrive.
-  time += dt;
-  CancelFling(time);
-
-  // The GestureScrollBegin should be swallowed by the fling if a fling cancel
-  // is deferred.
-  time += dt;
-  gesture_.SetTimeStampSeconds(InSecondsF(time));
-  gesture_.SetType(WebInputEvent::kGestureScrollBegin);
-  EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
-
-  VERIFY_AND_RESET_MOCKS();
-
-  // Animate calls within the deferred cancellation window should continue.
-  time += dt;
-  float expected_delta =
-      (time - last_animate_time).InSecondsF() * -fling_delta.x;
-  EXPECT_SET_NEEDS_ANIMATE_INPUT(1);
-  EXPECT_CALL(mock_input_handler_,
-              ScrollBy(testing::Property(&cc::ScrollState::delta_x,
-                                         testing::Eq(expected_delta))))
-      .WillOnce(testing::Return(scroll_result_did_scroll_));
-  Animate(time);
-  last_animate_time = time;
-
-  VERIFY_AND_RESET_MOCKS();
-
-  // GestureScrollUpdates in the same direction and at sufficient speed should
-  // be swallowed by the fling.
-  time += dt;
-  gesture_.SetTimeStampSeconds(InSecondsF(time));
-  gesture_.SetType(WebInputEvent::kGestureScrollUpdate);
-  gesture_.data.scroll_update.delta_x = fling_delta.x;
-  EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
-
-  VERIFY_AND_RESET_MOCKS();
-
-  // Animate calls within the deferred cancellation window should continue.
-  time += dt;
-  expected_delta = (time - last_animate_time).InSecondsF() * -fling_delta.x;
-  EXPECT_SET_NEEDS_ANIMATE_INPUT(1);
-  EXPECT_CALL(mock_input_handler_,
-              ScrollBy(testing::Property(&cc::ScrollState::delta_x,
-                                         testing::Eq(expected_delta))))
-      .WillOnce(testing::Return(scroll_result_did_scroll_));
-  Animate(time);
-  last_animate_time = time;
-
-  VERIFY_AND_RESET_MOCKS();
-
-  // GestureFlingStart in the same direction and at sufficient speed should
-  // boost the active fling.
-
-  gesture_ = CreateFling(time, blink::kWebGestureDeviceTouchscreen, fling_delta,
-                         fling_point, fling_point, 0);
-  EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
-  VERIFY_AND_RESET_MOCKS();
-
-  time += dt;
-  // Note we get *2x* as much delta because 2 flings have combined.
-  expected_delta = 2 * (time - last_animate_time).InSecondsF() * -fling_delta.x;
-  EXPECT_SET_NEEDS_ANIMATE_INPUT(1);
-  EXPECT_CALL(mock_input_handler_,
-              ScrollBy(testing::Property(&cc::ScrollState::delta_x,
-                                         testing::Eq(expected_delta))))
-      .WillOnce(testing::Return(scroll_result_did_scroll_));
-  Animate(time);
-  last_animate_time = time;
-
-  VERIFY_AND_RESET_MOCKS();
-
-  // Repeated GestureFlingStarts should accumulate.
-
-  CancelFling(time);
-  gesture_ = CreateFling(time, blink::kWebGestureDeviceTouchscreen, fling_delta,
-                         fling_point, fling_point, 0);
-  EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
-  VERIFY_AND_RESET_MOCKS();
-
-  time += dt;
-  // Note we get *3x* as much delta because 3 flings have combined.
-  expected_delta = 3 * (time - last_animate_time).InSecondsF() * -fling_delta.x;
-  EXPECT_SET_NEEDS_ANIMATE_INPUT(1);
-  EXPECT_CALL(mock_input_handler_,
-              ScrollBy(testing::Property(&cc::ScrollState::delta_x,
-                                         testing::Eq(expected_delta))))
-      .WillOnce(testing::Return(scroll_result_did_scroll_));
-  Animate(time);
-  last_animate_time = time;
-
-  VERIFY_AND_RESET_MOCKS();
-
-  // GestureFlingCancel should terminate the fling if no boosting gestures are
-  // received within the timeout window.
-
-  time += dt;
-  gesture_.SetTimeStampSeconds(InSecondsF(time));
-  gesture_.SetType(WebInputEvent::kGestureFlingCancel);
-  EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
-
-  VERIFY_AND_RESET_MOCKS();
-
-  time += base::TimeDelta::FromMilliseconds(100);
-  EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_, false));
-  Animate(time);
-
-  VERIFY_AND_RESET_MOCKS();
-}
-
-TEST_P(InputHandlerProxyTest, NoFlingBoostIfScrollDelayed) {
-  base::TimeDelta dt = base::TimeDelta::FromMilliseconds(10);
-  base::TimeTicks time = base::TimeTicks() + dt;
-  WebFloatPoint fling_delta = WebFloatPoint(1000, 0);
-  WebFloatPoint fling_point = WebFloatPoint(7, 13);
-  StartFling(time, blink::kWebGestureDeviceTouchscreen, fling_delta,
-             fling_point);
-
-  // Cancel the fling.  The fling cancellation should be deferred to allow
-  // fling boosting events to arrive.
-  time += dt;
-  CancelFling(time);
-
-  // The GestureScrollBegin should be swallowed by the fling if a fling cancel
-  // is deferred.
-  time += dt;
-  gesture_.SetTimeStampSeconds(InSecondsF(time));
-  gesture_.SetType(WebInputEvent::kGestureScrollBegin);
-  EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
-
-  VERIFY_AND_RESET_MOCKS();
-
-  // If no GestureScrollUpdate or GestureFlingStart is received within the
-  // timeout window, the fling should be cancelled and scrolling should resume.
-  time += base::TimeDelta::FromMilliseconds(100);
-  EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_, false));
-  EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
-      .WillOnce(testing::Return(kImplThreadScrollState));
-  Animate(time);
-
-  VERIFY_AND_RESET_MOCKS();
-}
-
-TEST_P(InputHandlerProxyTest, NoFlingBoostIfNotAnimated) {
-  base::TimeDelta dt = base::TimeDelta::FromMilliseconds(10);
-  base::TimeTicks time = base::TimeTicks() + dt;
-  WebFloatPoint fling_delta = WebFloatPoint(1000, 0);
-  WebFloatPoint fling_point = WebFloatPoint(7, 13);
-  StartFling(time, blink::kWebGestureDeviceTouchscreen, fling_delta,
-             fling_point);
-
-  // Animate fling once.
-  time += dt;
-  EXPECT_CALL(mock_input_handler_, ScrollBy(testing::_))
-      .WillOnce(testing::Return(scroll_result_did_scroll_));
-  EXPECT_SET_NEEDS_ANIMATE_INPUT(1);
-  Animate(time);
-
-  // Cancel the fling after long delay of no animate. The fling cancellation
-  // should be deferred to allow fling boosting events to arrive.
-  time += base::TimeDelta::FromMilliseconds(100);
-  CancelFling(time);
-
-  // The GestureScrollBegin should be swallowed by the fling if a fling cancel
-  // is deferred.
-  time += dt;
-  gesture_.SetTimeStampSeconds(InSecondsF(time));
-  gesture_.SetType(WebInputEvent::kGestureScrollBegin);
-  EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
-
-  VERIFY_AND_RESET_MOCKS();
-
-  // Should exit scroll bosting on GestureScrollUpdate due to long delay
-  // since last animate. Cancel old fling and start new scroll.
-  gesture_.SetType(WebInputEvent::kGestureScrollUpdate);
-  gesture_.data.scroll_update.delta_y = -40;
-  EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_, false));
-  EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
-      .WillOnce(testing::Return(kImplThreadScrollState));
-  EXPECT_CALL(mock_input_handler_, ScrollBy(testing::_))
-      .WillOnce(testing::Return(scroll_result_did_scroll_));
-  EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
-
-  VERIFY_AND_RESET_MOCKS();
-}
-
-TEST_P(InputHandlerProxyTest, NoFlingBoostIfFlingInDifferentDirection) {
-  base::TimeDelta dt = base::TimeDelta::FromMilliseconds(10);
-  base::TimeTicks time = base::TimeTicks() + dt;
-  WebFloatPoint fling_delta = WebFloatPoint(1000, 0);
-  WebFloatPoint fling_point = WebFloatPoint(7, 13);
-  StartFling(time, blink::kWebGestureDeviceTouchscreen, fling_delta,
-             fling_point);
-
-  // Cancel the fling.  The fling cancellation should be deferred to allow
-  // fling boosting events to arrive.
-  time += dt;
-  CancelFling(time);
-
-  // If the new fling is orthogonal to the existing fling, no boosting should
-  // take place, with the new fling replacing the old.
-  WebFloatPoint orthogonal_fling_delta =
-      WebFloatPoint(fling_delta.y, -fling_delta.x);
-  gesture_ = CreateFling(time, blink::kWebGestureDeviceTouchscreen,
-                         orthogonal_fling_delta, fling_point, fling_point, 0);
-  EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
-
-  VERIFY_AND_RESET_MOCKS();
-
-  // Note that the new fling delta uses the orthogonal, unboosted fling
-  // velocity.
-  time += dt;
-  float expected_delta = dt.InSecondsF() * -orthogonal_fling_delta.y;
-  EXPECT_SET_NEEDS_ANIMATE_INPUT(1);
-  EXPECT_CALL(mock_input_handler_,
-              ScrollBy(testing::Property(&cc::ScrollState::delta_y,
-                                         testing::Eq(expected_delta))))
-      .WillOnce(testing::Return(scroll_result_did_scroll_));
-  Animate(time);
-
-  VERIFY_AND_RESET_MOCKS();
-}
-
-TEST_P(InputHandlerProxyTest, NoFlingBoostIfScrollInDifferentDirection) {
-  base::TimeDelta dt = base::TimeDelta::FromMilliseconds(10);
-  base::TimeTicks time = base::TimeTicks() + dt;
-  WebFloatPoint fling_delta = WebFloatPoint(1000, 0);
-  WebFloatPoint fling_point = WebFloatPoint(7, 13);
-  StartFling(time, blink::kWebGestureDeviceTouchscreen, fling_delta,
-             fling_point);
-
-  // Cancel the fling.  The fling cancellation should be deferred to allow
-  // fling boosting events to arrive.
-  time += dt;
-  CancelFling(time);
-
-  // The GestureScrollBegin should be swallowed by the fling if a fling cancel
-  // is deferred.
-  time += dt;
-  gesture_.SetTimeStampSeconds(InSecondsF(time));
-  gesture_.SetType(WebInputEvent::kGestureScrollBegin);
-  EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
-
-  VERIFY_AND_RESET_MOCKS();
-
-  // If the GestureScrollUpdate is in a different direction than the fling,
-  // the fling should be cancelled and scrolling should resume.
-  time += dt;
-  gesture_.SetTimeStampSeconds(InSecondsF(time));
-  gesture_.SetType(WebInputEvent::kGestureScrollUpdate);
-  gesture_.data.scroll_update.delta_x = -fling_delta.x;
-  EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_, false));
-  EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
-      .WillOnce(testing::Return(kImplThreadScrollState));
-  EXPECT_CALL(mock_input_handler_,
-              ScrollBy(testing::Property(&cc::ScrollState::delta_x,
-                                         testing::Eq(fling_delta.x))))
-      .WillOnce(testing::Return(scroll_result_did_scroll_));
-  EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
-
-  VERIFY_AND_RESET_MOCKS();
-}
-
-TEST_P(InputHandlerProxyTest, NoFlingBoostIfFlingTooSlow) {
-  base::TimeDelta dt = base::TimeDelta::FromMilliseconds(10);
-  base::TimeTicks time = base::TimeTicks() + dt;
-  WebFloatPoint fling_delta = WebFloatPoint(1000, 0);
-  WebFloatPoint fling_point = WebFloatPoint(7, 13);
-  StartFling(time, blink::kWebGestureDeviceTouchscreen, fling_delta,
-             fling_point);
-
-  // Cancel the fling.  The fling cancellation should be deferred to allow
-  // fling boosting events to arrive.
-  time += dt;
-  CancelFling(time);
-
-  // If the new fling is too slow, no boosting should take place, with the new
-  // fling replacing the old.
-  WebFloatPoint small_fling_delta = WebFloatPoint(100, 0);
-  gesture_ = CreateFling(time, blink::kWebGestureDeviceTouchscreen,
-                         small_fling_delta, fling_point, fling_point, 0);
-  EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
-
-  VERIFY_AND_RESET_MOCKS();
-
-  // Note that the new fling delta uses the *slow*, unboosted fling velocity.
-  time += dt;
-  float expected_delta = dt.InSecondsF() * -small_fling_delta.x;
-  EXPECT_SET_NEEDS_ANIMATE_INPUT(1);
-  EXPECT_CALL(mock_input_handler_,
-              ScrollBy(testing::Property(&cc::ScrollState::delta_x,
-                                         testing::Eq(expected_delta))))
-      .WillOnce(testing::Return(scroll_result_did_scroll_));
-  Animate(time);
-
-  VERIFY_AND_RESET_MOCKS();
-}
-
-TEST_P(InputHandlerProxyTest, NoFlingBoostIfPreventBoostingFlagIsSet) {
-  base::TimeDelta dt = base::TimeDelta::FromMilliseconds(10);
-  base::TimeTicks time = base::TimeTicks() + dt;
-  WebFloatPoint fling_delta = WebFloatPoint(1000, 0);
-  WebFloatPoint fling_point = WebFloatPoint(7, 13);
-
-  StartFling(time, blink::kWebGestureDeviceTouchscreen, fling_delta,
-             fling_point);
-
-  EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_, false));
-
-  // Cancel the fling. The fling cancellation should not be deferred because of
-  // prevent boosting flag set.
-  gesture_.data.fling_cancel.prevent_boosting = true;
-  time += dt;
-  CancelFling(time);
-
-  // VERIFY_AND_RESET_MOCKS already called by CancelFling
-}
-
-TEST_P(InputHandlerProxyTest, FlingBoostTerminatedDuringScrollSequence) {
-  base::TimeDelta dt = base::TimeDelta::FromMilliseconds(10);
-  base::TimeTicks time = base::TimeTicks() + dt;
-  base::TimeTicks last_animate_time = time;
-  WebFloatPoint fling_delta = WebFloatPoint(1000, 0);
-  WebFloatPoint fling_point = WebFloatPoint(7, 13);
-  StartFling(time, blink::kWebGestureDeviceTouchscreen, fling_delta,
-             fling_point);
-
-  // Now cancel the fling.  The fling cancellation should be deferred to allow
-  // fling boosting events to arrive.
-  time += dt;
-  CancelFling(time);
-
-  // The GestureScrollBegin should be swallowed by the fling.
-  time += dt;
-  gesture_.SetTimeStampSeconds(InSecondsF(time));
-  gesture_.SetType(WebInputEvent::kGestureScrollBegin);
-  EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
-
-  VERIFY_AND_RESET_MOCKS();
-
-  // Now animate the fling to completion (in this case, the fling should
-  // terminate because the input handler reports a failed scroll). As the fling
-  // was cancelled during an active scroll sequence, a synthetic
-  // GestureScrollBegin should be processed, resuming the scroll.
-  time += dt;
-  float expected_delta =
-      (time - last_animate_time).InSecondsF() * -fling_delta.x;
-  EXPECT_CALL(mock_input_handler_,
-              ScrollBy(testing::Property(&cc::ScrollState::delta_x,
-                                         testing::Eq(expected_delta))))
-      .WillOnce(testing::Return(scroll_result_did_not_scroll_));
-  EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_, false));
-  EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
-      .WillOnce(testing::Return(kImplThreadScrollState));
-  Animate(time);
-
-  VERIFY_AND_RESET_MOCKS();
-
-  // Subsequent GestureScrollUpdates after the cancelled, boosted fling should
-  // cause scrolling as usual.
-  time += dt;
-  expected_delta = 7.3f;
-  gesture_.SetTimeStampSeconds(InSecondsF(time));
-  gesture_.SetType(WebInputEvent::kGestureScrollUpdate);
-  gesture_.data.scroll_update.delta_x = -expected_delta;
-  EXPECT_CALL(mock_input_handler_,
-              ScrollBy(testing::Property(&cc::ScrollState::delta_x,
-                                         testing::Eq(expected_delta))))
-      .WillOnce(testing::Return(scroll_result_did_scroll_));
-  EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
-
-  VERIFY_AND_RESET_MOCKS();
-
-  // GestureScrollEnd should terminate the resumed scroll properly.
-  time += dt;
-  gesture_.SetTimeStampSeconds(InSecondsF(time));
-  gesture_.SetType(WebInputEvent::kGestureScrollEnd);
-  EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_, true));
-  EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
-
-  VERIFY_AND_RESET_MOCKS();
-}
-
-TEST_P(InputHandlerProxyTest, DidReceiveInputEvent_ForFlingTouchscreen) {
-  gesture_.SetSourceDevice(blink::kWebGestureDeviceTouchscreen);
-  testing::StrictMock<MockInputHandlerProxyClientWithDidAnimateForInput>
-      mock_client;
-  input_handler_.reset(
-      new TestInputHandlerProxy(&mock_input_handler_, &mock_client,
-                                touchpad_and_wheel_scroll_latching_enabled_,
-                                async_wheel_events_enabled_));
-  if (install_synchronous_handler_) {
-    EXPECT_CALL(mock_input_handler_, RequestUpdateForSynchronousInputHandler())
-        .Times(1);
-    input_handler_->SetOnlySynchronouslyAnimateRootFlings(
-        &mock_synchronous_input_handler_);
-  }
-  mock_input_handler_.set_is_scrolling_root(synchronous_root_scroll_);
-
-  // A GSB must be sent before a GFS.
-  EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
-      .WillOnce(testing::Return(kImplThreadScrollState));
-  gesture_.SetType(WebInputEvent::kGestureScrollBegin);
-  gesture_.SetSourceDevice(blink::kWebGestureDeviceTouchscreen);
-  EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
-
-  VERIFY_AND_RESET_MOCKS();
-
-  gesture_.SetType(WebInputEvent::kGestureFlingStart);
-  WebFloatPoint fling_delta = WebFloatPoint(100, 100);
-  gesture_.data.fling_start.velocity_x = fling_delta.x;
-  gesture_.data.fling_start.velocity_y = fling_delta.y;
-  EXPECT_SET_NEEDS_ANIMATE_INPUT(1);
-  EXPECT_CALL(mock_input_handler_, FlingScrollBegin())
-      .WillOnce(testing::Return(kImplThreadScrollState));
-  EXPECT_EQ(InputHandlerProxy::DID_HANDLE,
-            input_handler_->HandleInputEvent(gesture_));
-  VERIFY_AND_RESET_MOCKS();
-
-  EXPECT_SET_NEEDS_ANIMATE_INPUT(1);
-  EXPECT_CALL(mock_client, DidAnimateForInput());
-  base::TimeTicks time = base::TimeTicks() + base::TimeDelta::FromSeconds(10);
-  Animate(time);
-
-  VERIFY_AND_RESET_MOCKS();
-}
-
 TEST(SynchronousInputHandlerProxyTest, StartupShutdown) {
   testing::StrictMock<MockInputHandler> mock_input_handler;
   testing::StrictMock<MockInputHandlerProxyClient> mock_client;
@@ -3181,95 +1963,6 @@
   testing::Mock::VerifyAndClearExpectations(&mock_input_handler_);
 }
 
-TEST_P(InputHandlerProxyEventQueueTest, GestureScrollFlingOrder) {
-  // Handle scroll on compositor.
-  cc::InputHandlerScrollResult scroll_result_did_scroll_;
-  scroll_result_did_scroll_.did_scroll = true;
-
-  EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
-      .WillRepeatedly(testing::Return(kImplThreadScrollState));
-  EXPECT_CALL(mock_input_handler_, SetNeedsAnimateInput())
-      .Times(::testing::AtLeast(1));
-  EXPECT_CALL(
-      mock_input_handler_,
-      ScrollBy(testing::Property(&cc::ScrollState::delta_y, testing::Gt(0))))
-      .WillRepeatedly(testing::Return(scroll_result_did_scroll_));
-  EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_, false))
-      .Times(::testing::AtLeast(1));
-  EXPECT_CALL(mock_input_handler_, FlingScrollBegin())
-      .WillOnce(testing::Return(kImplThreadScrollState));
-
-  // Simulate scroll.
-  HandleGestureEvent(WebInputEvent::kGestureScrollBegin);
-  HandleGestureEvent(WebInputEvent::kGestureScrollUpdate, -20);
-  HandleGestureEvent(WebInputEvent::kGestureScrollUpdate, -30);
-  HandleGestureEvent(WebInputEvent::kGestureFlingStart, -10);
-
-  // ScrollUpdate and FlingStart should be queued.
-  EXPECT_EQ(2ul, event_queue().size());
-  EXPECT_EQ(1ul, event_disposition_recorder_.size());
-  EXPECT_EQ(WebInputEvent::kGestureScrollUpdate,
-            event_queue()[0]->event().GetType());
-  EXPECT_EQ(WebInputEvent::kGestureFlingStart,
-            event_queue()[1]->event().GetType());
-
-  // Dispatch events.
-  input_handler_proxy_->DeliverInputForBeginFrame();
-  EXPECT_EQ(0ul, event_queue().size());
-  EXPECT_EQ(4ul, event_disposition_recorder_.size());
-  EXPECT_TRUE(
-      input_handler_proxy_->gesture_scroll_on_impl_thread_for_testing());
-
-  // Send FlingCancel to stop scrolling.
-  HandleGestureEvent(WebInputEvent::kGestureFlingCancel);
-  EXPECT_EQ(1ul, event_queue().size());
-  EXPECT_EQ(WebInputEvent::kGestureFlingCancel,
-            event_queue()[0]->event().GetType());
-  input_handler_proxy_->DeliverInputForBeginFrame();
-  EXPECT_EQ(0ul, event_queue().size());
-  EXPECT_EQ(5ul, event_disposition_recorder_.size());
-  // Should stop scrolling. Note that no ScrollEnd was sent.
-  EXPECT_TRUE(
-      !input_handler_proxy_->gesture_scroll_on_impl_thread_for_testing());
-}
-
-TEST_P(InputHandlerProxyEventQueueTest, GestureScrollAfterFling) {
-  // Handle scroll on compositor.
-  cc::InputHandlerScrollResult scroll_result_did_scroll_;
-  scroll_result_did_scroll_.did_scroll = true;
-
-  EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
-      .WillRepeatedly(testing::Return(kImplThreadScrollState));
-  EXPECT_CALL(mock_input_handler_, SetNeedsAnimateInput())
-      .Times(::testing::AtLeast(1));
-  EXPECT_CALL(
-      mock_input_handler_,
-      ScrollBy(testing::Property(&cc::ScrollState::delta_y, testing::Gt(0))))
-      .WillRepeatedly(testing::Return(scroll_result_did_scroll_));
-  EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_, false))
-      .Times(::testing::AtLeast(1));
-  EXPECT_CALL(mock_input_handler_, FlingScrollBegin())
-      .WillOnce(testing::Return(kImplThreadScrollState));
-
-  // Simulate fling.
-  HandleGestureEvent(WebInputEvent::kGestureScrollBegin);
-  HandleGestureEvent(WebInputEvent::kGestureScrollUpdate, -20);
-  HandleGestureEvent(WebInputEvent::kGestureFlingStart, -10);
-  HandleGestureEvent(WebInputEvent::kGestureFlingCancel);
-
-  // Dispatch events.
-  input_handler_proxy_->DeliverInputForBeginFrame();
-  EXPECT_EQ(0ul, event_queue().size());
-  EXPECT_EQ(4ul, event_disposition_recorder_.size());
-  EXPECT_FALSE(
-      input_handler_proxy_->gesture_scroll_on_impl_thread_for_testing());
-
-  // New ScrollBegin should be dispatched immediately as there is no on-going
-  // scroll, fling or pinch.
-  HandleGestureEvent(WebInputEvent::kGestureScrollBegin);
-  EXPECT_EQ(0ul, event_queue().size());
-}
-
 TEST_P(InputHandlerProxyEventQueueTest, TouchpadGestureScrollEndFlushQueue) {
   // Handle scroll on compositor.
   cc::InputHandlerScrollResult scroll_result_did_scroll_;
diff --git a/ui/latency/BUILD.gn b/ui/latency/BUILD.gn
index b755496..093ad755 100644
--- a/ui/latency/BUILD.gn
+++ b/ui/latency/BUILD.gn
@@ -9,6 +9,8 @@
   sources = [
     "fixed_point.cc",
     "fixed_point.h",
+    "histograms.cc",
+    "histograms.h",
     "latency_histogram_macros.h",
     "latency_info.cc",
     "latency_info.h",
@@ -40,6 +42,9 @@
 test("latency_unittests") {
   sources = [
     "fixed_point_unittest.cc",
+    "histograms_test_common.cc",
+    "histograms_test_common.h",
+    "histograms_unittest.cc",
     "latency_info_unittest.cc",
   ]
 
@@ -66,3 +71,21 @@
     ]
   }
 }
+
+test("latency_perftests") {
+  sources = [
+    "histograms_perftest.cc",
+    "histograms_test_common.cc",
+    "histograms_test_common.h",
+  ]
+
+  deps = [
+    ":latency",
+    "//base",
+    "//base/test:test_support",
+    "//mojo/edk/test:run_all_unittests",
+    "//testing/gmock",
+    "//testing/gtest",
+    "//testing/perf",
+  ]
+}
diff --git a/ui/latency/histograms.cc b/ui/latency/histograms.cc
new file mode 100644
index 0000000..85b3c140
--- /dev/null
+++ b/ui/latency/histograms.cc
@@ -0,0 +1,385 @@
+// 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 "ui/latency/histograms.h"
+
+#include <cmath>
+#include <limits>
+
+#include "base/bits.h"
+#include "base/time/time.h"
+#include "ui/latency/fixed_point.h"
+
+namespace {
+
+// Calculates percentiles in a way that can be shared by different histograms.
+ui::PercentileResults PercentilesHelper(
+    ui::frame_metrics::BoundaryIterator* boundary_iterator,
+    const uint32_t* buckets_begin,
+    const uint32_t* buckets_end,
+    uint64_t total_samples) {
+  ui::PercentileResults result;
+  uint64_t boundary_left = 0;
+  uint64_t boundary_right = boundary_iterator->Next();
+
+  double thresholds[ui::PercentileResults::kCount];
+  for (size_t i = 0; i < ui::PercentileResults::kCount; i++) {
+    thresholds[i] = ui::PercentileResults::kPercentiles[i] * total_samples;
+  }
+
+  uint64_t accumulator = 0;
+  size_t result_index = 0;
+  for (const uint32_t* bucket = buckets_begin; bucket < buckets_end; bucket++) {
+    accumulator += *bucket;
+    // Multiple percentiles might be calculated from the same bucket,
+    // so we use a while loop here.
+    while (accumulator > thresholds[result_index]) {
+      const double overage = accumulator - thresholds[result_index];
+      double b0_fraction = overage / (*bucket);
+      double b1_fraction = 1.0 - b0_fraction;
+
+      // Use a linear interpolation between two buckets.
+      // This assumes the samples are evenly distributed within a bucket.
+      // TODO(brianderson): Consider neighboring bucket sizes and fit to a
+      //   curve. http://crbug.com/821879
+      const double estimate =
+          b0_fraction * boundary_left + b1_fraction * boundary_right;
+      result.values[result_index] = estimate;
+      result_index++;
+      if (result_index >= ui::PercentileResults::kCount)
+        return result;
+    }
+
+    boundary_left = boundary_right;
+    boundary_right = boundary_iterator->Next();
+  }
+
+  NOTREACHED();
+  return result;
+}
+
+}  // namespace
+
+namespace ui {
+
+constexpr double PercentileResults::kPercentiles[];
+constexpr size_t PercentileResults::kCount;
+
+namespace frame_metrics {
+
+constexpr size_t RatioHistogram::kBucketCount;
+constexpr size_t VSyncHistogram::kBucketCount;
+
+// Ratio Histogram.
+// The distribution of each category of buckets in this historam is
+// exponential, however each category is divided into N linear buckets
+// depending on how much precision we want for that category. How much
+// precision a category gets depends on how often we expect that bucket to be
+// used and how important those buckets are.
+//
+// Most of the precision is allocated for values just > 1 since most ratios,
+// when not ~0 will be > 1. And since ratios are likely to be near whole
+// numbers (some multiple of the vsync), we only give it a precision of 1/2.
+// You can think about the stride of each category as the number of vsyncs of
+// precision that category will have.
+//
+// There will be aliasing, but because of the vsync aligned linear division
+// of each category, we won't get a bucket that represents fewer vsyncs than
+// its fprevious bucket.
+//
+// This is in contrast to the default exponential distribution of UMA
+// buckets, which result in a constant precision for each bucket and would
+// allocate lots of very small buckets near 0 where we don't need the
+// precision.
+
+namespace {
+
+constexpr size_t kBucketHalfStrideFirstBucketIndex = 17;
+
+// Within the range [16, 4096), there are 9 categories of buckets that each
+// start with a power of 2. Within a category, successive buckets have a fixed
+// stride. Across categories, the strides increase exponentionally, encoded
+// as powers of 2 in |stride_shift|, which increases linearly.
+struct RatioBucketCategory {
+  uint8_t first_bucket_index;
+  uint8_t stride_shift;
+};
+using RatioCategoryHelper = std::array<RatioBucketCategory, 9>;
+constexpr RatioCategoryHelper kCategories16to4096 = {
+    // first_bucket_index of each row below is the previous one + number of
+    // buckets. Each entry is {first_bucket_index, stride_shift}.
+    {{47, 0},      // [16, 32) stride 1 => 16 buckets.
+     {63, 1},      // [32, 64) stride 2 => 16 buckets.
+     {79, 3},      // [64, 128) stride 8 => 8 buckets.
+     {87, 4},      // [128, 256) stride 16 => 8 buckets.
+     {95, 6},      // [256, 512) stride 64 => 4 buckets
+     {99, 7},      // [512, 1024) stride 128 => 4 buckets.
+     {103, 9},     // [1024, 2048) stride 512 => 2 buckets.
+     {105, 10},    // [2048, 4096) stride 1024 => 2 buckets.
+     {107, 12}}};  // [4096, 8192) stride 4096 => 1 bucket.
+
+// The delegate RatioBoundary::Percentiles will pass to PercentilesHelper.
+struct RatioBoundaryIterator : public BoundaryIterator {
+  ~RatioBoundaryIterator() override = default;
+
+  size_t bucket = 0;
+  uint64_t boundary = 0;
+  RatioCategoryHelper::const_iterator b16to4096 = kCategories16to4096.begin();
+  uint64_t next_boundary_to_change_category =
+      32 * frame_metrics::kFixedPointMultiplier;
+
+  uint64_t Next() override {
+    if (bucket == 0) {
+      // The first bucket is [0, 1).
+      boundary = 1;
+    } else if (bucket < kBucketHalfStrideFirstBucketIndex ||
+               bucket >= kCategories16to4096.back().first_bucket_index) {
+      // The start and end buckets increase in size by powers of 2.
+      boundary *= 2;
+    } else if (bucket < kCategories16to4096.front().first_bucket_index) {
+      // The 30 buckets before 47 have a stride of .5 and represent the
+      // range [1, 16).
+      boundary += (frame_metrics::kFixedPointMultiplier / 2);
+    } else {
+      // The rest of the buckets are defined by kCategories16to4096.
+      DCHECK(b16to4096 < kCategories16to4096.end());
+      boundary +=
+          (frame_metrics::kFixedPointMultiplier << b16to4096->stride_shift);
+      // The category changes for every power of 2.
+      if (boundary >= next_boundary_to_change_category) {
+        next_boundary_to_change_category *= 2;
+        b16to4096++;
+      }
+    }
+
+    bucket++;
+    return boundary;
+  }
+};
+
+}  // namespace
+
+std::unique_ptr<BoundaryIterator> CreateRatioIteratorForTesting() {
+  return std::make_unique<RatioBoundaryIterator>();
+}
+
+RatioHistogram::RatioHistogram() = default;
+RatioHistogram::~RatioHistogram() = default;
+
+void RatioHistogram::AddSample(uint32_t ratio, uint32_t weight) {
+  size_t bucket = 0;
+
+  // Precomputed thresholds for the log base 2 of the ratio that help
+  // determine which category of buckets the sample should go in.
+  constexpr int kLog2HalfStrideStart = kFixedPointShift;
+  constexpr int kLog2Cats16to4096Start = kFixedPointShift + 4;  // 2^4 = 16.
+  constexpr int kLog2_4096Pow2Start = kFixedPointShift + 12;    // 2^12 = 4096.
+
+  if (ratio == 0) {
+    bucket = 0;
+  } else {
+    int log2 = base::bits::Log2Floor(ratio);
+    DCHECK_GE(log2, 0);
+    if (log2 < kLog2HalfStrideStart) {
+      // [2^-16, 1) pow of 2 strides => 16 buckets. (16x1)
+      bucket = 1 + log2;
+    } else if (log2 < kLog2Cats16to4096Start) {
+      // [1, 16) stride 1/2 => 30 buckets. (2 + 4 + 8 + 16)
+      const int first_bucket_index = kBucketHalfStrideFirstBucketIndex;
+      const int category_start = kFixedPointMultiplier;
+      const int total_shift = kFixedPointShift - 1;  // -1 multiplies by 2.
+      const int category_offset = (ratio - category_start) >> total_shift;
+      bucket = first_bucket_index + category_offset;
+    } else if (log2 < kLog2_4096Pow2Start) {
+      // [16, 32) stride 1 => 16 buckets.
+      // [32, 64) stride 2 => 16 buckets.
+      // [64, 128) stride 8 => 8 buckets.
+      // [128, 256) stride 16 => 8 buckets.
+      // [256, 512) stride 64 => 4 buckets.
+      // [512, 1024) stride 128 => 4 buckets.
+      // [1024, 2048) stride 512 => 2 buckets.
+      // [2048, 4096) stride 1024 => 2 buckets.
+      const int category = log2 - kLog2Cats16to4096Start;
+      const int category_start = 1 << log2;
+      const int total_shift =
+          (kFixedPointShift + kCategories16to4096[category].stride_shift);
+      const int category_offset = (ratio - category_start) >> total_shift;
+      bucket =
+          kCategories16to4096[category].first_bucket_index + category_offset;
+    } else {
+      // [4096, 2^16) pow of 2 strides => 4 buckets. (4x1)
+      const int category_offset = log2 - kLog2_4096Pow2Start;
+      bucket = kCategories16to4096.back().first_bucket_index + category_offset;
+    }
+  }
+  DCHECK_LT(bucket, kBucketCount);
+
+  // Verify overflow isn't an issue.
+  DCHECK_LT(weight, std::numeric_limits<BucketArray::value_type>::max() -
+                        buckets_[bucket]);
+  DCHECK_LT(weight, std::numeric_limits<decltype(total_samples_)>::max() -
+                        total_samples_);
+
+  buckets_[bucket] += weight;
+  total_samples_ += weight;
+}
+
+PercentileResults RatioHistogram::CalculatePercentiles() const {
+  RatioBoundaryIterator i;
+  return PercentilesHelper(&i, buckets_.data(),
+                           buckets_.data() + buckets_.size(), total_samples_);
+}
+
+void RatioHistogram::Reset() {
+  total_samples_ = 0;
+  buckets_.fill(0);
+}
+
+// VSyncHistogram.
+namespace {
+
+// The number of buckets in bucket categories 1 through 6.
+constexpr std::array<uint8_t, 6> kVSyncBucketCounts = {{12, 16, 16, 16, 31, 6}};
+
+// Some constants used to convert values to bucket categories.
+constexpr size_t kVSync1stBucketC0 = 0;
+constexpr size_t kVSync1stBucketC1 = kVSync1stBucketC0 + 1;
+constexpr size_t kVSync1stBucketC2 = kVSync1stBucketC1 + kVSyncBucketCounts[0];
+constexpr size_t kVSync1stBucketC3 = kVSync1stBucketC2 + kVSyncBucketCounts[1];
+constexpr size_t kVSync1stBucketC4 = kVSync1stBucketC3 + kVSyncBucketCounts[2];
+constexpr size_t kVSync1stBucketC5 = kVSync1stBucketC4 + kVSyncBucketCounts[3];
+constexpr size_t kVSync1stBucketC6 = kVSync1stBucketC5 + kVSyncBucketCounts[4];
+constexpr size_t kVSyncBucketCountC6 = kVSyncBucketCounts[5];
+
+// This iterates through the microsecond VSync boundaries.
+struct VSyncBoundaryIterator : public BoundaryIterator {
+  ~VSyncBoundaryIterator() override = default;
+
+  uint8_t category_ = 0;
+  uint8_t sub_bucket_ = 0;
+
+  uint64_t Next() override {
+    uint32_t boundary = 0;
+    switch (category_) {
+      case 0:  // Powers of two from 1 to 2048 us @ 50% precision
+        boundary = 1 << sub_bucket_;
+        break;
+      case 1:    // Every 8 Hz from 256 Hz to 128 Hz @ 3-6% precision
+      case 2:    // Every 4 Hz from 128 Hz to  64 Hz @ 3-6% precision
+      case 3:    // Every 2 Hz from  64 Hz to  32 Hz @ 3-6% precision
+      case 4: {  // Every 1 Hz from  32 Hz to   1 Hz @ 3-33% precision
+        int hz_start = 256 >> (category_ - 1);
+        int hz_stride = 8 >> (category_ - 1);
+        int hz = hz_start - hz_stride * sub_bucket_;
+        boundary = (base::TimeTicks::kMicrosecondsPerSecond + (hz / 2)) / hz;
+        break;
+      }
+      case 5:  // Powers of two from 1s to 32s @ 50% precision
+        boundary =
+            static_cast<uint32_t>(base::TimeTicks::kMicrosecondsPerSecond) *
+            (1 << sub_bucket_);
+        break;
+      case 6:  // The last boundary of 64s.
+        // Advancing would result in out-of-bounds access of
+        // kVSyncBucketCounts, so just return.
+        return 64 * base::TimeTicks::kMicrosecondsPerSecond;
+      default:
+        NOTREACHED();
+    }
+
+    if (++sub_bucket_ >= kVSyncBucketCounts[category_]) {
+      category_++;
+      sub_bucket_ = 0;
+    }
+
+    return boundary;
+  }
+};
+
+}  // namespace
+
+std::unique_ptr<BoundaryIterator> CreateVSyncIteratorForTesting() {
+  return std::make_unique<VSyncBoundaryIterator>();
+}
+
+VSyncHistogram::VSyncHistogram() = default;
+VSyncHistogram::~VSyncHistogram() = default;
+
+// Optimized to minimize the number of memory accesses.
+void VSyncHistogram::AddSample(uint32_t microseconds, uint32_t weight) {
+  size_t bucket = 0;
+
+  static constexpr int k256HzPeriodInMicroseconds =
+      base::TimeTicks::kMicrosecondsPerSecond / 256;
+
+  if (microseconds == 0) {
+    // bucket = 0;
+  } else if (microseconds < k256HzPeriodInMicroseconds) {
+    // Powers of two from 1 to 2048 us @ 50% precision
+    bucket = kVSync1stBucketC1 + base::bits::Log2Floor(microseconds);
+  } else if (microseconds < base::TimeTicks::kMicrosecondsPerSecond) {
+    // [256Hz, 1Hz)
+    int hz = base::TimeTicks::kMicrosecondsPerSecond / (microseconds + 0.5);
+    DCHECK_LT(hz, 256);
+    switch (hz / 32) {
+      // Every 1 Hz from 32 Hz to 1 Hz @ 3-33% precision
+      case 0:
+        bucket = kVSync1stBucketC6 - hz;
+        break;
+      // Every 2 Hz from 64 Hz to 32 Hz @ 3-6% precision
+      case 1:
+        bucket = kVSync1stBucketC5 - ((hz - 30) / 2);
+        break;
+      // Every 4 Hz from 128 Hz to 64 Hz @ 3-6% precision
+      case 2:
+      case 3:
+        bucket = kVSync1stBucketC4 - ((hz - 60) / 4);
+        break;
+      // Every 8 Hz from 256 Hz to 128 Hz @ 3-6% precision
+      case 4:
+      case 5:
+      case 6:
+      case 7:
+        bucket = kVSync1stBucketC3 - ((hz - 120) / 8);
+        break;
+      default:
+        NOTREACHED();
+        return;
+    }
+  } else {
+    // Powers of two from 1s to 32s @ 50% precision
+    int seconds_log2 = base::bits::Log2Floor(
+        microseconds / base::TimeTicks::kMicrosecondsPerSecond);
+    DCHECK_GE(seconds_log2, 0);
+    size_t offset = std::min<size_t>(kVSyncBucketCountC6 - 1, seconds_log2);
+    bucket = kVSync1stBucketC6 + offset;
+  }
+
+  DCHECK_GE(bucket, 0u);
+  DCHECK_LT(bucket, kVSync1stBucketC6 + kVSyncBucketCountC6);
+  DCHECK_LT(bucket, kBucketCount);
+
+  // Verify overflow isn't an issue.
+  DCHECK_LT(weight, std::numeric_limits<BucketArray::value_type>::max() -
+                        buckets_[bucket]);
+  DCHECK_LT(weight, std::numeric_limits<decltype(total_samples_)>::max() -
+                        total_samples_);
+
+  buckets_[bucket] += weight;
+  total_samples_ += weight;
+}
+
+PercentileResults VSyncHistogram::CalculatePercentiles() const {
+  VSyncBoundaryIterator i;
+  return PercentilesHelper(&i, buckets_.data(),
+                           buckets_.data() + buckets_.size(), total_samples_);
+}
+
+void VSyncHistogram::Reset() {
+  total_samples_ = 0;
+  buckets_.fill(0);
+}
+
+}  // namespace frame_metrics
+}  // namespace ui
diff --git a/ui/latency/histograms.h b/ui/latency/histograms.h
new file mode 100644
index 0000000..b56bf92
--- /dev/null
+++ b/ui/latency/histograms.h
@@ -0,0 +1,103 @@
+// 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 UI_LATENCY_HISTOGRAMS_H_
+#define UI_LATENCY_HISTOGRAMS_H_
+
+#include <array>
+#include <memory>
+
+#include "base/macros.h"
+
+namespace ui {
+
+// Used to communicate percentile results to clients.
+struct PercentileResults {
+  static constexpr double kPercentiles[] = {.50, .99};
+  static constexpr size_t kCount = arraysize(kPercentiles);
+
+  double values[kCount]{};
+};
+
+namespace frame_metrics {
+
+// This is an interface different metrics will use to inject their ideal
+// histogram implementations into the StreamAnalyzer.
+class Histogram {
+ public:
+  Histogram() = default;
+  virtual ~Histogram() = default;
+
+  // Increases the bucket that contains |value| by |weight|.
+  virtual void AddSample(uint32_t value, uint32_t weight) = 0;
+
+  // Calculates and returns the approximate percentiles based on the
+  // histogram distribution.
+  virtual PercentileResults CalculatePercentiles() const = 0;
+
+  // Resets all buckets in the histogram to 0.
+  // Higher level logic may periodically reset the the counts after it
+  // gathers the percentiles in order to avoid overflow.
+  virtual void Reset() = 0;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(Histogram);
+};
+
+// Ratio histogram, with a range of [0, 2^32) and most of it's precision
+// just above kFixedPointMultiplier (i.e. a fixed point of 1).
+class RatioHistogram : public Histogram {
+ public:
+  RatioHistogram();
+  ~RatioHistogram() override;
+  void AddSample(uint32_t ratio, uint32_t weight) override;
+  PercentileResults CalculatePercentiles() const override;
+  void Reset() override;
+
+ private:
+  static constexpr size_t kBucketCount = 111;
+
+  uint64_t total_samples_ = 0;
+  using BucketArray = std::array<uint32_t, kBucketCount>;
+  BucketArray buckets_{};
+
+  DISALLOW_COPY_AND_ASSIGN(RatioHistogram);
+};
+
+// A histogram of 98 buckets from 0 to 64 seconds with extra precision
+// around common vsync boundaries.
+class VSyncHistogram : public Histogram {
+ public:
+  VSyncHistogram();
+  ~VSyncHistogram() override;
+  void AddSample(uint32_t microseconds, uint32_t weight) override;
+  PercentileResults CalculatePercentiles() const override;
+  void Reset() override;
+
+ private:
+  static constexpr size_t kBucketCount = 98;
+
+  uint64_t total_samples_ = 0;
+  using BucketArray = std::array<uint32_t, kBucketCount>;
+  BucketArray buckets_{};
+
+  DISALLOW_COPY_AND_ASSIGN(VSyncHistogram);
+};
+
+// An interface that allows PercentileHelper to iterate through the
+// bucket boundaries of the delegating histogram.
+// This is an implemenation detail, but is exposed here for testing purposes.
+struct BoundaryIterator {
+  virtual ~BoundaryIterator() = default;
+  virtual uint64_t Next() = 0;
+};
+
+// These expose the internal iterators, so they can be verified in tests.
+std::unique_ptr<BoundaryIterator> CreateRatioIteratorForTesting();
+std::unique_ptr<BoundaryIterator> CreateVSyncIteratorForTesting();
+
+}  // namespace frame_metrics
+}  // namespace ui
+
+#endif  // UI_LATENCY_HISTOGRAMS_H_
diff --git a/ui/latency/histograms_perftest.cc b/ui/latency/histograms_perftest.cc
new file mode 100644
index 0000000..a44e0331
--- /dev/null
+++ b/ui/latency/histograms_perftest.cc
@@ -0,0 +1,257 @@
+// 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 "ui/latency/histograms.h"
+
+#include <algorithm>
+
+#include "base/metrics/bucket_ranges.h"
+#include "base/metrics/sample_vector.h"
+#include "base/time/time.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/perf/perf_test.h"
+#include "ui/latency/fixed_point.h"
+#include "ui/latency/histograms_test_common.h"
+
+namespace ui {
+namespace frame_metrics {
+
+constexpr base::TimeDelta kTimeLimit = base::TimeDelta::FromSeconds(2);
+
+// A version of RatioHistogram based on the default implementations
+// of base::BucketRanges and base::SampleVector.
+class RatioHistogramBaseline : public Histogram {
+ public:
+  RatioHistogramBaseline()
+      : ratio_boundaries_(),
+        bucket_ranges_(ratio_boundaries_.size()),
+        sample_vector_(&bucket_ranges_) {
+    size_t i = 0;
+    for (const auto& b : ratio_boundaries_.boundaries) {
+      bucket_ranges_.set_range(i++, std::min<uint64_t>(b, INT_MAX));
+    }
+  }
+
+  ~RatioHistogramBaseline() override = default;
+
+  void AddSample(uint32_t microseconds, uint32_t weight) override {
+    sample_vector_.Accumulate(microseconds, weight);
+  }
+
+  PercentileResults CalculatePercentiles() const override {
+    return PercentileResults();
+  }
+  void Reset() override {}
+
+ private:
+  TestRatioBoundaries ratio_boundaries_;
+  base::BucketRanges bucket_ranges_;
+  base::SampleVector sample_vector_;
+
+  DISALLOW_COPY_AND_ASSIGN(RatioHistogramBaseline);
+};
+
+TEST(FrameMetricsHistogramsPerfTest, RatioEntireRange) {
+  const int kStride = 0x1000;
+
+  RatioHistogramBaseline vh_base;
+  RatioHistogram vh_impl;
+
+  base::TimeDelta impl_time;
+  base::TimeDelta base_time;
+
+  base::TimeTicks finish_time = base::TimeTicks::Now() + kTimeLimit;
+  while (base::TimeTicks::Now() < finish_time) {
+    // Impl then Base
+    for (int i = 0; i < INT_MAX - kStride; i += kStride) {
+      int value = (i * 37) & 0x3FFFFFFF;
+      base::TimeTicks t0 = base::TimeTicks::Now();
+      vh_impl.AddSample(value, 1);
+      base::TimeTicks t1 = base::TimeTicks::Now();
+      vh_base.AddSample(value, 1);
+      base::TimeTicks t2 = base::TimeTicks::Now();
+      base::TimeTicks t3 = base::TimeTicks::Now();
+      impl_time += t1 - t0 - (t3 - t2);
+      base_time += t2 - t1 - (t3 - t2);
+    }
+
+    // Base then Impl
+    for (int i = 0; i < INT_MAX - kStride; i += kStride) {
+      int value = (i * 37) & 0x3FFFFFFF;
+      base::TimeTicks t0 = base::TimeTicks::Now();
+      vh_base.AddSample(value, 1);
+      base::TimeTicks t1 = base::TimeTicks::Now();
+      vh_impl.AddSample(value, 1);
+      base::TimeTicks t2 = base::TimeTicks::Now();
+      base::TimeTicks t3 = base::TimeTicks::Now();
+      base_time += t1 - t0 - (t3 - t2);
+      impl_time += t2 - t1 - (t3 - t2);
+    }
+  }
+
+  double X = base_time.InSecondsF() / impl_time.InSecondsF();
+  perf_test::PrintResult(__FUNCTION__, "", __FUNCTION__, X, "x", true);
+}
+
+TEST(FrameMetricsHistogramsPerfTest, RatioCommonRange) {
+  const int kStride = 0x100;
+
+  RatioHistogramBaseline vh_base;
+  RatioHistogram vh_impl;
+
+  base::TimeDelta impl_time;
+  base::TimeDelta base_time;
+
+  base::TimeTicks finish_time = base::TimeTicks::Now() + kTimeLimit;
+  while (base::TimeTicks::Now() < finish_time) {
+    // Impl then Base
+    for (int i = 0; i < 4 * kFixedPointMultiplier; i += kStride) {
+      int value = i;
+      base::TimeTicks t0 = base::TimeTicks::Now();
+      vh_impl.AddSample(value, 1);
+      base::TimeTicks t1 = base::TimeTicks::Now();
+      vh_base.AddSample(value, 1);
+      base::TimeTicks t2 = base::TimeTicks::Now();
+      base::TimeTicks t3 = base::TimeTicks::Now();
+      impl_time += t1 - t0 - (t3 - t2);
+      base_time += t2 - t1 - (t3 - t2);
+    }
+
+    // Base then Impl
+    for (int i = 0; i < 4 * kFixedPointMultiplier; i += kStride) {
+      int value = i;
+      base::TimeTicks t0 = base::TimeTicks::Now();
+      vh_base.AddSample(value, 1);
+      base::TimeTicks t1 = base::TimeTicks::Now();
+      vh_impl.AddSample(value, 1);
+      base::TimeTicks t2 = base::TimeTicks::Now();
+      base::TimeTicks t3 = base::TimeTicks::Now();
+      base_time += t1 - t0 - (t3 - t2);
+      impl_time += t2 - t1 - (t3 - t2);
+    }
+  }
+
+  double X = base_time.InSecondsF() / impl_time.InSecondsF();
+  perf_test::PrintResult(__FUNCTION__, "", __FUNCTION__, X, "x", true);
+}
+
+// A version of VSyncHistogram based on the default implementations
+// of base::BucketRanges and base::SampleVector.
+class VSyncHistogramBaseline : public Histogram {
+ public:
+  VSyncHistogramBaseline()
+      : bucket_ranges_(kTestVSyncBoundries.size() + 1),
+        sample_vector_(&bucket_ranges_) {
+    size_t i = 0;
+    for (const auto& b : kTestVSyncBoundries) {
+      bucket_ranges_.set_range(i++, b);
+    }
+    // BucketRanges needs the last elemet set to INT_MAX.
+    bucket_ranges_.set_range(i++, INT_MAX);
+  }
+
+  ~VSyncHistogramBaseline() override = default;
+
+  void AddSample(uint32_t microseconds, uint32_t weight) override {
+    sample_vector_.Accumulate(microseconds, weight);
+  }
+
+  PercentileResults CalculatePercentiles() const override {
+    return PercentileResults();
+  }
+  void Reset() override {}
+
+ private:
+  base::BucketRanges bucket_ranges_;
+  base::SampleVector sample_vector_;
+
+  DISALLOW_COPY_AND_ASSIGN(VSyncHistogramBaseline);
+};
+
+TEST(FrameMetricsHistogramsPerfTest, VSyncEntireRange) {
+  const int kStride = 0x1000;
+
+  VSyncHistogramBaseline vh_base;
+  VSyncHistogram vh_impl;
+
+  base::TimeDelta impl_time;
+  base::TimeDelta base_time;
+
+  base::TimeTicks finish_time = base::TimeTicks::Now() + kTimeLimit;
+  while (base::TimeTicks::Now() < finish_time) {
+    // Impl then Base
+    for (int i = 0; i < INT_MAX - kStride; i += kStride) {
+      int value = (i * 37) % 64000000;
+      base::TimeTicks t0 = base::TimeTicks::Now();
+      vh_impl.AddSample(value, 1);
+      base::TimeTicks t1 = base::TimeTicks::Now();
+      vh_base.AddSample(value, 1);
+      base::TimeTicks t2 = base::TimeTicks::Now();
+      base::TimeTicks t3 = base::TimeTicks::Now();
+      impl_time += t1 - t0 - (t3 - t2);
+      base_time += t2 - t1 - (t3 - t2);
+    }
+
+    // Base then Impl
+    for (int i = 0; i < INT_MAX - kStride; i += kStride) {
+      int value = (i * 37) % 64000000;
+      base::TimeTicks t0 = base::TimeTicks::Now();
+      vh_base.AddSample(value, 1);
+      base::TimeTicks t1 = base::TimeTicks::Now();
+      vh_impl.AddSample(value, 1);
+      base::TimeTicks t2 = base::TimeTicks::Now();
+      base::TimeTicks t3 = base::TimeTicks::Now();
+      base_time += t1 - t0 - (t3 - t2);
+      impl_time += t2 - t1 - (t3 - t2);
+    }
+  }
+
+  double X = base_time.InSecondsF() / impl_time.InSecondsF();
+  perf_test::PrintResult(__FUNCTION__, "", __FUNCTION__, X, "x", true);
+}
+
+TEST(FrameMetricsHistogramsPerfTest, VSyncCommonRange) {
+  const int kStride = 0x100;
+
+  VSyncHistogramBaseline vh_base;
+  VSyncHistogram vh_impl;
+
+  base::TimeDelta impl_time;
+  base::TimeDelta base_time;
+
+  base::TimeTicks finish_time = base::TimeTicks::Now() + kTimeLimit;
+  while (base::TimeTicks::Now() < finish_time) {
+    // Impl then Base
+    for (int i = 0; i < 100000; i += kStride) {
+      int value = i;
+      base::TimeTicks t0 = base::TimeTicks::Now();
+      vh_impl.AddSample(value, 1);
+      base::TimeTicks t1 = base::TimeTicks::Now();
+      vh_base.AddSample(value, 1);
+      base::TimeTicks t2 = base::TimeTicks::Now();
+      base::TimeTicks t3 = base::TimeTicks::Now();
+      impl_time += t1 - t0 - (t3 - t2);
+      base_time += t2 - t1 - (t3 - t2);
+    }
+
+    // Base then Impl
+    for (int i = 0; i < 100000; i += kStride) {
+      int value = i;
+      base::TimeTicks t0 = base::TimeTicks::Now();
+      vh_base.AddSample(value, 1);
+      base::TimeTicks t1 = base::TimeTicks::Now();
+      vh_impl.AddSample(value, 1);
+      base::TimeTicks t2 = base::TimeTicks::Now();
+      base::TimeTicks t3 = base::TimeTicks::Now();
+      base_time += t1 - t0 - (t3 - t2);
+      impl_time += t2 - t1 - (t3 - t2);
+    }
+  }
+
+  double X = base_time.InSecondsF() / impl_time.InSecondsF();
+  perf_test::PrintResult(__FUNCTION__, "", __FUNCTION__, X, "x", true);
+}
+
+}  // namespace frame_metrics
+}  // namespace ui
diff --git a/ui/latency/histograms_test_common.cc b/ui/latency/histograms_test_common.cc
new file mode 100644
index 0000000..5fd2d5df
--- /dev/null
+++ b/ui/latency/histograms_test_common.cc
@@ -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.
+
+#include "ui/latency/histograms_test_common.h"
+
+#include "base/logging.h"
+
+namespace ui {
+namespace frame_metrics {
+
+TestRatioBoundaries::TestRatioBoundaries() {
+  const uint32_t one = kFixedPointMultiplier;
+  const uint32_t half = one / 2;
+  // [0, 2^-16) => 1 bucket.
+  int i = 0;
+  boundaries[i++] = 0;
+  // [2^-16,1) pow of 2 strides => 16 buckets. (16x1)
+  for (int j = 0; j < 16; j++)
+    boundaries[i++] = 1ULL << j;
+  // [1,16) stride 1/2 => 30 buckets. (2 + 4 + 8 + 16)
+  for (int j = 0; j < 30; j++)
+    boundaries[i++] = one + (j * half);
+  // [16,32) stride 1 => 16 buckets.
+  for (int j = 0; j < 16; j++)
+    boundaries[i++] = (16 + j) * one;
+  // [32,64) stride 2 => 16 buckets.
+  for (int j = 0; j < 16; j++)
+    boundaries[i++] = (32 + 2 * j) * one;
+  // [64,128) stride 8 => 8 buckets.
+  for (int j = 0; j < 8; j++)
+    boundaries[i++] = (64 + 8 * j) * one;
+  // [128, 256) stride 16 => 8 buckets.
+  for (int j = 0; j < 8; j++)
+    boundaries[i++] = (128 + 16 * j) * one;
+  // [256, 512) stride 64 => 4 buckets.
+  for (int j = 0; j < 4; j++)
+    boundaries[i++] = (256 + 64 * j) * one;
+  // [512, 1024) stride 128 => 4 buckets.
+  for (int j = 0; j < 4; j++)
+    boundaries[i++] = (512 + 128 * j) * one;
+  // [1024, 2048) stride 512 => 2 buckets.
+  for (int j = 0; j < 2; j++)
+    boundaries[i++] = (1024 + 512 * j) * one;
+  // [2048, 4096) stride 1024 => 2 buckets.
+  for (int j = 0; j < 2; j++)
+    boundaries[i++] = (2048 + 1024 * j) * one;
+  // [4096, 2^16) pow of 2 strides => 4 buckets. (4x1)
+  for (int j = 0; j < 4; j++)
+    boundaries[i++] = (4096ULL << j) * one;
+  boundaries[i++] = 1ULL << 32;
+  DCHECK_EQ(112, i);
+}
+
+}  // namespace frame_metrics
+}  // namespace ui
diff --git a/ui/latency/histograms_test_common.h b/ui/latency/histograms_test_common.h
new file mode 100644
index 0000000..5b5657f
--- /dev/null
+++ b/ui/latency/histograms_test_common.h
@@ -0,0 +1,58 @@
+// 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 UI_LATENCY_HISTOGRAMS_TEST_COMMON_H_
+#define UI_LATENCY_HISTOGRAMS_TEST_COMMON_H_
+
+#include "ui/latency/fixed_point.h"
+
+#include <array>
+
+namespace ui {
+namespace frame_metrics {
+
+// This class initializes the ratio boundaries on construction in a way that
+// is easier to follow than the procedural code in the RatioHistogram
+// implementation.
+class TestRatioBoundaries {
+ public:
+  TestRatioBoundaries();
+  uint64_t operator[](size_t i) const { return boundaries[i]; }
+  size_t size() const { return boundaries.size(); }
+
+ public:
+  // uint64_t since the last boundary needs 33 bits.
+  std::array<uint64_t, 112> boundaries;
+};
+
+// An explicit list of VSync boundaries to verify the procedurally generated
+// ones in the implementation.
+static constexpr std::array<uint32_t, 99> kTestVSyncBoundries = {
+    {// C0: [0,1) (1 bucket).
+     0,
+     // C1: Powers of two from 1 to 2048 us @ 50% precision (12 buckets)
+     1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048,
+     // C2: Every 8 Hz from 256 Hz to 128 Hz @ 3-6% precision (16 buckets)
+     3906, 4032, 4167, 4310, 4464, 4630, 4808, 5000, 5208, 5435, 5682, 5952,
+     6250, 6579, 6944, 7353,
+     // C3: Every 4 Hz from 128 Hz to 64 Hz @ 3-6% precision (16 buckets)
+     7813, 8065, 8333, 8621, 8929, 9259, 9615, 10000, 10417, 10870, 11364,
+     11905, 12500, 13158, 13889, 14706,
+     // C4: Every 2 Hz from 64 Hz to 32 Hz @ 3-6% precision (16 buckets)
+     15625, 16129, 16667, 17241, 17857, 18519, 19231, 20000, 20833, 21739,
+     22727, 23810, 25000, 26316, 27778, 29412,
+     // C5: Every 1 Hz from 32 Hz to 1 Hz @ 3-33% precision (31 buckets)
+     31250, 32258, 33333, 34483, 35714, 37037, 38462, 40000, 41667, 43478,
+     45455, 47619, 50000, 52632, 55556, 58824, 62500, 66667, 71429, 76923,
+     83333, 90909, 100000, 111111, 125000, 142857, 166667, 200000, 250000,
+     333333, 500000,
+     // C6: Powers of two from 1s to 32s @ 50% precision (6 buckets)
+     1000000, 2000000, 4000000, 8000000, 16000000, 32000000,
+     // C7: Extra value to simplify estimate in Percentiles().
+     64000000}};
+
+}  // namespace frame_metrics
+}  // namespace ui
+
+#endif  // UI_LATENCY_HISTOGRAMS_TEST_COMMON_H_
diff --git a/ui/latency/histograms_unittest.cc b/ui/latency/histograms_unittest.cc
new file mode 100644
index 0000000..4687c18
--- /dev/null
+++ b/ui/latency/histograms_unittest.cc
@@ -0,0 +1,151 @@
+// 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 "ui/latency/histograms.h"
+
+#include <algorithm>
+
+#include "base/metrics/bucket_ranges.h"
+#include "base/metrics/sample_vector.h"
+#include "base/time/time.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/latency/fixed_point.h"
+#include "ui/latency/histograms_test_common.h"
+
+namespace ui {
+namespace frame_metrics {
+
+// Verifies the ratio boundaries generated internally match the reference
+// boundaries.
+TEST(FrameMetricsHistogramsTest, RatioBoundariesDirect) {
+  const TestRatioBoundaries kTestRatioBoundaries;
+  std::unique_ptr<BoundaryIterator> ratio_impl =
+      CreateRatioIteratorForTesting();
+  for (uint32_t boundary : kTestRatioBoundaries.boundaries) {
+    if (boundary == 0)
+      continue;
+    EXPECT_EQ(boundary, ratio_impl->Next());
+  }
+}
+
+// Verifies the VSync boundaries generated internally match the reference
+// boundaries.
+TEST(FrameMetricsHistogramsTest, VSyncBoundariesDirect) {
+  std::unique_ptr<BoundaryIterator> vsync_impl =
+      CreateVSyncIteratorForTesting();
+  for (uint32_t boundary : kTestVSyncBoundries) {
+    if (boundary == 0)
+      continue;
+    EXPECT_EQ(boundary, vsync_impl->Next());
+  }
+}
+
+template <typename ReferenceBoundaryT>
+void BoundaryTestCommon(const ReferenceBoundaryT& reference_boundaries,
+                        std::unique_ptr<Histogram> histogram) {
+  PercentileResults percentiles;
+
+  for (size_t i = 0; i < reference_boundaries.size() - 1; i++) {
+    uint64_t bucket_start = reference_boundaries[i];
+    uint64_t bucket_end = reference_boundaries[i + 1];
+
+    // Verify values within the current bucket don't affect percentile.
+    // This also checks the first value in the bucket.
+    uint32_t stride = std::max<uint32_t>(1u, (bucket_end - bucket_start) / 8);
+    for (uint64_t value = bucket_start; value < bucket_end; value += stride) {
+      histogram->AddSample(value, 1);
+      percentiles = histogram->CalculatePercentiles();
+      histogram->Reset();
+      EXPECT_LE(bucket_start, percentiles.values[0]);
+      EXPECT_GT(bucket_end, percentiles.values[0]);
+    }
+
+    // Verify the value just before the next bucket doesn't affect percentile.
+    histogram->AddSample(bucket_end - 1, 1);
+    percentiles = histogram->CalculatePercentiles();
+    histogram->Reset();
+    EXPECT_LE(bucket_start, percentiles.values[0]);
+    EXPECT_GT(bucket_end, percentiles.values[0]);
+  }
+}
+
+TEST(FrameMetricsHistogramsTest, RatioBoundaries) {
+  const TestRatioBoundaries kTestRatioBoundaries;
+  BoundaryTestCommon(kTestRatioBoundaries, std::make_unique<RatioHistogram>());
+}
+
+TEST(FrameMetricsHistogramsTest, VSyncBoundaries) {
+  const TestRatioBoundaries kTestRatioBoundaries;
+  BoundaryTestCommon(kTestVSyncBoundries, std::make_unique<VSyncHistogram>());
+}
+
+template <typename ReferenceBoundaryT>
+void PercentilesTestCommon(const ReferenceBoundaryT& reference_boundaries,
+                           std::unique_ptr<Histogram> histogram,
+                           int percentile_index) {
+  double percentile = PercentileResults::kPercentiles[percentile_index];
+  PercentileResults percentiles;
+  for (size_t i = 0; i < reference_boundaries.size() - 1; i++) {
+    uint64_t bucket_start = reference_boundaries[i];
+    uint64_t bucket_end = reference_boundaries[i + 1];
+
+    // Add samples to current bucket.
+    // Where the samples are added in the current bucket should not affect the
+    // result.
+    uint32_t stride = std::max<uint32_t>(1u, (bucket_end - bucket_start) / 100);
+    int samples_added_inside = 0;
+    for (uint64_t value = bucket_start; value < bucket_end; value += stride) {
+      histogram->AddSample(value, 10);
+      samples_added_inside += 10;
+    }
+
+    // Add samples to left and right of current bucket.
+    // Don't worry about doing this for the left most and right most buckets.
+    int samples_added_left = 0;
+    int samples_added_outside = 0;
+    if (i != 0 && i < reference_boundaries.size() - 2) {
+      samples_added_outside = 10000;
+      samples_added_left = samples_added_outside * percentile;
+      histogram->AddSample(bucket_start / 3, samples_added_left);
+      histogram->AddSample(bucket_start * 3,
+                           samples_added_outside - samples_added_left);
+    }
+
+    percentiles = histogram->CalculatePercentiles();
+    histogram->Reset();
+
+    double index = (samples_added_inside + samples_added_outside) * percentile -
+                   samples_added_left;
+    double w = index / samples_added_inside;
+    double expected_value = bucket_end * w + bucket_start * (1.0 - w);
+    EXPECT_DOUBLE_EQ(expected_value, percentiles.values[percentile_index]);
+  }
+}
+
+TEST(FrameMetricsHistogramsTest, RatioPercentiles50th) {
+  const TestRatioBoundaries kTestRatioBoundaries;
+  PercentilesTestCommon(kTestRatioBoundaries,
+                        std::make_unique<RatioHistogram>(), 0);
+}
+
+TEST(FrameMetricsHistogramsTest, RatioPercentiles99th) {
+  const TestRatioBoundaries kTestRatioBoundaries;
+  PercentilesTestCommon(kTestRatioBoundaries,
+                        std::make_unique<RatioHistogram>(), 1);
+}
+
+TEST(FrameMetricsHistogramsTest, VSyncPercentiles50th) {
+  const TestRatioBoundaries kTestRatioBoundaries;
+  PercentilesTestCommon(kTestVSyncBoundries, std::make_unique<VSyncHistogram>(),
+                        0);
+}
+
+TEST(FrameMetricsHistogramsTest, VSyncPercentiles99th) {
+  const TestRatioBoundaries kTestRatioBoundaries;
+  PercentilesTestCommon(kTestVSyncBoundries, std::make_unique<VSyncHistogram>(),
+                        1);
+}
+
+}  // namespace frame_metrics
+}  // namespace ui
diff --git a/ui/login/display_manager.js b/ui/login/display_manager.js
index 0a3594d..69b6d98 100644
--- a/ui/login/display_manager.js
+++ b/ui/login/display_manager.js
@@ -385,12 +385,12 @@
      * @param {string} name Accelerator name.
      */
     handleAccelerator: function(name) {
-      if (this.currentScreen.ignoreAccelerators) {
+      if (this.currentScreen && this.currentScreen.ignoreAccelerators) {
         return;
       }
       var currentStepId = this.screens_[this.currentStep_];
       if (name == ACCELERATOR_CANCEL) {
-        if (this.currentScreen.cancel) {
+        if (this.currentScreen && this.currentScreen.cancel) {
           this.currentScreen.cancel();
         }
       } else if (name == ACCELERATOR_ENABLE_DEBBUGING) {
diff --git a/ui/views/cocoa/bridged_content_view.mm b/ui/views/cocoa/bridged_content_view.mm
index d57a5e3..756745e6 100644
--- a/ui/views/cocoa/bridged_content_view.mm
+++ b/ui/views/cocoa/bridged_content_view.mm
@@ -614,11 +614,16 @@
 
 // NSView implementation.
 
-// Always refuse first responder. Note this does not prevent the view becoming
-// first responder via -[NSWindow makeFirstResponder:] when invoked during Init
-// or by FocusManager.
+// Refuse first responder, unless we are already first responder. Note this does
+// not prevent the view becoming first responder via -[NSWindow
+// makeFirstResponder:] when invoked during Init or by FocusManager.
+//
+// The condition is to work around an AppKit quirk. When a window is being
+// ordered front, if its current first responder returns |NO| for this method,
+// it resigns it if it can find another responder in the key loop that replies
+// |YES|.
 - (BOOL)acceptsFirstResponder {
-  return NO;
+  return [[self window] firstResponder] == self;
 }
 
 - (BOOL)becomeFirstResponder {