diff --git a/DEPS b/DEPS
index f992d43..ca8321f 100644
--- a/DEPS
+++ b/DEPS
@@ -105,11 +105,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': 'c062b6be5a01b3f4845c64181b1588d03c02d1e1',
+  'skia_revision': 'b284280be4cc15bd13bc8c53b9f486d027fcc939',
   # 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': '58ea46ee6c757b368c2e719085a909394225fe11',
+  'v8_revision': 'd729403cd1d7b25f51637aa900527903b8837ced',
   # 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.
@@ -117,7 +117,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': '096c5296c3b0bd2c83211b256d28fe3288792eac',
+  'angle_revision': '2160821e16dbc4f2715422940df914ed5e77bf92',
   # 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.
@@ -539,7 +539,7 @@
 
   # Build tools for Chrome OS. Note: This depends on third_party/pyelftools.
   'src/third_party/chromite': {
-      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '09f0990a2db0cf45d076a0c6d99a88853b258a10',
+      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + 'cb29fbd231d64bbc5d23bbf04fb47637111b71bb',
       'condition': 'checkout_linux',
   },
 
@@ -1034,7 +1034,7 @@
     Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + '21dbf06b5aa6c7dc8cf56314d4a3f96f57956c53',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + '715cc238d24b5d9bb7a7619946a8bf9fe44d339e',
+    Var('webrtc_git') + '/src.git' + '@' + 'e71d1bb7fc22c7a08f34391b69c722d07c2100f2',
 
   'src/third_party/xdg-utils': {
       'url': Var('chromium_git') + '/chromium/deps/xdg-utils.git' + '@' + 'd80274d5869b17b8c9067a1022e4416ee7ed5e0d',
diff --git a/android_webview/browser/net/aw_cookie_change_dispatcher_wrapper.cc b/android_webview/browser/net/aw_cookie_change_dispatcher_wrapper.cc
index fc0813b..de3ea504 100644
--- a/android_webview/browser/net/aw_cookie_change_dispatcher_wrapper.cc
+++ b/android_webview/browser/net/aw_cookie_change_dispatcher_wrapper.cc
@@ -49,7 +49,7 @@
     DCHECK(callback_list_.empty());
 
     nested_subscription_ =
-        new NestedSubscription(url, name, weak_factory_.GetWeakPtr());
+        NestedSubscription::Create(url, name, weak_factory_.GetWeakPtr());
     return std::make_unique<AwCookieChangeSubscription>(
         callback_list_.Add(std::move(callback)));
   }
@@ -61,21 +61,28 @@
   class NestedSubscription
       : public base::RefCountedDeleteOnSequence<NestedSubscription> {
    public:
-    NestedSubscription(const GURL& url,
-                       const std::string& name,
-                       base::WeakPtr<SubscriptionWrapper> subscription_wrapper)
-        : base::RefCountedDeleteOnSequence<NestedSubscription>(
-              GetCookieStoreTaskRunner()),
-          subscription_wrapper_(subscription_wrapper),
-          client_task_runner_(base::ThreadTaskRunnerHandle::Get()) {
-      PostTaskToCookieStoreTaskRunner(
-          base::BindOnce(&NestedSubscription::Subscribe, this, url, name));
+    static scoped_refptr<NestedSubscription> Create(
+        const GURL& url,
+        const std::string& name,
+        base::WeakPtr<SubscriptionWrapper> subscription_wrapper) {
+      auto subscription = base::WrapRefCounted(
+          new NestedSubscription(std::move(subscription_wrapper)));
+      PostTaskToCookieStoreTaskRunner(base::BindOnce(
+          &NestedSubscription::Subscribe, subscription, url, name));
+      return subscription;
     }
 
    private:
     friend class base::RefCountedDeleteOnSequence<NestedSubscription>;
     friend class base::DeleteHelper<NestedSubscription>;
 
+    explicit NestedSubscription(
+        base::WeakPtr<SubscriptionWrapper> subscription_wrapper)
+        : base::RefCountedDeleteOnSequence<NestedSubscription>(
+              GetCookieStoreTaskRunner()),
+          subscription_wrapper_(subscription_wrapper),
+          client_task_runner_(base::ThreadTaskRunnerHandle::Get()) {}
+
     ~NestedSubscription() {}
 
     void Subscribe(const GURL& url, const std::string& name) {
diff --git a/android_webview/tools/system_webview_shell/test/data/run_tests_rebaseline.sh b/android_webview/tools/system_webview_shell/test/data/run_tests_rebaseline.sh
index 74feb16..5563630 100755
--- a/android_webview/tools/system_webview_shell/test/data/run_tests_rebaseline.sh
+++ b/android_webview/tools/system_webview_shell/test/data/run_tests_rebaseline.sh
@@ -10,7 +10,7 @@
 #    needs to be installed on the device (e.g. system_webview_apk).
 # 2. Build system_webview_shell_layout_test_apk. This will also
 #    create a base script for running tests used here.
-# 3. Execute run_test_rebaseline.sh [builddir]
+# 3. Execute run_tests_rebaseline.sh [builddir]
 #    "builddir" is the build output directory (e.g. out/Debug/
 #    which is also the default if no directory is provided).
 #    This script will produce a shadow test_rebaseline/ directory
@@ -42,7 +42,7 @@
 
 adb shell am instrument -w -e mode rebaseline -e class \
     $PACKAGE_NAME.WebViewLayoutTest \
-    $PACKAGE_NAME/$PACKAGE_NAME.WebViewLayoutTestRunner
+    $PACKAGE_NAME/android.support.test.runner.AndroidJUnitRunner
 adb pull $DEVICE_WEBVIEW_TEST_PATH ../test_rebaseline/
 
 exit 0
diff --git a/ash/BUILD.gn b/ash/BUILD.gn
index 3bd5127f..4d18a7bc 100644
--- a/ash/BUILD.gn
+++ b/ash/BUILD.gn
@@ -278,8 +278,6 @@
     "frame/default_frame_header.h",
     "frame/detached_title_area_renderer.cc",
     "frame/detached_title_area_renderer.h",
-    "frame/frame_border_hit_test.cc",
-    "frame/frame_border_hit_test.h",
     "frame/frame_header.cc",
     "frame/frame_header.h",
     "frame/frame_header_util.cc",
@@ -739,8 +737,6 @@
     "system/network/vpn_list_view.h",
     "system/network/wifi_toggle_notification_controller.cc",
     "system/network/wifi_toggle_notification_controller.h",
-    "system/networking_config_delegate.cc",
-    "system/networking_config_delegate.h",
     "system/night_light/night_light_controller.cc",
     "system/night_light/night_light_controller.h",
     "system/night_light/night_light_feature_pod_controller.cc",
diff --git a/ash/frame/caption_buttons/frame_back_button.cc b/ash/frame/caption_buttons/frame_back_button.cc
index c772dc4..0bae36ce5 100644
--- a/ash/frame/caption_buttons/frame_back_button.cc
+++ b/ash/frame/caption_buttons/frame_back_button.cc
@@ -10,6 +10,7 @@
 #include "ash/strings/grit/ash_strings.h"
 #include "ui/aura/window.h"
 #include "ui/aura/window_tree_host.h"
+#include "ui/base/hit_test.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/events/event_sink.h"
@@ -18,7 +19,7 @@
 namespace ash {
 
 FrameBackButton::FrameBackButton()
-    : FrameCaptionButton(this, CAPTION_BUTTON_ICON_BACK) {
+    : FrameCaptionButton(this, CAPTION_BUTTON_ICON_BACK, HTMENU) {
   SetPreferredSize(GetAshLayoutSize(AshLayoutSize::kNonBrowserCaption));
   SetAccessibleName(
       l10n_util::GetStringUTF16(IDS_ASH_WINDOW_CONTROL_ACCNAME_BACK));
diff --git a/ash/frame/caption_buttons/frame_caption_button.cc b/ash/frame/caption_buttons/frame_caption_button.cc
index 40d4d264..4942d2e4 100644
--- a/ash/frame/caption_buttons/frame_caption_button.cc
+++ b/ash/frame/caption_buttons/frame_caption_button.cc
@@ -5,6 +5,7 @@
 #include "ash/frame/caption_buttons/frame_caption_button.h"
 
 #include "ash/public/cpp/ash_constants.h"
+#include "ui/base/hit_test.h"
 #include "ui/gfx/animation/slide_animation.h"
 #include "ui/gfx/animation/throb_animation.h"
 #include "ui/gfx/canvas.h"
@@ -16,6 +17,7 @@
 #include "ui/views/animation/ink_drop_impl.h"
 #include "ui/views/animation/ink_drop_mask.h"
 #include "ui/views/animation/ink_drop_ripple.h"
+#include "ui/views/view_properties.h"
 
 namespace ash {
 
@@ -68,7 +70,8 @@
 const char FrameCaptionButton::kViewClassName[] = "FrameCaptionButton";
 
 FrameCaptionButton::FrameCaptionButton(views::ButtonListener* listener,
-                                       CaptionButtonIcon icon)
+                                       CaptionButtonIcon icon,
+                                       int hit_test_type)
     : Button(listener),
       icon_(icon),
       background_color_(SK_ColorWHITE),
@@ -76,6 +79,8 @@
       paint_as_active_(false),
       alpha_(255),
       swap_images_animation_(new gfx::SlideAnimation(this)) {
+  SetProperty(views::kHitTestComponentKey, hit_test_type);
+
   set_animate_on_state_change(true);
   swap_images_animation_->Reset(1);
 
diff --git a/ash/frame/caption_buttons/frame_caption_button.h b/ash/frame/caption_buttons/frame_caption_button.h
index 99ad84d2..9dee774 100644
--- a/ash/frame/caption_buttons/frame_caption_button.h
+++ b/ash/frame/caption_buttons/frame_caption_button.h
@@ -33,7 +33,9 @@
 
   static const char kViewClassName[];
 
-  FrameCaptionButton(views::ButtonListener* listener, CaptionButtonIcon icon);
+  FrameCaptionButton(views::ButtonListener* listener,
+                     CaptionButtonIcon icon,
+                     int hit_test_type);
   ~FrameCaptionButton() override;
 
   // Gets the color to use for a frame caption button while a theme color is
diff --git a/ash/frame/caption_buttons/frame_caption_button_container_view.cc b/ash/frame/caption_buttons/frame_caption_button_container_view.cc
index 86424a1..8767920 100644
--- a/ash/frame/caption_buttons/frame_caption_button_container_view.cc
+++ b/ash/frame/caption_buttons/frame_caption_button_container_view.cc
@@ -94,15 +94,6 @@
          static_cast<float>(kHidePositionDelayMs) / kHideAnimationDurationMs;
 }
 
-// Converts |point| from |src| to |dst| and hittests against |dst|.
-bool ConvertPointToViewAndHitTest(const views::View* src,
-                                  const views::View* dst,
-                                  const gfx::Point& point) {
-  gfx::Point converted(point);
-  views::View::ConvertPointToTarget(src, dst, &converted);
-  return dst->HitTestPoint(converted);
-}
-
 // Bounds animation values to the range 0.0 - 1.0. Allows for mapping of offset
 // animations to the expected range so that gfx::Tween::CalculateValue() can be
 // used.
@@ -199,12 +190,13 @@
   }
 
   // Insert the buttons left to right.
-  menu_button_ = new FrameCaptionButton(this, CAPTION_BUTTON_ICON_MENU);
+  menu_button_ = new FrameCaptionButton(this, CAPTION_BUTTON_ICON_MENU, HTMENU);
   menu_button_->SetAccessibleName(
       l10n_util::GetStringUTF16(IDS_APP_ACCNAME_MENU));
   AddChildView(menu_button_);
 
-  minimize_button_ = new FrameCaptionButton(this, CAPTION_BUTTON_ICON_MINIMIZE);
+  minimize_button_ =
+      new FrameCaptionButton(this, CAPTION_BUTTON_ICON_MINIMIZE, HTMINBUTTON);
   minimize_button_->SetAccessibleName(
       l10n_util::GetStringUTF16(IDS_APP_ACCNAME_MINIMIZE));
   AddChildView(minimize_button_);
@@ -214,7 +206,8 @@
       l10n_util::GetStringUTF16(IDS_APP_ACCNAME_MAXIMIZE));
   AddChildView(size_button_);
 
-  close_button_ = new FrameCaptionButton(this, CAPTION_BUTTON_ICON_CLOSE);
+  close_button_ =
+      new FrameCaptionButton(this, CAPTION_BUTTON_ICON_CLOSE, HTCLOSE);
   close_button_->SetAccessibleName(
       l10n_util::GetStringUTF16(IDS_APP_ACCNAME_CLOSE));
   AddChildView(close_button_);
@@ -269,24 +262,6 @@
   SetButtonsToNormal(ANIMATE_NO);
 }
 
-int FrameCaptionButtonContainerView::NonClientHitTest(
-    const gfx::Point& point) const {
-  if (close_button_->visible() &&
-      ConvertPointToViewAndHitTest(this, close_button_, point)) {
-    return HTCLOSE;
-  } else if (size_button_->visible() &&
-             ConvertPointToViewAndHitTest(this, size_button_, point)) {
-    return HTMAXBUTTON;
-  } else if (minimize_button_->visible() &&
-             ConvertPointToViewAndHitTest(this, minimize_button_, point)) {
-    return HTMINBUTTON;
-  } else if (menu_button_->visible() &&
-             ConvertPointToViewAndHitTest(this, menu_button_, point)) {
-    return HTMENU;
-  }
-  return HTNOWHERE;
-}
-
 void FrameCaptionButtonContainerView::UpdateCaptionButtonState(bool animate) {
   bool size_button_visible =
       (model_->IsVisible(CAPTION_BUTTON_ICON_MAXIMIZE_RESTORE) ||
diff --git a/ash/frame/caption_buttons/frame_caption_button_container_view.h b/ash/frame/caption_buttons/frame_caption_button_container_view.h
index 3d48344..27c7f66dc 100644
--- a/ash/frame/caption_buttons/frame_caption_button_container_view.h
+++ b/ash/frame/caption_buttons/frame_caption_button_container_view.h
@@ -93,11 +93,6 @@
   // Tell the window controls to reset themselves to the normal state.
   void ResetWindowControls();
 
-  // Determines the window HT* code for the caption button at |point|. Returns
-  // HTNOWHERE if |point| is not over any of the caption buttons. |point| must
-  // be in the coordinates of the FrameCaptionButtonContainerView.
-  int NonClientHitTest(const gfx::Point& point) const;
-
   // Updates the caption buttons' state based on the caption button model's
   // state. A parent view should relayout to reflect the change in states.
   void UpdateCaptionButtonState(bool animate);
diff --git a/ash/frame/caption_buttons/frame_size_button.cc b/ash/frame/caption_buttons/frame_size_button.cc
index 630ca590..4b3a8c8d 100644
--- a/ash/frame/caption_buttons/frame_size_button.cc
+++ b/ash/frame/caption_buttons/frame_size_button.cc
@@ -13,6 +13,7 @@
 #include "base/i18n/rtl.h"
 #include "base/metrics/user_metrics.h"
 #include "ui/aura/window.h"
+#include "ui/base/hit_test.h"
 #include "ui/gfx/geometry/vector2d.h"
 #include "ui/views/widget/widget.h"
 #include "ui/wm/core/coordinate_conversion.h"
@@ -48,7 +49,9 @@
 FrameSizeButton::FrameSizeButton(views::ButtonListener* listener,
                                  views::Widget* frame,
                                  FrameSizeButtonDelegate* delegate)
-    : FrameCaptionButton(listener, CAPTION_BUTTON_ICON_MAXIMIZE_RESTORE),
+    : FrameCaptionButton(listener,
+                         CAPTION_BUTTON_ICON_MAXIMIZE_RESTORE,
+                         HTMAXBUTTON),
       frame_(frame),
       delegate_(delegate),
       set_buttons_to_snap_mode_delay_ms_(kSetButtonsToSnapModeDelayMs),
diff --git a/ash/frame/custom_frame_view_ash.cc b/ash/frame/custom_frame_view_ash.cc
index 7da880d..3317b5b 100644
--- a/ash/frame/custom_frame_view_ash.cc
+++ b/ash/frame/custom_frame_view_ash.cc
@@ -11,9 +11,9 @@
 #include "ash/frame/caption_buttons/frame_caption_button.h"
 #include "ash/frame/caption_buttons/frame_caption_button_container_view.h"
 #include "ash/frame/default_frame_header.h"
-#include "ash/frame/frame_border_hit_test.h"
 #include "ash/frame/header_view.h"
 #include "ash/public/cpp/ash_constants.h"
+#include "ash/public/cpp/frame_border_hit_test.h"
 #include "ash/public/cpp/immersive/immersive_fullscreen_controller.h"
 #include "ash/public/cpp/immersive/immersive_fullscreen_controller_delegate.h"
 #include "ash/public/cpp/window_properties.h"
@@ -353,9 +353,7 @@
 }
 
 int CustomFrameViewAsh::NonClientHitTest(const gfx::Point& point) {
-  return FrameBorderNonClientHitTest(this, header_view_->GetBackButton(),
-                                     header_view_->caption_button_container(),
-                                     point);
+  return FrameBorderNonClientHitTest(this, point);
 }
 
 void CustomFrameViewAsh::GetWindowMask(const gfx::Size& size,
diff --git a/ash/frame/custom_frame_view_ash_unittest.cc b/ash/frame/custom_frame_view_ash_unittest.cc
index 6b4b50f..d7c5f140 100644
--- a/ash/frame/custom_frame_view_ash_unittest.cc
+++ b/ash/frame/custom_frame_view_ash_unittest.cc
@@ -494,6 +494,7 @@
   // back key sequence.
   generator->MoveMouseTo(
       header_view->GetBackButton()->GetBoundsInScreen().CenterPoint());
+
   generator->ClickLeftButton();
   EXPECT_EQ(1, target_back_press.accelerator_count());
   EXPECT_EQ(1, target_back_release.accelerator_count());
diff --git a/ash/frame/frame_border_hit_test.cc b/ash/frame/frame_border_hit_test.cc
deleted file mode 100644
index d3cf03b1..0000000
--- a/ash/frame/frame_border_hit_test.cc
+++ /dev/null
@@ -1,75 +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 "ash/frame/frame_border_hit_test.h"
-
-#include "ash/frame/caption_buttons/frame_caption_button_container_view.h"
-#include "ash/public/cpp/ash_constants.h"
-#include "ash/shell_port.h"
-#include "ui/base/hit_test.h"
-#include "ui/views/widget/widget.h"
-#include "ui/views/widget/widget_delegate.h"
-#include "ui/views/window/non_client_view.h"
-
-namespace ash {
-
-int FrameBorderNonClientHitTest(
-    views::NonClientFrameView* view,
-    const views::View* back_button,
-    const FrameCaptionButtonContainerView* caption_button_container,
-    const gfx::Point& point_in_widget) {
-  gfx::Rect expanded_bounds = view->bounds();
-  int outside_bounds = kResizeOutsideBoundsSize;
-
-  if (ShellPort::Get()->IsTouchDown())
-    outside_bounds *= kResizeOutsideBoundsScaleForTouch;
-  expanded_bounds.Inset(-outside_bounds, -outside_bounds);
-
-  if (!expanded_bounds.Contains(point_in_widget))
-    return HTNOWHERE;
-
-  // Check the frame first, as we allow a small area overlapping the contents
-  // to be used for resize handles.
-  views::Widget* frame = view->GetWidget();
-  bool can_ever_resize = frame->widget_delegate()->CanResize();
-  // Don't allow overlapping resize handles when the window is maximized or
-  // fullscreen, as it can't be resized in those states.
-  int resize_border = kResizeInsideBoundsSize;
-  if (frame->IsMaximized() || frame->IsFullscreen()) {
-    resize_border = 0;
-    can_ever_resize = false;
-  }
-  int frame_component = view->GetHTComponentForFrame(
-      point_in_widget, resize_border, resize_border, kResizeAreaCornerSize,
-      kResizeAreaCornerSize, can_ever_resize);
-  if (frame_component != HTNOWHERE)
-    return frame_component;
-
-  int client_component =
-      frame->client_view()->NonClientHitTest(point_in_widget);
-  if (client_component != HTNOWHERE)
-    return client_component;
-
-  if (caption_button_container->visible()) {
-    gfx::Point point_in_caption_button_container(point_in_widget);
-    views::View::ConvertPointFromWidget(caption_button_container,
-                                        &point_in_caption_button_container);
-    int caption_button_component = caption_button_container->NonClientHitTest(
-        point_in_caption_button_container);
-    if (caption_button_component != HTNOWHERE)
-      return caption_button_component;
-  }
-
-  if (back_button) {
-    gfx::Point point_in_back_button(point_in_widget);
-    views::View::ConvertPointFromWidget(back_button, &point_in_back_button);
-    // Using HTMENU as a placeholder to pass through the event to button.
-    if (back_button->GetLocalBounds().Contains(point_in_back_button))
-      return HTMENU;
-  }
-  // Caption is a safe default.
-  return HTCAPTION;
-}
-
-}  // namespace ash
diff --git a/ash/frame/frame_border_hit_test.h b/ash/frame/frame_border_hit_test.h
deleted file mode 100644
index f70d6173..0000000
--- a/ash/frame/frame_border_hit_test.h
+++ /dev/null
@@ -1,32 +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 ASH_FRAME_FRAME_BORDER_HIT_TEST_H_
-#define ASH_FRAME_FRAME_BORDER_HIT_TEST_H_
-
-#include "ash/ash_export.h"
-
-namespace gfx {
-class Point;
-}
-
-namespace views {
-class NonClientFrameView;
-class View;
-}
-
-namespace ash {
-
-class FrameCaptionButtonContainerView;
-
-// Returns the HitTestCompat for the specified point.
-ASH_EXPORT int FrameBorderNonClientHitTest(
-    views::NonClientFrameView* view,
-    const views::View* back_button,
-    const FrameCaptionButtonContainerView* caption_button_container,
-    const gfx::Point& point_in_widget);
-
-}  // namespace ash
-
-#endif  // ASH_FRAME_FRAME_BORDER_HIT_TEST_H_
diff --git a/ash/public/cpp/BUILD.gn b/ash/public/cpp/BUILD.gn
index 09658e0..77320d0 100644
--- a/ash/public/cpp/BUILD.gn
+++ b/ash/public/cpp/BUILD.gn
@@ -46,6 +46,8 @@
     "ash_typography.h",
     "ash_view_ids.h",
     "config.h",
+    "frame_border_hit_test.cc",
+    "frame_border_hit_test.h",
     "immersive/immersive_context.cc",
     "immersive/immersive_context.h",
     "immersive/immersive_focus_watcher.h",
diff --git a/ash/public/cpp/frame_border_hit_test.cc b/ash/public/cpp/frame_border_hit_test.cc
new file mode 100644
index 0000000..151d675
--- /dev/null
+++ b/ash/public/cpp/frame_border_hit_test.cc
@@ -0,0 +1,72 @@
+// 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 "ash/public/cpp/frame_border_hit_test.h"
+
+#include "ash/public/cpp/ash_constants.h"
+#include "ui/aura/env.h"
+#include "ui/base/hit_test.h"
+#include "ui/views/view_properties.h"
+#include "ui/views/widget/widget.h"
+#include "ui/views/widget/widget_delegate.h"
+#include "ui/views/window/non_client_view.h"
+
+namespace ash {
+
+int FrameBorderNonClientHitTest(views::NonClientFrameView* view,
+                                const gfx::Point& point_in_widget) {
+  gfx::Rect expanded_bounds = view->bounds();
+  int outside_bounds = kResizeOutsideBoundsSize;
+
+  if (aura::Env::GetInstance()->is_touch_down())
+    outside_bounds *= kResizeOutsideBoundsScaleForTouch;
+  expanded_bounds.Inset(-outside_bounds, -outside_bounds);
+
+  if (!expanded_bounds.Contains(point_in_widget))
+    return HTNOWHERE;
+
+  // Check the frame first, as we allow a small area overlapping the contents
+  // to be used for resize handles.
+  views::Widget* widget = view->GetWidget();
+  bool can_ever_resize = widget->widget_delegate()->CanResize();
+  // Don't allow overlapping resize handles when the window is maximized or
+  // fullscreen, as it can't be resized in those states.
+  int resize_border = kResizeInsideBoundsSize;
+  if (widget->IsMaximized() || widget->IsFullscreen()) {
+    resize_border = 0;
+    can_ever_resize = false;
+  }
+  int frame_component = view->GetHTComponentForFrame(
+      point_in_widget, resize_border, resize_border, kResizeAreaCornerSize,
+      kResizeAreaCornerSize, can_ever_resize);
+  if (frame_component != HTNOWHERE)
+    return frame_component;
+
+  int client_component =
+      widget->client_view()->NonClientHitTest(point_in_widget);
+  if (client_component != HTNOWHERE)
+    return client_component;
+
+  // Check if it intersects with children (frame caption button, back button,
+  // etc.).
+  gfx::Point point_in_non_client_view(point_in_widget);
+  views::View::ConvertPointFromWidget(widget->non_client_view(),
+                                      &point_in_non_client_view);
+  for (views::View* target_view =
+           widget->non_client_view()->GetEventHandlerForPoint(
+               point_in_non_client_view);
+       target_view; target_view = target_view->parent()) {
+    int target_component =
+        target_view->GetProperty(views::kHitTestComponentKey);
+    if (target_component != HTNOWHERE)
+      return target_component;
+    if (target_view == widget->non_client_view())
+      break;
+  }
+
+  // Caption is a safe default.
+  return HTCAPTION;
+}
+
+}  // namespace ash
diff --git a/ash/public/cpp/frame_border_hit_test.h b/ash/public/cpp/frame_border_hit_test.h
new file mode 100644
index 0000000..f5c7a76
--- /dev/null
+++ b/ash/public/cpp/frame_border_hit_test.h
@@ -0,0 +1,27 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef ASH_PUBLIC_CPP_FRAME_BORDER_HIT_TEST_H_
+#define ASH_PUBLIC_CPP_FRAME_BORDER_HIT_TEST_H_
+
+#include "ash/public/cpp/ash_public_export.h"
+
+namespace gfx {
+class Point;
+}
+
+namespace views {
+class NonClientFrameView;
+}  // namespace views
+
+namespace ash {
+
+// Returns the HitTestCompat for the specified point.
+ASH_PUBLIC_EXPORT int FrameBorderNonClientHitTest(
+    views::NonClientFrameView* view,
+    const gfx::Point& point_in_widget);
+
+}  // namespace ash
+
+#endif  // ASH_PUBLIC_CPP_FRAME_BORDER_HIT_TEST_H_
diff --git a/ash/shell/shell_delegate_impl.cc b/ash/shell/shell_delegate_impl.cc
index b50e206..e08334d 100644
--- a/ash/shell/shell_delegate_impl.cc
+++ b/ash/shell/shell_delegate_impl.cc
@@ -31,10 +31,6 @@
   return std::make_unique<TestKeyboardUI>();
 }
 
-NetworkingConfigDelegate* ShellDelegateImpl::GetNetworkingConfigDelegate() {
-  return nullptr;
-}
-
 std::unique_ptr<ash::ScreenshotDelegate>
 ShellDelegateImpl::CreateScreenshotDelegate() {
   return std::make_unique<TestScreenshotDelegate>();
diff --git a/ash/shell/shell_delegate_impl.h b/ash/shell/shell_delegate_impl.h
index 45a5c61..43a10bb5 100644
--- a/ash/shell/shell_delegate_impl.h
+++ b/ash/shell/shell_delegate_impl.h
@@ -28,7 +28,6 @@
   bool CanShowWindowForUser(aura::Window* window) const override;
   void PreInit() override;
   std::unique_ptr<keyboard::KeyboardUI> CreateKeyboardUI() override;
-  NetworkingConfigDelegate* GetNetworkingConfigDelegate() override;
   std::unique_ptr<ScreenshotDelegate> CreateScreenshotDelegate() override;
   AccessibilityDelegate* CreateAccessibilityDelegate() override;
   ui::InputDeviceControllerClient* GetInputDeviceControllerClient() override;
diff --git a/ash/shell_delegate.h b/ash/shell_delegate.h
index 49831b8..4c884765 100644
--- a/ash/shell_delegate.h
+++ b/ash/shell_delegate.h
@@ -31,7 +31,6 @@
 namespace ash {
 
 class AccessibilityDelegate;
-class NetworkingConfigDelegate;
 class ScreenshotDelegate;
 
 // Delegate of the Shell.
@@ -54,9 +53,6 @@
   // Create a shell-specific keyboard::KeyboardUI.
   virtual std::unique_ptr<keyboard::KeyboardUI> CreateKeyboardUI() = 0;
 
-  // Returns the delegate. May be null in tests.
-  virtual NetworkingConfigDelegate* GetNetworkingConfigDelegate() = 0;
-
   // TODO(jamescook): Replace with a mojo-compatible interface.
   virtual std::unique_ptr<ScreenshotDelegate> CreateScreenshotDelegate() = 0;
 
diff --git a/ash/shell_delegate_mash.cc b/ash/shell_delegate_mash.cc
index 21d36d09..bcd5ea4e 100644
--- a/ash/shell_delegate_mash.cc
+++ b/ash/shell_delegate_mash.cc
@@ -65,13 +65,6 @@
   return nullptr;
 }
 
-NetworkingConfigDelegate* ShellDelegateMash::GetNetworkingConfigDelegate() {
-  // TODO(mash): Provide a real implementation, perhaps by folding its behavior
-  // into an ash-side network information cache. http://crbug.com/651157
-  NOTIMPLEMENTED_LOG_ONCE();
-  return nullptr;
-}
-
 std::unique_ptr<ScreenshotDelegate>
 ShellDelegateMash::CreateScreenshotDelegate() {
   return std::make_unique<ScreenshotDelegateMash>();
diff --git a/ash/shell_delegate_mash.h b/ash/shell_delegate_mash.h
index 18f9fa7..2ae8231 100644
--- a/ash/shell_delegate_mash.h
+++ b/ash/shell_delegate_mash.h
@@ -26,7 +26,6 @@
   bool CanShowWindowForUser(aura::Window* window) const override;
   void PreInit() override;
   std::unique_ptr<keyboard::KeyboardUI> CreateKeyboardUI() override;
-  NetworkingConfigDelegate* GetNetworkingConfigDelegate() override;
   std::unique_ptr<ScreenshotDelegate> CreateScreenshotDelegate() override;
   AccessibilityDelegate* CreateAccessibilityDelegate() override;
   ui::InputDeviceControllerClient* GetInputDeviceControllerClient() override;
diff --git a/ash/system/network/network_list.cc b/ash/system/network/network_list.cc
index f1ec7ee..0b8cb3d7 100644
--- a/ash/system/network/network_list.cc
+++ b/ash/system/network/network_list.cc
@@ -21,7 +21,6 @@
 #include "ash/system/network/network_info.h"
 #include "ash/system/network/network_row_title_view.h"
 #include "ash/system/network/network_state_list_detailed_view.h"
-#include "ash/system/networking_config_delegate.h"
 #include "ash/system/power/power_status.h"
 #include "ash/system/tray/hover_highlight_view.h"
 #include "ash/system/tray/system_menu_button.h"
@@ -825,14 +824,10 @@
 
 views::View* NetworkListView::CreateControlledByExtensionView(
     const NetworkInfo& info) {
-  NetworkingConfigDelegate* networking_config_delegate =
-      Shell::Get()->shell_delegate()->GetNetworkingConfigDelegate();
-  if (!networking_config_delegate)
-    return nullptr;
-  std::unique_ptr<const NetworkingConfigDelegate::ExtensionInfo>
-      extension_info =
-          networking_config_delegate->LookUpExtensionForNetwork(info.guid);
-  if (!extension_info)
+  const chromeos::NetworkState* network =
+      NetworkHandler::Get()->network_state_handler()->GetNetworkStateFromGuid(
+          info.guid);
+  if (!network || !network->captive_portal_provider())
     return nullptr;
 
   views::ImageView* controlled_icon = TrayPopupUtils::CreateMainImageView();
@@ -840,7 +835,7 @@
       gfx::CreateVectorIcon(kCaptivePortalIcon, kMenuIconColor));
   controlled_icon->SetTooltipText(l10n_util::GetStringFUTF16(
       IDS_ASH_STATUS_TRAY_EXTENSION_CONTROLLED_WIFI,
-      base::UTF8ToUTF16(extension_info->extension_name)));
+      base::UTF8ToUTF16(network->captive_portal_provider()->name)));
   controlled_icon->set_id(VIEW_ID_EXTENSION_CONTROLLED_WIFI);
   return controlled_icon;
 }
diff --git a/ash/system/network/vpn_list_view.cc b/ash/system/network/vpn_list_view.cc
index aed8fc9..a703838 100644
--- a/ash/system/network/vpn_list_view.cc
+++ b/ash/system/network/vpn_list_view.cc
@@ -54,17 +54,19 @@
 // Indicates whether |network| belongs to this VPN provider.
 bool VpnProviderMatchesNetwork(const VPNProvider& provider,
                                const chromeos::NetworkState& network) {
-  // Never display non-VPN networks or ARC VPNs.
-  if (network.type() != shill::kTypeVPN)
+  const chromeos::NetworkState::VpnProviderInfo* network_vpn_provider =
+      network.vpn_provider();
+  // Never display non-VPN networks or VPNs with no provider info.
+  if (network.type() != shill::kTypeVPN || !network_vpn_provider)
     return false;
 
   // Package name is the vpn provider id for ArcVPNProvider in network state.
-  if (network.vpn_provider_type() == shill::kProviderArcVpn) {
+  if (network_vpn_provider->type == shill::kProviderArcVpn) {
     return provider.provider_type == VPNProvider::ARC_VPN &&
-           network.vpn_provider_id() == provider.package_name;
-  } else if (network.vpn_provider_type() == shill::kProviderThirdPartyVpn) {
+           network_vpn_provider->id == provider.package_name;
+  } else if (network_vpn_provider->type == shill::kProviderThirdPartyVpn) {
     return provider.provider_type == VPNProvider::THIRD_PARTY_VPN &&
-           network.vpn_provider_id() == provider.app_id;
+           network_vpn_provider->id == provider.app_id;
   } else {
     return provider.provider_type == VPNProvider::BUILT_IN_VPN;
   }
@@ -362,7 +364,7 @@
   for (const chromeos::NetworkState* const& network : networks) {
     if (!network->IsConnectingOrConnected())
       break;
-    if (network->vpn_provider_type() != shill::kProviderArcVpn)
+    if (network->GetVpnProviderType() != shill::kProviderArcVpn)
       continue;
 
     bool found_provider = false;
diff --git a/ash/system/networking_config_delegate.cc b/ash/system/networking_config_delegate.cc
deleted file mode 100644
index 55cb48b..0000000
--- a/ash/system/networking_config_delegate.cc
+++ /dev/null
@@ -1,15 +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 "ash/system/networking_config_delegate.h"
-
-namespace ash {
-
-NetworkingConfigDelegate::ExtensionInfo::ExtensionInfo(const std::string& id,
-                                                       const std::string& name)
-    : extension_id(id), extension_name(name) {}
-
-NetworkingConfigDelegate::ExtensionInfo::~ExtensionInfo() = default;
-
-}  // namespace ash
diff --git a/ash/system/networking_config_delegate.h b/ash/system/networking_config_delegate.h
deleted file mode 100644
index b040e70..0000000
--- a/ash/system/networking_config_delegate.h
+++ /dev/null
@@ -1,47 +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 ASH_SYSTEM_NETWORKING_CONFIG_DELEGATE_H_
-#define ASH_SYSTEM_NETWORKING_CONFIG_DELEGATE_H_
-
-#include <memory>
-#include <string>
-
-#include "ash/ash_export.h"
-#include "base/macros.h"
-
-namespace ash {
-
-// This delegate allows the UI code in ash, e.g. |NetworkStateListDetailedView|,
-// to access the |NetworkingConfigService| in order to determine whether the
-// configuration of a network identified by its |guid| is controlled by
-// an extension.
-// TODO(crbug.com/651157): Eliminate this delegate. Information about extension
-// controlled networks should be provided by a mojo service that caches data at
-// the NetworkState level.
-class NetworkingConfigDelegate {
- public:
-  // A struct that provides information about the extension controlling the
-  // configuration of a network.
-  struct ASH_EXPORT ExtensionInfo {
-    ExtensionInfo(const std::string& id, const std::string& name);
-    ~ExtensionInfo();
-    std::string extension_id;
-    std::string extension_name;
-  };
-
-  virtual ~NetworkingConfigDelegate() {}
-
-  // Returns information about the extension registered to control configuration
-  // of the network |guid|. Returns null if no extension is registered.
-  virtual std::unique_ptr<const ExtensionInfo> LookUpExtensionForNetwork(
-      const std::string& guid) = 0;
-
- private:
-  DISALLOW_ASSIGN(NetworkingConfigDelegate);
-};
-
-}  // namespace ash
-
-#endif  // ASH_SYSTEM_NETWORKING_CONFIG_DELEGATE_H_
diff --git a/ash/test_shell_delegate.cc b/ash/test_shell_delegate.cc
index 3fb790f..720a706f 100644
--- a/ash/test_shell_delegate.cc
+++ b/ash/test_shell_delegate.cc
@@ -31,10 +31,6 @@
   return std::make_unique<TestKeyboardUI>();
 }
 
-NetworkingConfigDelegate* TestShellDelegate::GetNetworkingConfigDelegate() {
-  return nullptr;
-}
-
 std::unique_ptr<ScreenshotDelegate>
 TestShellDelegate::CreateScreenshotDelegate() {
   return std::make_unique<TestScreenshotDelegate>();
diff --git a/ash/test_shell_delegate.h b/ash/test_shell_delegate.h
index 5577171f..ab05b16 100644
--- a/ash/test_shell_delegate.h
+++ b/ash/test_shell_delegate.h
@@ -22,7 +22,6 @@
   bool CanShowWindowForUser(aura::Window* window) const override;
   void PreInit() override;
   std::unique_ptr<keyboard::KeyboardUI> CreateKeyboardUI() override;
-  NetworkingConfigDelegate* GetNetworkingConfigDelegate() override;
   std::unique_ptr<ScreenshotDelegate> CreateScreenshotDelegate() override;
   AccessibilityDelegate* CreateAccessibilityDelegate() override;
   ui::InputDeviceControllerClient* GetInputDeviceControllerClient() override;
diff --git a/ash/wm/panels/panel_frame_view.cc b/ash/wm/panels/panel_frame_view.cc
index 8fc1912..a0c0c80e 100644
--- a/ash/wm/panels/panel_frame_view.cc
+++ b/ash/wm/panels/panel_frame_view.cc
@@ -6,8 +6,8 @@
 
 #include "ash/frame/caption_buttons/frame_caption_button_container_view.h"
 #include "ash/frame/default_frame_header.h"
-#include "ash/frame/frame_border_hit_test.h"
 #include "ash/public/cpp/ash_constants.h"
+#include "ash/public/cpp/frame_border_hit_test.h"
 #include "ash/shell.h"
 #include "ash/wm/resize_handle_window_targeter.h"
 #include "ash/wm/window_util.h"
@@ -123,8 +123,7 @@
 int PanelFrameView::NonClientHitTest(const gfx::Point& point) {
   if (!frame_header_)
     return HTNOWHERE;
-  return FrameBorderNonClientHitTest(this, nullptr, caption_button_container_,
-                                     point);
+  return FrameBorderNonClientHitTest(this, point);
 }
 
 void PanelFrameView::OnPaint(gfx::Canvas* canvas) {
diff --git a/base/post_task_and_reply_with_result_internal.h b/base/post_task_and_reply_with_result_internal.h
index 6f50de8..881f4bad 100644
--- a/base/post_task_and_reply_with_result_internal.h
+++ b/base/post_task_and_reply_with_result_internal.h
@@ -5,6 +5,7 @@
 #ifndef BASE_POST_TASK_AND_REPLY_WITH_RESULT_INTERNAL_H_
 #define BASE_POST_TASK_AND_REPLY_WITH_RESULT_INTERNAL_H_
 
+#include <memory>
 #include <utility>
 
 #include "base/callback.h"
@@ -16,15 +17,17 @@
 // Adapts a function that produces a result via a return value to
 // one that returns via an output parameter.
 template <typename ReturnType>
-void ReturnAsParamAdapter(OnceCallback<ReturnType()> func, ReturnType* result) {
-  *result = std::move(func).Run();
+void ReturnAsParamAdapter(OnceCallback<ReturnType()> func,
+                          std::unique_ptr<ReturnType>* result) {
+  result->reset(new ReturnType(std::move(func).Run()));
 }
 
 // Adapts a T* result to a callblack that expects a T.
 template <typename TaskReturnType, typename ReplyArgType>
 void ReplyAdapter(OnceCallback<void(ReplyArgType)> callback,
-                  TaskReturnType* result) {
-  std::move(callback).Run(std::move(*result));
+                  std::unique_ptr<TaskReturnType>* result) {
+  DCHECK(result->get());
+  std::move(callback).Run(std::move(**result));
 }
 
 }  // namespace internal
diff --git a/base/task/cancelable_task_tracker.h b/base/task/cancelable_task_tracker.h
index e5e6b5e..b7f6d3f 100644
--- a/base/task/cancelable_task_tracker.h
+++ b/base/task/cancelable_task_tracker.h
@@ -38,6 +38,7 @@
 
 #include <stdint.h>
 
+#include <memory>
 #include <utility>
 
 #include "base/base_export.h"
@@ -82,7 +83,7 @@
                                     const Location& from_here,
                                     OnceCallback<TaskReturnType()> task,
                                     OnceCallback<void(ReplyArgType)> reply) {
-    TaskReturnType* result = new TaskReturnType();
+    auto* result = new std::unique_ptr<TaskReturnType>();
     return PostTaskAndReply(
         task_runner, from_here,
         BindOnce(&internal::ReturnAsParamAdapter<TaskReturnType>,
diff --git a/base/task_runner_util.h b/base/task_runner_util.h
index d79f5b85..7ae085b 100644
--- a/base/task_runner_util.h
+++ b/base/task_runner_util.h
@@ -5,6 +5,7 @@
 #ifndef BASE_TASK_RUNNER_UTIL_H_
 #define BASE_TASK_RUNNER_UTIL_H_
 
+#include <memory>
 #include <utility>
 
 #include "base/bind.h"
@@ -37,7 +38,8 @@
                                 OnceCallback<void(ReplyArgType)> reply) {
   DCHECK(task);
   DCHECK(reply);
-  TaskReturnType* result = new TaskReturnType();
+  // std::unique_ptr used to avoid the need of a default constructor.
+  auto* result = new std::unique_ptr<TaskReturnType>();
   return task_runner->PostTaskAndReply(
       from_here,
       BindOnce(&internal::ReturnAsParamAdapter<TaskReturnType>, std::move(task),
diff --git a/base/task_runner_util_unittest.cc b/base/task_runner_util_unittest.cc
index 44baad47..c6d4997 100644
--- a/base/task_runner_util_unittest.cc
+++ b/base/task_runner_util_unittest.cc
@@ -66,6 +66,20 @@
   EXPECT_FALSE(foo.get());
 }
 
+struct FooWithoutDefaultConstructor {
+  explicit FooWithoutDefaultConstructor(int value) : value(value) {}
+  int value;
+};
+
+FooWithoutDefaultConstructor CreateFooWithoutDefaultConstructor(int value) {
+  return FooWithoutDefaultConstructor(value);
+}
+
+void SaveFooWithoutDefaultConstructor(int* output_value,
+                                      FooWithoutDefaultConstructor input) {
+  *output_value = input.value;
+}
+
 }  // namespace
 
 TEST(TaskRunnerHelpersTest, PostTaskAndReplyWithResult) {
@@ -73,8 +87,8 @@
 
   MessageLoop message_loop;
   PostTaskAndReplyWithResult(message_loop.task_runner().get(), FROM_HERE,
-                             Bind(&ReturnFourtyTwo),
-                             Bind(&StoreValue, &result));
+                             BindOnce(&ReturnFourtyTwo),
+                             BindOnce(&StoreValue, &result));
 
   RunLoop().RunUntilIdle();
 
@@ -86,8 +100,8 @@
 
   MessageLoop message_loop;
   PostTaskAndReplyWithResult(message_loop.task_runner().get(), FROM_HERE,
-                             Bind(&ReturnFourtyTwo),
-                             Bind(&StoreDoubleValue, &result));
+                             BindOnce(&ReturnFourtyTwo),
+                             BindOnce(&StoreDoubleValue, &result));
 
   RunLoop().RunUntilIdle();
 
@@ -100,7 +114,7 @@
 
   MessageLoop message_loop;
   PostTaskAndReplyWithResult(message_loop.task_runner().get(), FROM_HERE,
-                             Bind(&CreateFoo), Bind(&ExpectFoo));
+                             BindOnce(&CreateFoo), BindOnce(&ExpectFoo));
 
   RunLoop().RunUntilIdle();
 
@@ -114,7 +128,8 @@
 
   MessageLoop message_loop;
   PostTaskAndReplyWithResult(message_loop.task_runner().get(), FROM_HERE,
-                             Bind(&CreateScopedFoo), Bind(&ExpectScopedFoo));
+                             BindOnce(&CreateScopedFoo),
+                             BindOnce(&ExpectScopedFoo));
 
   RunLoop().RunUntilIdle();
 
@@ -122,4 +137,20 @@
   EXPECT_EQ(1, g_foo_free_count);
 }
 
+TEST(TaskRunnerHelpersTest,
+     PostTaskAndReplyWithResultWithoutDefaultConstructor) {
+  const int kSomeVal = 17;
+
+  MessageLoop message_loop;
+  int actual = 0;
+  PostTaskAndReplyWithResult(
+      message_loop.task_runner().get(), FROM_HERE,
+      BindOnce(&CreateFooWithoutDefaultConstructor, kSomeVal),
+      BindOnce(&SaveFooWithoutDefaultConstructor, &actual));
+
+  RunLoop().RunUntilIdle();
+
+  EXPECT_EQ(kSomeVal, actual);
+}
+
 }  // namespace base
diff --git a/base/task_scheduler/post_task.h b/base/task_scheduler/post_task.h
index d757c85..12c5b715 100644
--- a/base/task_scheduler/post_task.h
+++ b/base/task_scheduler/post_task.h
@@ -5,6 +5,7 @@
 #ifndef BASE_TASK_SCHEDULER_POST_TASK_H_
 #define BASE_TASK_SCHEDULER_POST_TASK_H_
 
+#include <memory>
 #include <utility>
 
 #include "base/base_export.h"
@@ -152,7 +153,7 @@
     const TaskTraits& traits,
     OnceCallback<TaskReturnType()> task,
     OnceCallback<void(ReplyArgType)> reply) {
-  TaskReturnType* result = new TaskReturnType();
+  auto* result = new std::unique_ptr<TaskReturnType>();
   return PostTaskWithTraitsAndReply(
       from_here, traits,
       BindOnce(&internal::ReturnAsParamAdapter<TaskReturnType>, std::move(task),
diff --git a/build/config/android/rules.gni b/build/config/android/rules.gni
index 2f558e39..eb0d633 100644
--- a/build/config/android/rules.gni
+++ b/build/config/android/rules.gni
@@ -2589,6 +2589,12 @@
                                ])
       }
     } else {
+      # placeholder native libraries never go into bundles, since they are
+      # only used for pre-L Android releases. Use the invoker variable to
+      # avoid GN errors when the target defines them.
+      assert(!defined(invoker.native_lib_placeholders) ||
+             invoker.native_lib_placeholders != [])
+
       _final_deps += [
                        ":$_merge_manifest_target",
                        ":$_build_config_target",
diff --git a/build/fuchsia/sdk.sha1 b/build/fuchsia/sdk.sha1
index ce4087c..d0c37bc 100644
--- a/build/fuchsia/sdk.sha1
+++ b/build/fuchsia/sdk.sha1
@@ -1 +1 @@
-0250d4201e9f4e1324362859cf38d37ba3f473d8
\ No newline at end of file
+c4a06fe7a901ee3c23359052bd7d9e448d8207ce
\ No newline at end of file
diff --git a/cc/animation/scroll_offset_animation_curve.cc b/cc/animation/scroll_offset_animation_curve.cc
index dad0ee2..39d75dc2 100644
--- a/cc/animation/scroll_offset_animation_curve.cc
+++ b/cc/animation/scroll_offset_animation_curve.cc
@@ -171,35 +171,37 @@
   return curve_clone;
 }
 
-static double VelocityBasedDurationBound(gfx::Vector2dF old_delta,
-                                         double old_normalized_velocity,
-                                         double old_duration,
-                                         gfx::Vector2dF new_delta) {
+static base::TimeDelta VelocityBasedDurationBound(
+    gfx::Vector2dF old_delta,
+    double old_normalized_velocity,
+    base::TimeDelta old_duration,
+    gfx::Vector2dF new_delta) {
   double old_delta_max_dimension = MaximumDimension(old_delta);
   double new_delta_max_dimension = MaximumDimension(new_delta);
 
   // If we are already at the target, stop animating.
   if (std::abs(new_delta_max_dimension) < kEpsilon)
-    return 0;
+    return base::TimeDelta();
 
   // Guard against division by zero.
   if (std::abs(old_delta_max_dimension) < kEpsilon ||
       std::abs(old_normalized_velocity) < kEpsilon) {
-    return std::numeric_limits<double>::infinity();
+    return base::TimeDelta::Max();
   }
 
   // Estimate how long it will take to reach the new target at our present
   // velocity, with some fudge factor to account for the "ease out".
-  double old_true_velocity =
-      old_normalized_velocity * old_delta_max_dimension / old_duration;
+  double old_true_velocity = old_normalized_velocity * old_delta_max_dimension /
+                             old_duration.InSecondsF();
   double bound = (new_delta_max_dimension / old_true_velocity) * 2.5f;
 
   // If bound < 0 we are moving in the opposite direction.
-  return bound < 0 ? std::numeric_limits<double>::infinity() : bound;
+  return bound < 0 ? base::TimeDelta::Max()
+                   : base::TimeDelta::FromSecondsD(bound);
 }
 
 void ScrollOffsetAnimationCurve::UpdateTarget(
-    double t,
+    base::TimeDelta t,
     const gfx::ScrollOffset& new_target) {
   if (std::abs(MaximumDimension(target_value_.DeltaFrom(new_target))) <
       kEpsilon) {
@@ -207,41 +209,38 @@
     return;
   }
 
-  base::TimeDelta delayed_by = base::TimeDelta::FromSecondsD(
-      std::max(0.0, last_retarget_.InSecondsF() - t));
-  t = std::max(t, last_retarget_.InSecondsF());
+  base::TimeDelta delayed_by = std::max(base::TimeDelta(), last_retarget_ - t);
+  t = std::max(t, last_retarget_);
 
-  gfx::ScrollOffset current_position =
-      GetValue(base::TimeDelta::FromSecondsD(t));
+  gfx::ScrollOffset current_position = GetValue(t);
   gfx::Vector2dF old_delta = target_value_.DeltaFrom(initial_value_);
   gfx::Vector2dF new_delta = new_target.DeltaFrom(current_position);
 
   // The last segement was of zero duration.
   if ((total_animation_duration_ - last_retarget_).is_zero()) {
-    DCHECK_EQ(t, last_retarget_.InSecondsF());
+    DCHECK_EQ(t, last_retarget_);
     total_animation_duration_ =
         SegmentDuration(new_delta, duration_behavior_, delayed_by);
     target_value_ = new_target;
     return;
   }
 
-  double old_duration =
-      (total_animation_duration_ - last_retarget_).InSecondsF();
+  base::TimeDelta old_duration = total_animation_duration_ - last_retarget_;
   double old_normalized_velocity = timing_function_->Velocity(
-      (t - last_retarget_.InSecondsF()) / old_duration);
+      ((t - last_retarget_).InSecondsF()) / old_duration.InSecondsF());
 
   // Use the velocity-based duration bound when it is less than the constant
   // segment duration. This minimizes the "rubber-band" bouncing effect when
   // old_normalized_velocity is large and new_delta is small.
-  double new_duration = std::min(
-      SegmentDuration(new_delta, duration_behavior_, delayed_by).InSecondsF(),
-      VelocityBasedDurationBound(old_delta, old_normalized_velocity,
-                                 old_duration, new_delta));
+  base::TimeDelta new_duration =
+      std::min(SegmentDuration(new_delta, duration_behavior_, delayed_by),
+               VelocityBasedDurationBound(old_delta, old_normalized_velocity,
+                                          old_duration, new_delta));
 
-  if (new_duration < kEpsilon) {
+  if (new_duration.InSecondsF() < kEpsilon) {
     // We are already at or very close to the new target. Stop animating.
     target_value_ = new_target;
-    total_animation_duration_ = base::TimeDelta::FromSecondsD(t);
+    total_animation_duration_ = t;
     return;
   }
 
@@ -249,13 +248,14 @@
   // To match the "true" velocity in px/sec we must adjust this slope for
   // differences in duration and scroll delta between old and new curves.
   double new_normalized_velocity =
-      old_normalized_velocity * (new_duration / old_duration) *
+      old_normalized_velocity *
+      (new_duration.InSecondsF() / old_duration.InSecondsF()) *
       (MaximumDimension(old_delta) / MaximumDimension(new_delta));
 
   initial_value_ = current_position;
   target_value_ = new_target;
-  total_animation_duration_ = base::TimeDelta::FromSecondsD(t + new_duration);
-  last_retarget_ = base::TimeDelta::FromSecondsD(t);
+  total_animation_duration_ = t + new_duration;
+  last_retarget_ = t;
   timing_function_ = EaseOutWithInitialVelocity(new_normalized_velocity);
 }
 
diff --git a/cc/animation/scroll_offset_animation_curve.h b/cc/animation/scroll_offset_animation_curve.h
index d471d2b..6924c1e 100644
--- a/cc/animation/scroll_offset_animation_curve.h
+++ b/cc/animation/scroll_offset_animation_curve.h
@@ -59,7 +59,7 @@
   // relative to the start of the animation.  The duration is recomputed based
   // on the DurationBehavior the curve was constructed with.  The timing
   // function is an ease-in-out cubic bezier modified to preserve velocity at t.
-  void UpdateTarget(double t, const gfx::ScrollOffset& new_target);
+  void UpdateTarget(base::TimeDelta t, const gfx::ScrollOffset& new_target);
 
   // Shifts the entire curve by a delta without affecting its shape or timing.
   // Used for scroll anchoring adjustments that happen during scroll animations
diff --git a/cc/animation/scroll_offset_animation_curve_unittest.cc b/cc/animation/scroll_offset_animation_curve_unittest.cc
index 522ea2d..cd308a70 100644
--- a/cc/animation/scroll_offset_animation_curve_unittest.cc
+++ b/cc/animation/scroll_offset_animation_curve_unittest.cc
@@ -148,7 +148,8 @@
               curve->GetValue(base::TimeDelta::FromSecondsD(duration)).y(),
               0.0002f);
 
-  curve->UpdateTarget(duration / 2, gfx::ScrollOffset(0.0, 9900.0));
+  curve->UpdateTarget(base::TimeDelta::FromSecondsD(duration / 2),
+                      gfx::ScrollOffset(0.0, 9900.0));
 
   EXPECT_NEAR(duration * 1.5, curve->Duration().InSecondsF(), 0.0002f);
   EXPECT_NEAR(
@@ -163,7 +164,8 @@
       curve->GetValue(base::TimeDelta::FromSecondsD(duration * 1.5)).y(),
       0.0002f);
 
-  curve->UpdateTarget(duration, gfx::ScrollOffset(0.0, 7200.0));
+  curve->UpdateTarget(base::TimeDelta::FromSecondsD(duration),
+                      gfx::ScrollOffset(0.0, 7200.0));
 
   // A closer target at high velocity reduces the duration.
   EXPECT_NEAR(duration * 1.0794, curve->Duration().InSecondsF(), 0.0002f);
@@ -187,16 +189,19 @@
   curve->SetInitialValue(gfx::ScrollOffset());
   double smallDeltaDuration = curve->Duration().InSecondsF();
 
-  curve->UpdateTarget(0.01f, gfx::ScrollOffset(0.f, 300.f));
+  curve->UpdateTarget(base::TimeDelta::FromSecondsD(0.01f),
+                      gfx::ScrollOffset(0.f, 300.f));
   double mediumDeltaDuration = curve->Duration().InSecondsF();
 
-  curve->UpdateTarget(0.01f, gfx::ScrollOffset(0.f, 500.f));
+  curve->UpdateTarget(base::TimeDelta::FromSecondsD(0.01f),
+                      gfx::ScrollOffset(0.f, 500.f));
   double largeDeltaDuration = curve->Duration().InSecondsF();
 
   EXPECT_GT(smallDeltaDuration, mediumDeltaDuration);
   EXPECT_GT(mediumDeltaDuration, largeDeltaDuration);
 
-  curve->UpdateTarget(0.01f, gfx::ScrollOffset(0.f, 5000.f));
+  curve->UpdateTarget(base::TimeDelta::FromSecondsD(0.01f),
+                      gfx::ScrollOffset(0.f, 5000.f));
   EXPECT_EQ(largeDeltaDuration, curve->Duration().InSecondsF());
 }
 
@@ -215,7 +220,8 @@
                          base::TimeDelta::FromSecondsD(delay_in_seconds));
   EXPECT_NEAR(curve_duration, curve->Duration().InSecondsF(), 0.0002f);
 
-  curve->UpdateTarget(0.01f, gfx::ScrollOffset(0.f, 500.f));
+  curve->UpdateTarget(base::TimeDelta::FromSecondsD(0.01f),
+                      gfx::ScrollOffset(0.f, 500.f));
   EXPECT_GT(curve_duration, curve->Duration().InSecondsF());
   EXPECT_EQ(gfx::ScrollOffset(0.f, 500.f), curve->target_value());
 }
@@ -232,7 +238,8 @@
   EXPECT_EQ(0.f, curve->Duration().InSecondsF());
 
   // Re-targeting when animation duration is 0.
-  curve->UpdateTarget(-0.01, gfx::ScrollOffset(0.f, 300.f));
+  curve->UpdateTarget(base::TimeDelta::FromSecondsD(-0.01),
+                      gfx::ScrollOffset(0.f, 300.f));
   double duration =
       ScrollOffsetAnimationCurve::SegmentDuration(
           gfx::Vector2dF(0.f, 200.f),
@@ -243,7 +250,8 @@
 
   // Re-targeting before last_retarget_, the  difference should be accounted for
   // in duration.
-  curve->UpdateTarget(-0.01, gfx::ScrollOffset(0.f, 500.f));
+  curve->UpdateTarget(base::TimeDelta::FromSecondsD(-0.01),
+                      gfx::ScrollOffset(0.f, 500.f));
   duration = ScrollOffsetAnimationCurve::SegmentDuration(
                  gfx::Vector2dF(0.f, 500.f),
                  ScrollOffsetAnimationCurve::DurationBehavior::INVERSE_DELTA,
@@ -283,13 +291,15 @@
           base::TimeDelta())
           .InSecondsF() +
       0.05;
-  curve->UpdateTarget(0.05, gfx::ScrollOffset(0.f, 200.f));
+  curve->UpdateTarget(base::TimeDelta::FromSecondsD(0.05),
+                      gfx::ScrollOffset(0.f, 200.f));
   EXPECT_NEAR(expected_duration, curve->Duration().InSecondsF(), 0.0002f);
 
   // Re-target 2, this should set total_animation_duration to t, which is
   // last_retarget_. This is what would cause the DCHECK failure in
   // crbug.com/645317.
-  curve->UpdateTarget(-0.145, gfx::ScrollOffset(0.f, 300.f));
+  curve->UpdateTarget(base::TimeDelta::FromSecondsD(-0.145),
+                      gfx::ScrollOffset(0.f, 300.f));
   EXPECT_NEAR(0.05, curve->Duration().InSecondsF(), 0.0002f);
 
   // Re-target 3, this should set total_animation_duration based on new_delta.
@@ -301,7 +311,8 @@
           ScrollOffsetAnimationCurve::DurationBehavior::INVERSE_DELTA,
           base::TimeDelta::FromSecondsD(0.15))
           .InSecondsF();
-  curve->UpdateTarget(-0.1, gfx::ScrollOffset(0.f, 500.f));
+  curve->UpdateTarget(base::TimeDelta::FromSecondsD(-0.1),
+                      gfx::ScrollOffset(0.f, 500.f));
   EXPECT_NEAR(expected_duration, curve->Duration().InSecondsF(), 0.0002f);
 }
 
diff --git a/cc/animation/scroll_offset_animations_impl.cc b/cc/animation/scroll_offset_animations_impl.cc
index 2e1a274..00ce5bf 100644
--- a/cc/animation/scroll_offset_animations_impl.cc
+++ b/cc/animation/scroll_offset_animations_impl.cc
@@ -110,7 +110,7 @@
   // t = -delayed_by.
   trimmed -= delayed_by;
 
-  curve->UpdateTarget(trimmed.InSecondsF(), new_target);
+  curve->UpdateTarget(trimmed, new_target);
   TRACE_EVENT_INSTANT1("cc", "ScrollAnimationUpdateTarget",
                        TRACE_EVENT_SCOPE_THREAD, "UpdatedDuration",
                        curve->Duration().InMillisecondsF());
diff --git a/cc/input/input_handler.h b/cc/input/input_handler.h
index a3530604..807f140 100644
--- a/cc/input/input_handler.h
+++ b/cc/input/input_handler.h
@@ -16,6 +16,7 @@
 #include "cc/input/scroll_state.h"
 #include "cc/input/scrollbar.h"
 #include "cc/input/touch_action.h"
+#include "cc/trees/element_id.h"
 #include "cc/trees/swap_promise_monitor.h"
 
 namespace gfx {
@@ -227,10 +228,11 @@
   virtual ScrollElasticityHelper* CreateScrollElasticityHelper() = 0;
 
   // Called by the single-threaded UI Compositor to get or set the scroll offset
-  // on the impl side. Retruns false if |layer_id| isn't in the active tree.
-  virtual bool GetScrollOffsetForLayer(int layer_id,
+  // on the impl side. Returns false if |element_id| isn't in the active tree.
+  virtual bool GetScrollOffsetForLayer(ElementId element_id,
                                        gfx::ScrollOffset* offset) = 0;
-  virtual bool ScrollLayerTo(int layer_id, const gfx::ScrollOffset& offset) = 0;
+  virtual bool ScrollLayerTo(ElementId element_id,
+                             const gfx::ScrollOffset& offset) = 0;
 
   virtual bool ScrollingShouldSwitchtoMainThread() = 0;
 
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc
index ebdb74e..cffc4df 100644
--- a/cc/trees/layer_tree_host_impl.cc
+++ b/cc/trees/layer_tree_host_impl.cc
@@ -813,24 +813,28 @@
   return scroll_elasticity_helper_.get();
 }
 
-bool LayerTreeHostImpl::GetScrollOffsetForLayer(int layer_id,
+bool LayerTreeHostImpl::GetScrollOffsetForLayer(ElementId element_id,
                                                 gfx::ScrollOffset* offset) {
-  LayerImpl* layer = active_tree()->FindActiveTreeLayerById(layer_id);
-  if (!layer)
+  ScrollTree& scroll_tree = active_tree()->property_trees()->scroll_tree;
+  ScrollNode* scroll_node = scroll_tree.FindNodeFromElementId(element_id);
+  if (!scroll_node)
     return false;
-
-  *offset = layer->CurrentScrollOffset();
+  *offset = scroll_tree.current_scroll_offset(element_id);
   return true;
 }
 
-bool LayerTreeHostImpl::ScrollLayerTo(int layer_id,
+bool LayerTreeHostImpl::ScrollLayerTo(ElementId element_id,
                                       const gfx::ScrollOffset& offset) {
-  LayerImpl* layer = active_tree()->FindActiveTreeLayerById(layer_id);
-  if (!layer)
+  ScrollTree& scroll_tree = active_tree()->property_trees()->scroll_tree;
+  ScrollNode* scroll_node = scroll_tree.FindNodeFromElementId(element_id);
+  if (!scroll_node)
     return false;
 
-  layer->ScrollBy(
-      ScrollOffsetToVector2dF(offset - layer->CurrentScrollOffset()));
+  scroll_tree.ScrollBy(
+      scroll_node,
+      ScrollOffsetToVector2dF(offset -
+                              scroll_tree.current_scroll_offset(element_id)),
+      active_tree());
   return true;
 }
 
diff --git a/cc/trees/layer_tree_host_impl.h b/cc/trees/layer_tree_host_impl.h
index 862fcaf7..a4b2e504 100644
--- a/cc/trees/layer_tree_host_impl.h
+++ b/cc/trees/layer_tree_host_impl.h
@@ -283,9 +283,10 @@
   std::unique_ptr<SwapPromiseMonitor> CreateLatencyInfoSwapPromiseMonitor(
       ui::LatencyInfo* latency) override;
   ScrollElasticityHelper* CreateScrollElasticityHelper() override;
-  bool GetScrollOffsetForLayer(int layer_id,
+  bool GetScrollOffsetForLayer(ElementId element_id,
                                gfx::ScrollOffset* offset) override;
-  bool ScrollLayerTo(int layer_id, const gfx::ScrollOffset& offset) override;
+  bool ScrollLayerTo(ElementId element_id,
+                     const gfx::ScrollOffset& offset) override;
   bool ScrollingShouldSwitchtoMainThread() override;
 
   // BrowserControlsOffsetManagerClient implementation.
diff --git a/cc/trees/property_tree.cc b/cc/trees/property_tree.cc
index d94e2fe..45f7556 100644
--- a/cc/trees/property_tree.cc
+++ b/cc/trees/property_tree.cc
@@ -1243,6 +1243,14 @@
 }
 #endif
 
+ScrollNode* ScrollTree::FindNodeFromElementId(ElementId id) {
+  auto iterator = property_trees()->element_id_to_scroll_node_index.find(id);
+  if (iterator == property_trees()->element_id_to_scroll_node_index.end())
+    return nullptr;
+
+  return Node(iterator->second);
+}
+
 const ScrollNode* ScrollTree::FindNodeFromElementId(ElementId id) const {
   auto iterator = property_trees()->element_id_to_scroll_node_index.find(id);
   if (iterator == property_trees()->element_id_to_scroll_node_index.end())
diff --git a/cc/trees/property_tree.h b/cc/trees/property_tree.h
index 39dac92370..a41eb36f 100644
--- a/cc/trees/property_tree.h
+++ b/cc/trees/property_tree.h
@@ -460,6 +460,7 @@
   void CopyCompleteTreeState(const ScrollTree& other);
 #endif
 
+  ScrollNode* FindNodeFromElementId(ElementId id);
   const ScrollNode* FindNodeFromElementId(ElementId id) const;
 
  private:
diff --git a/chrome/android/java/res/layout/password_accessory_sheet_suggestion.xml b/chrome/android/java/res/layout/password_accessory_sheet_suggestion.xml
index 621d041..d7cbb66 100644
--- a/chrome/android/java/res/layout/password_accessory_sheet_suggestion.xml
+++ b/chrome/android/java/res/layout/password_accessory_sheet_suggestion.xml
@@ -5,11 +5,11 @@
 
 <TextView
     xmlns:android="http://schemas.android.com/apk/res/android"
-    android:paddingTop="8dp"
-    android:paddingBottom="8dp"
-    android:paddingStart="52dp"
-    android:paddingEnd="16dp"
+    android:id="@+id/suggestion_text"
+    android:layout_marginStart="@dimen/keyboard_accessory_suggestion_margin"
+    android:paddingEnd="@dimen/keyboard_accessory_suggestion_margin"
+    android:gravity="center_vertical|start"
     android:fillViewport="true"
-    android:layout_height="48dp"
+    android:layout_height="@dimen/keyboard_accessory_suggestion_height"
     android:textAppearance="@style/BlackTitle1"
     android:layout_width="match_parent"/>
\ No newline at end of file
diff --git a/chrome/android/java/res/values/dimens.xml b/chrome/android/java/res/values/dimens.xml
index 052adae..d28a612 100644
--- a/chrome/android/java/res/values/dimens.xml
+++ b/chrome/android/java/res/values/dimens.xml
@@ -129,6 +129,9 @@
     <dimen name="keyboard_accessory_padding">6dp</dimen>
     <dimen name="keyboard_accessory_sheet_height">330dp</dimen>
     <dimen name="keyboard_accessory_text_size">14sp</dimen>
+    <dimen name="keyboard_accessory_suggestion_margin">16dp</dimen>
+    <dimen name="keyboard_accessory_suggestion_height">48dp</dimen>
+    <dimen name="keyboard_accessory_suggestion_icon_size">20dp</dimen>
 
     <!-- Password generation popup dimensions -->
     <dimen name="password_generation_divider_height">1dp</dimen>
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/DefaultBrowserInfo.java b/chrome/android/java/src/org/chromium/chrome/browser/DefaultBrowserInfo.java
index 361c3f33..0717dffa 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/DefaultBrowserInfo.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/DefaultBrowserInfo.java
@@ -173,10 +173,10 @@
                 .isStartupSuccessfullyCompleted();
 
         try {
-            new AsyncTask<Context, Void, DefaultInfo>() {
+            new AsyncTask<Void, Void, DefaultInfo>() {
                 @Override
-                protected DefaultInfo doInBackground(Context... params) {
-                    Context context = params[0];
+                protected DefaultInfo doInBackground(Void... params) {
+                    Context context = ContextUtils.getApplicationContext();
 
                     PackageManager pm = context.getPackageManager();
 
@@ -222,8 +222,7 @@
                             getDefaultBrowserUmaState(info), MobileDefaultBrowserState.NUM_ENTRIES);
                 }
             }
-                    .executeOnExecutor(
-                            AsyncTask.THREAD_POOL_EXECUTOR, ContextUtils.getApplicationContext());
+                    .executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
         } catch (RejectedExecutionException ex) {
             // Fail silently here since this is not a critical task.
         }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryData.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryData.java
index a5055965..a31b40c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryData.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryData.java
@@ -4,6 +4,7 @@
 
 package org.chromium.chrome.browser.autofill.keyboard_accessory;
 
+import android.graphics.Bitmap;
 import android.graphics.drawable.Drawable;
 import android.support.annotation.LayoutRes;
 import android.support.annotation.Nullable;
@@ -146,6 +147,19 @@
         private final String mContentDescription;
         private final boolean mIsPassword;
         private final @Nullable Callback<Item> mItemSelectedCallback;
+        private final @Nullable FaviconProvider mFaviconProvider;
+
+        /**
+         * Items will call a class that implements this interface to request a favicon.
+         */
+        interface FaviconProvider {
+            /**
+             * Starts a request for a favicon. The callback can be called either asynchronously or
+             * synchronously (depending on whether the icon was cached).
+             * @param favicon The icon to be used for this Item. If null, use the default icon.
+             */
+            void fetchFavicon(Callback<Bitmap> favicon);
+        }
 
         /**
          * Creates a new Item of type {@link ItemType#LABEL}. It is not interactive.
@@ -153,8 +167,9 @@
          * @param contentDescription The description of this item (i.e. used for accessibility).
          */
         public static Item createLabel(String caption, String contentDescription) {
-            return new Item(ItemType.LABEL, caption, contentDescription, false, null);
+            return new Item(ItemType.LABEL, caption, contentDescription, false, null, null);
         }
+
         /**
          * Creates a new Item of type {@link ItemType#SUGGESTION} if has a callback, otherwise, it
          * will be {@link ItemType#NON_INTERACTIVE_SUGGESTION}. It usually is part of a list of
@@ -165,20 +180,21 @@
          * @param itemSelectedCallback A click on this item will invoke this callback. Optional.
          */
         public static Item createSuggestion(String caption, String contentDescription,
-                boolean isPassword, @Nullable Callback<Item> itemSelectedCallback) {
+                boolean isPassword, @Nullable Callback<Item> itemSelectedCallback,
+                @Nullable FaviconProvider faviconProvider) {
             if (itemSelectedCallback == null) {
                 return new Item(ItemType.NON_INTERACTIVE_SUGGESTION, caption, contentDescription,
-                        isPassword, null);
+                        isPassword, null, faviconProvider);
             }
             return new Item(ItemType.SUGGESTION, caption, contentDescription, isPassword,
-                    itemSelectedCallback);
+                    itemSelectedCallback, faviconProvider);
         }
 
         /**
          * Creates an Item of type {@link ItemType#DIVIDER}. Basically, it's a horizontal line.
          */
         public static Item createDivider() {
-            return new Item(ItemType.DIVIDER, null, null, false, null);
+            return new Item(ItemType.DIVIDER, null, null, false, null, null);
         }
 
         /**
@@ -190,7 +206,7 @@
          */
         public static Item createOption(
                 String caption, String contentDescription, Callback<Item> callback) {
-            return new Item(ItemType.OPTION, caption, contentDescription, false, callback);
+            return new Item(ItemType.OPTION, caption, contentDescription, false, callback, null);
         }
 
         /**
@@ -200,14 +216,17 @@
          * @param contentDescription The description of this item (i.e. used for accessibility).
          * @param isPassword If true, the displayed caption is transformed into stars.
          * @param itemSelectedCallback If the Item is interactive, a click on it will trigger this.
+         * @param faviconProvider
          */
         private Item(@ItemType int type, String caption, String contentDescription,
-                boolean isPassword, @Nullable Callback<Item> itemSelectedCallback) {
+                boolean isPassword, @Nullable Callback<Item> itemSelectedCallback,
+                @Nullable FaviconProvider faviconProvider) {
             mType = type;
             mCaption = caption;
             mContentDescription = contentDescription;
             mIsPassword = isPassword;
             mItemSelectedCallback = itemSelectedCallback;
+            mFaviconProvider = faviconProvider;
         }
 
         /**
@@ -249,6 +268,14 @@
         public Callback<Item> getItemSelectedCallback() {
             return mItemSelectedCallback;
         }
+
+        public void fetchFavicon(Callback<Bitmap> faviconCallback) {
+            if (mFaviconProvider == null) {
+                faviconCallback.onResult(null); // Use default icon without provider.
+                return;
+            }
+            mFaviconProvider.fetchFavicon(faviconCallback);
+        }
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessoryBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessoryBridge.java
index ddc1283..ba35074 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessoryBridge.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessoryBridge.java
@@ -4,8 +4,10 @@
 
 package org.chromium.chrome.browser.autofill.keyboard_accessory;
 
+import android.graphics.Bitmap;
 import android.support.annotation.Nullable;
 
+import org.chromium.base.Callback;
 import org.chromium.base.annotations.CalledByNative;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeActivity;
@@ -92,11 +94,11 @@
                                         != 0 : "Controller was destroyed but the bridge wasn't!";
                                 nativeOnFillingTriggered(
                                         mNativeView, item.isPassword(), item.getCaption());
-                            });
+                            }, this::fetchFavicon);
                     continue;
                 case ItemType.NON_INTERACTIVE_SUGGESTION:
                     items[i] = Item.createSuggestion(
-                            text[i], description[i], isPassword[i] == 1, null);
+                            text[i], description[i], isPassword[i] == 1, null, this::fetchFavicon);
                     continue;
                 case ItemType.DIVIDER:
                     items[i] = Item.createDivider();
@@ -113,6 +115,13 @@
         return items;
     }
 
+    public void fetchFavicon(Callback<Bitmap> faviconCallback) {
+        assert mNativeView != 0 : "Favicon was requested after the bridge was destroyed!";
+        nativeOnFaviconRequested(mNativeView, faviconCallback);
+    }
+
+    private native void nativeOnFaviconRequested(
+            long nativePasswordAccessoryViewAndroid, Callback<Bitmap> faviconCallback);
     private native void nativeOnFillingTriggered(
             long nativePasswordAccessoryViewAndroid, boolean isPassword, String textToFill);
     private native void nativeOnOptionSelected(
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessorySheetCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessorySheetCoordinator.java
index 7d5d49a4..0341e215 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessorySheetCoordinator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessorySheetCoordinator.java
@@ -5,7 +5,9 @@
 package org.chromium.chrome.browser.autofill.keyboard_accessory;
 
 import android.content.Context;
+import android.graphics.Bitmap;
 import android.graphics.drawable.Drawable;
+import android.support.annotation.Nullable;
 import android.support.v7.content.res.AppCompatResources;
 import android.support.v7.widget.RecyclerView;
 import android.view.View;
@@ -56,6 +58,11 @@
         }
     }
 
+    interface FaviconProvider {
+        @Nullable
+        Bitmap getFavicon();
+    }
+
     /**
      * Creates the passwords tab.
      * @param context The {@link Context} containing resources like icons and layouts for this tab.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessorySheetViewBinder.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessorySheetViewBinder.java
index 02b3782..f212860 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessorySheetViewBinder.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessorySheetViewBinder.java
@@ -4,6 +4,12 @@
 
 package org.chromium.chrome.browser.autofill.keyboard_accessory;
 
+import android.graphics.Bitmap;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.support.annotation.Nullable;
+import android.support.v4.view.MarginLayoutParamsCompat;
+import android.support.v7.content.res.AppCompatResources;
 import android.support.v7.widget.LinearLayoutManager;
 import android.support.v7.widget.RecyclerView;
 import android.text.method.PasswordTransformationMethod;
@@ -12,6 +18,7 @@
 import android.view.ViewGroup;
 import android.widget.TextView;
 
+import org.chromium.base.ApiCompatibilityUtils;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryData.Item;
 import org.chromium.chrome.browser.modelutil.RecyclerViewAdapter;
@@ -39,7 +46,7 @@
                                             false));
                 case ItemType.SUGGESTION: // Intentional fallthrough.
                 case ItemType.NON_INTERACTIVE_SUGGESTION: {
-                    return new TextViewHolder(
+                    return new IconTextViewHolder(
                             LayoutInflater.from(parent.getContext())
                                     .inflate(R.layout.password_accessory_sheet_suggestion, parent,
                                             false));
@@ -79,24 +86,82 @@
          * Returns the text view of this item if there is one.
          * @return Returns a {@link TextView}.
          */
-        private TextView getTextView() {
+        protected TextView getTextView() {
             return (TextView) itemView;
         }
 
         @Override
         protected void bind(Item item) {
             super.bind(item);
-            if (item.isPassword()) {
-                getTextView().setTransformationMethod(new PasswordTransformationMethod());
-            }
+            getTextView().setTransformationMethod(
+                    item.isPassword() ? new PasswordTransformationMethod() : null);
             getTextView().setText(item.getCaption());
             if (item.getItemSelectedCallback() != null) {
                 getTextView().setOnClickListener(
                         src -> item.getItemSelectedCallback().onResult(item));
+            } else {
+                getTextView().setOnClickListener(null);
             }
         }
     }
 
+    /**
+     * Holds a TextView that represents a list entry.
+     */
+    static class IconTextViewHolder extends TextViewHolder {
+        private final TextView mSuggestionText;
+        private final int mMargin;
+        private final int mIconSize;
+
+        IconTextViewHolder(View itemView) {
+            super(itemView);
+            mSuggestionText = itemView.findViewById(R.id.suggestion_text);
+            mMargin = itemView.getContext().getResources().getDimensionPixelSize(
+                    R.dimen.keyboard_accessory_suggestion_margin);
+            mIconSize = itemView.getContext().getResources().getDimensionPixelSize(
+                    R.dimen.keyboard_accessory_suggestion_icon_size);
+        }
+
+        @Override
+        protected TextView getTextView() {
+            return mSuggestionText;
+        }
+
+        @Override
+        protected void bind(Item item) {
+            super.bind(item);
+            ViewGroup.MarginLayoutParams params =
+                    new ViewGroup.MarginLayoutParams(mSuggestionText.getLayoutParams());
+            MarginLayoutParamsCompat.setMarginEnd(params, mMargin);
+            if (!item.isPassword()) {
+                setIconForBitmap(null); // Set the default icon, then try to get a better one.
+                item.fetchFavicon(this::setIconForBitmap);
+                MarginLayoutParamsCompat.setMarginStart(params, mMargin);
+            } else {
+                ApiCompatibilityUtils.setCompoundDrawablesRelative(
+                        mSuggestionText, null, null, null, null);
+                MarginLayoutParamsCompat.setMarginStart(params, 2 * mMargin + mIconSize);
+            }
+            mSuggestionText.setLayoutParams(params);
+        }
+
+        private void setIconForBitmap(@Nullable Bitmap favicon) {
+            Drawable icon;
+            if (favicon == null) {
+                icon = AppCompatResources.getDrawable(
+                        itemView.getContext(), R.drawable.ic_globe_36dp);
+            } else {
+                icon = new BitmapDrawable(itemView.getContext().getResources(), favicon);
+            }
+            if (icon != null) { // AppCompatResources.getDrawable is @Nullable.
+                icon.setBounds(0, 0, mIconSize, mIconSize);
+            }
+            mSuggestionText.setCompoundDrawablePadding(mMargin);
+            ApiCompatibilityUtils.setCompoundDrawablesRelative(
+                    mSuggestionText, icon, null, null, null);
+        }
+    }
+
     static void initializeView(RecyclerView view, RecyclerViewAdapter adapter) {
         view.setLayoutManager(
                 new LinearLayoutManager(view.getContext(), LinearLayoutManager.VERTICAL, false));
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/home/glue/FileDeletionQueue.java b/chrome/android/java/src/org/chromium/chrome/browser/download/home/glue/FileDeletionQueue.java
index 3afdd20..aa5691b7 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/home/glue/FileDeletionQueue.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/home/glue/FileDeletionQueue.java
@@ -67,22 +67,25 @@
 
         System.out.println("dtrainor: Starting " + file.getName());
 
-        mTask = new FileDeletionTask();
-        mTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, file);
+        mTask = new FileDeletionTask(file);
+        mTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
     }
 
-    private class FileDeletionTask extends AsyncTask<File, Void, Void> {
-        // AsyncTask implementation.
+    private class FileDeletionTask extends AsyncTask<Void, Void, Void> {
+        private final File mFile;
+
+        FileDeletionTask(File file) {
+            mFile = file;
+        }
+
         @Override
-        protected Void doInBackground(File... params) {
-            System.out.println("dtrainor: Deleting " + params[0].getName());
-            mDeleter.onResult(params[0]);
+        protected Void doInBackground(Void... params) {
+            mDeleter.onResult(mFile);
             return null;
         }
 
         @Override
         protected void onPostExecute(Void result) {
-            System.out.println("dtrainor: Post");
             super.onPostExecute(result);
             mTask = null;
             deleteNextFile();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/feedback/ConnectivityChecker.java b/chrome/android/java/src/org/chromium/chrome/browser/feedback/ConnectivityChecker.java
index d4dd0ee4..67bc6eaa 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/feedback/ConnectivityChecker.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/feedback/ConnectivityChecker.java
@@ -95,9 +95,9 @@
             postResult(callback, ConnectivityCheckResult.ERROR);
             return;
         }
-        new AsyncTask<String, Void, Integer>() {
+        new AsyncTask<Void, Void, Integer>() {
             @Override
-            protected Integer doInBackground(String... strings) {
+            protected Integer doInBackground(Void... params) {
                 try {
                     HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                     conn.setInstanceFollowRedirects(false);
@@ -127,7 +127,8 @@
             protected void onPostExecute(Integer result) {
                 callback.onResult(result);
             }
-        }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+        }
+                .executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/sync/SyncController.java b/chrome/android/java/src/org/chromium/chrome/browser/sync/SyncController.java
index fa83255..1f626503 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/sync/SyncController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/sync/SyncController.java
@@ -66,13 +66,11 @@
     private static SyncController sInstance;
     private static boolean sInitialized;
 
-    private final Context mContext;
     private final ChromeSigninController mChromeSigninController;
     private final ProfileSyncService mProfileSyncService;
     private final SyncNotificationController mSyncNotificationController;
 
-    private SyncController(Context context) {
-        mContext = context;
+    private SyncController() {
         mChromeSigninController = ChromeSigninController.get();
         AndroidSyncSettings.registerObserver(this);
         mProfileSyncService = ProfileSyncService.get();
@@ -89,7 +87,7 @@
 
         // Create the SyncNotificationController.
         mSyncNotificationController = new SyncNotificationController(
-                mContext, PassphraseActivity.class, AccountManagementFragment.class);
+                PassphraseActivity.class, AccountManagementFragment.class);
         mProfileSyncService.addSyncStateChangedListener(mSyncNotificationController);
 
         updateSyncStateFromAndroid();
@@ -123,15 +121,14 @@
     /**
      * Retrieve the singleton instance of this class.
      *
-     * @param context the current context.
      * @return the singleton instance.
      */
     @Nullable
-    public static SyncController get(Context context) {
+    public static SyncController get() {
         ThreadUtils.assertOnUiThread();
         if (!sInitialized) {
             if (ProfileSyncService.get() != null) {
-                sInstance = new SyncController(context.getApplicationContext());
+                sInstance = new SyncController();
             }
             sInitialized = true;
         }
@@ -139,6 +136,16 @@
     }
 
     /**
+     * Retrieve the singleton instance of this class.
+     * @deprecated Use get with no arguments instead.
+     * @return the singleton instance.
+     */
+    @Nullable
+    public static SyncController get(Context context) {
+        return get();
+    }
+
+    /**
      * Updates sync to reflect the state of the Android sync settings.
      */
     private void updateSyncStateFromAndroid() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/sync/SyncNotificationController.java b/chrome/android/java/src/org/chromium/chrome/browser/sync/SyncNotificationController.java
index 147e52f..09ad6399a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/sync/SyncNotificationController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/sync/SyncNotificationController.java
@@ -14,6 +14,7 @@
 import android.content.Intent;
 import android.util.Log;
 
+import org.chromium.base.ContextUtils;
 import org.chromium.base.ThreadUtils;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.notifications.ChromeNotificationBuilder;
@@ -32,18 +33,15 @@
  */
 public class SyncNotificationController implements ProfileSyncService.SyncStateChangedListener {
     private static final String TAG = "SyncNotificationController";
-    private final Context mApplicationContext;
     private final NotificationManagerProxy mNotificationManager;
     private final Class<? extends Activity> mPassphraseRequestActivity;
     private final Class<? extends Fragment> mAccountManagementFragment;
     private final ProfileSyncService mProfileSyncService;
 
-    public SyncNotificationController(Context context,
-            Class<? extends Activity> passphraseRequestActivity,
+    public SyncNotificationController(Class<? extends Activity> passphraseRequestActivity,
             Class<? extends Fragment> accountManagementFragment) {
-        mApplicationContext = context.getApplicationContext();
         mNotificationManager = new NotificationManagerProxyImpl(
-                (NotificationManager) mApplicationContext.getSystemService(
+                (NotificationManager) ContextUtils.getApplicationContext().getSystemService(
                         Context.NOTIFICATION_SERVICE));
         mProfileSyncService = ProfileSyncService.get();
         assert mProfileSyncService != null;
@@ -95,11 +93,12 @@
      * @param intent Intent to send when the user activates the notification.
      */
     private void showSyncNotification(int message, Intent intent) {
-        String title = mApplicationContext.getString(R.string.app_name);
-        String text = mApplicationContext.getString(R.string.sign_in_sync) + ": "
-                + mApplicationContext.getString(message);
+        Context applicationContext = ContextUtils.getApplicationContext();
+        String title = applicationContext.getString(R.string.app_name);
+        String text = applicationContext.getString(R.string.sign_in_sync) + ": "
+                + applicationContext.getString(message);
 
-        PendingIntent contentIntent = PendingIntent.getActivity(mApplicationContext, 0, intent, 0);
+        PendingIntent contentIntent = PendingIntent.getActivity(applicationContext, 0, intent, 0);
 
         // There is no need to provide a group summary notification because the NOTIFICATION_ID_SYNC
         // notification id ensures there's only one sync notification at a time.
@@ -151,8 +150,8 @@
      * @return the intent for opening the settings
      */
     private Intent createSettingsIntent() {
-        return PreferencesLauncher.createIntentForSettingsPage(
-                mApplicationContext, mAccountManagementFragment.getCanonicalName());
+        return PreferencesLauncher.createIntentForSettingsPage(ContextUtils.getApplicationContext(),
+                mAccountManagementFragment.getCanonicalName());
     }
 
     /**
@@ -165,7 +164,8 @@
         mProfileSyncService.setPassphrasePrompted(true);
 
         Intent intent = new Intent(Intent.ACTION_MAIN);
-        intent.setComponent(new ComponentName(mApplicationContext, mPassphraseRequestActivity));
+        intent.setComponent(new ComponentName(
+                ContextUtils.getApplicationContext(), mPassphraseRequestActivity));
         intent.addCategory(Intent.CATEGORY_LAUNCHER);
         // This activity will become the start of a new task on this history stack.
         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/sync/ui/PassphraseActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/sync/ui/PassphraseActivity.java
index 4146eee..98365b3 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/sync/ui/PassphraseActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/sync/ui/PassphraseActivity.java
@@ -138,7 +138,7 @@
     @Override
     public void onPassphraseCanceled() {
         // Re add the notification.
-        SyncController.get(this).getSyncNotificationController().syncStateChanged();
+        SyncController.get().getSyncNotificationController().syncStateChanged();
         finish();
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheet.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheet.java
index 04ec30d..abc60bf 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheet.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheet.java
@@ -77,10 +77,14 @@
          * transitioning between states.
          */
         int NONE = -1;
+        // Values are used for indexing mStateRatios, should start from 0
+        // and can't have gaps. Additionally order is important for these,
+        // they go from smallest to largest.
         int HIDDEN = 0;
         int PEEK = 1;
         int HALF = 2;
         int FULL = 3;
+
         int SCROLLING = 4;
     }
 
@@ -141,8 +145,6 @@
      * Information about the different scroll states of the sheet. Order is important for these,
      * they go from smallest to largest.
      */
-    private static final int[] sStates =
-            new int[] {SheetState.HIDDEN, SheetState.PEEK, SheetState.HALF, SheetState.FULL};
     private final float[] mStateRatios = new float[4];
 
     /** The interpolator that the height animator uses. */
@@ -1405,7 +1407,7 @@
      */
     @SheetState
     private int getTargetSheetState(float sheetHeight, float yVelocity) {
-        if (sheetHeight <= getMinOffsetPx()) return sStates[getMinSwipableSheetState()];
+        if (sheetHeight <= getMinOffsetPx()) return getMinSwipableSheetState();
         if (sheetHeight >= getMaxOffsetPx()) return SheetState.FULL;
 
         boolean isMovingDownward = yVelocity < 0;
@@ -1413,15 +1415,15 @@
 
         // First, find the two states that the sheet height is between.
         @SheetState
-        int nextState = sStates[getMinSwipableSheetState()];
+        int nextState = getMinSwipableSheetState();
 
         @SheetState
         int prevState = nextState;
-        for (int i = getMinSwipableSheetState(); i < sStates.length; i++) {
-            if (sStates[i] == SheetState.HALF && shouldSkipHalfState) continue;
-            if (sStates[i] == SheetState.PEEK && !mSheetContent.isPeekStateEnabled()) continue;
+        for (@SheetState int i = getMinSwipableSheetState(); i <= SheetState.FULL; i++) {
+            if (i == SheetState.HALF && shouldSkipHalfState) continue;
+            if (i == SheetState.PEEK && !mSheetContent.isPeekStateEnabled()) continue;
             prevState = nextState;
-            nextState = sStates[i];
+            nextState = i;
             // The values in PanelState are ascending, they should be kept that way in order for
             // this to work.
             if (sheetHeight >= getSheetHeightForState(prevState)
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessoryIntegrationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessoryIntegrationTest.java
index b605cc7..4300a02 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessoryIntegrationTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessoryIntegrationTest.java
@@ -222,10 +222,10 @@
     }
 
     private static Item createSuggestion(String caption, Callback<Item> callback) {
-        return Item.createSuggestion(caption, "Description_" + caption, false, callback);
+        return Item.createSuggestion(caption, "Description_" + caption, false, callback, null);
     }
 
     private static Item createPassword(String caption) {
-        return Item.createSuggestion(caption, "Description_" + caption, true, null);
+        return Item.createSuggestion(caption, "Description_" + caption, true, null, null);
     }
 }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessorySheetViewTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessorySheetViewTest.java
index 0fe63e6..87b287a 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessorySheetViewTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessorySheetViewTest.java
@@ -110,15 +110,13 @@
         ThreadUtils.runOnUiThreadBlocking(
                 ()
                         -> mModel.add(Item.createSuggestion(
-                                "Name Suggestion", null, false, item -> clicked.set(true))));
+                                "Name Suggestion", null, false, item -> clicked.set(true), null)));
 
         CriteriaHelper.pollUiThread(Criteria.equals(1, () -> mView.get().getChildCount()));
-        assertThat(mView.get().getChildAt(0), instanceOf(TextView.class));
 
-        TextView suggestion = (TextView) mView.get().getChildAt(0);
-        assertThat(suggestion.getText(), is("Name Suggestion"));
+        assertThat(getFirstSuggestion().getText(), is("Name Suggestion"));
 
-        ThreadUtils.runOnUiThreadBlocking(suggestion::performClick);
+        ThreadUtils.runOnUiThreadBlocking(getFirstSuggestion()::performClick);
         assertThat(clicked.get(), is(true));
     }
 
@@ -130,18 +128,21 @@
 
         ThreadUtils.runOnUiThreadBlocking(
                 ()
-                        -> mModel.add(Item.createSuggestion(
-                                "Password Suggestion", null, true, item -> clicked.set(true))));
+                        -> mModel.add(Item.createSuggestion("Password Suggestion", null, true,
+                                item -> clicked.set(true), null)));
 
         CriteriaHelper.pollUiThread(Criteria.equals(1, () -> mView.get().getChildCount()));
-        assertThat(mView.get().getChildAt(0), instanceOf(TextView.class));
 
-        TextView suggestion = (TextView) mView.get().getChildAt(0);
-        assertThat(suggestion.getText(), is("Password Suggestion"));
-        assertThat(suggestion.getTransformationMethod(),
+        assertThat(getFirstSuggestion().getText(), is("Password Suggestion"));
+        assertThat(getFirstSuggestion().getTransformationMethod(),
                 instanceOf(PasswordTransformationMethod.class));
 
-        ThreadUtils.runOnUiThreadBlocking(suggestion::performClick);
+        ThreadUtils.runOnUiThreadBlocking(getFirstSuggestion()::performClick);
         assertThat(clicked.get(), is(true));
     }
+
+    private TextView getFirstSuggestion() {
+        assertThat(mView.get().getChildAt(0), instanceOf(TextView.class));
+        return (TextView) mView.get().getChildAt(0);
+    }
 }
\ No newline at end of file
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/notifications/NotificationPlatformBridgeTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/notifications/NotificationPlatformBridgeTest.java
index 2dd1876..6c147390 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/notifications/NotificationPlatformBridgeTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/notifications/NotificationPlatformBridgeTest.java
@@ -33,7 +33,6 @@
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.metrics.RecordHistogram;
 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.MinAndroidSdkLevel;
 import org.chromium.base.test.util.RetryOnFailure;
@@ -41,20 +40,19 @@
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeSwitches;
 import org.chromium.chrome.browser.engagement.SiteEngagementService;
-import org.chromium.chrome.browser.infobar.InfoBar;
+import org.chromium.chrome.browser.permissions.PermissionDialogController;
+import org.chromium.chrome.browser.permissions.PermissionTestRule;
 import org.chromium.chrome.browser.preferences.PrefServiceBridge;
 import org.chromium.chrome.browser.preferences.website.ContentSetting;
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.widget.RoundedIconGenerator;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
-import org.chromium.chrome.test.util.InfoBarUtil;
 import org.chromium.chrome.test.util.browser.TabTitleObserver;
 import org.chromium.chrome.test.util.browser.notifications.MockNotificationManagerProxy.NotificationEntry;
 import org.chromium.components.url_formatter.UrlFormatter;
 import org.chromium.content.browser.test.util.Criteria;
 import org.chromium.content.browser.test.util.CriteriaHelper;
-import org.chromium.net.test.EmbeddedTestServerRule;
 
 import java.net.URL;
 import java.util.ArrayList;
@@ -73,7 +71,7 @@
 @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
 public class NotificationPlatformBridgeTest {
     @Rule
-    public EmbeddedTestServerRule mEmbeddedTestServerRule = new EmbeddedTestServerRule();
+    public PermissionTestRule mPermissionTestRule = new PermissionTestRule();
 
     @Rule
     public NotificationTestRule mNotificationTestRule = new NotificationTestRule();
@@ -85,8 +83,8 @@
     @Before
     public void setUp() throws Exception {
         SiteEngagementService.setParamValuesForTesting();
-        mNotificationTestRule.loadUrl(
-                mEmbeddedTestServerRule.getServer().getURL(NOTIFICATION_TEST_PAGE));
+        mNotificationTestRule.loadUrl(mPermissionTestRule.getURL(NOTIFICATION_TEST_PAGE));
+        mPermissionTestRule.setActivity(mNotificationTestRule.getActivity());
     }
 
     @SuppressWarnings("MissingFail")
@@ -102,31 +100,11 @@
         }
     }
 
-    private InfoBar getInfobarBlocking() {
-        CriteriaHelper.pollUiThread(new Criteria() {
-            @Override
-            public boolean isSatisfied() {
-                return !mNotificationTestRule.getInfoBars().isEmpty();
-            }
-        });
-        List<InfoBar> infoBars = mNotificationTestRule.getInfoBars();
-        Assert.assertEquals(1, infoBars.size());
-        return infoBars.get(0);
-    }
-
-    private void waitForInfobarToClose() {
-        CriteriaHelper.pollUiThread(new Criteria() {
-            @Override
-            public boolean isSatisfied() {
-                return mNotificationTestRule.getInfoBars().isEmpty();
-            }
-        });
-        Assert.assertEquals(0, mNotificationTestRule.getInfoBars().size());
-    }
-
     private void checkThatShowNotificationIsDenied() throws Exception {
         showNotification("MyNotification", "{}");
-        waitForTitle("TypeError: No notification permission has been granted for this origin.");
+        waitForTitle(
+                "TypeError: Failed to execute 'showNotification' on 'ServiceWorkerRegistration': "
+                + "No notification permission has been granted for this origin.");
 
         // Ideally we'd wait a little here, but it's hard to wait for things that shouldn't happen.
         Assert.assertTrue(mNotificationTestRule.getNotificationEntries().isEmpty());
@@ -138,7 +116,7 @@
                 @Override
                 public Double call() throws Exception {
                     return SiteEngagementService.getForProfile(Profile.getLastUsedProfile())
-                            .getScore(mEmbeddedTestServerRule.getOrigin());
+                            .getScore(mPermissionTestRule.getOrigin());
                 }
             });
         } catch (ExecutionException ex) {
@@ -151,52 +129,36 @@
      * Verifies that notifcations cannot be shown without permission, and that dismissing or denying
      * the infobar works correctly.
      */
-    //@LargeTest
-    //@Feature({"Browser", "Notifications"})
-    // crbug.com/707528
+    @LargeTest
+    @Feature({"Browser", "Notifications"})
     @Test
-    @DisabledTest
     public void testPermissionDenied() throws Exception {
         // Notifications permission should initially be prompt, and showing should fail.
         Assert.assertEquals("\"default\"", runJavaScript("Notification.permission"));
         checkThatShowNotificationIsDenied();
 
-        // Notification.requestPermission() should show the notifications infobar.
-        Assert.assertEquals(0, mNotificationTestRule.getInfoBars().size());
-        runJavaScript("Notification.requestPermission(sendToTest)");
-        InfoBar infoBar = getInfobarBlocking();
+        PermissionTestRule.PermissionUpdateWaiter updateWaiter =
+                new PermissionTestRule.PermissionUpdateWaiter(
+                        "denied: ", mNotificationTestRule.getActivity());
 
-        // Dismissing the infobar should pass prompt to the requestPermission callback.
-        Assert.assertTrue(InfoBarUtil.clickCloseButton(infoBar));
-        waitForInfobarToClose();
-        waitForTitle("default"); // See https://crbug.com/434547.
+        mNotificationTestRule.getActivity().getActivityTab().addObserver(updateWaiter);
 
-        // Notifications permission should still be prompt.
-        Assert.assertEquals("\"default\"", runJavaScript("Notification.permission"));
-        checkThatShowNotificationIsDenied();
-
-        // Notification.requestPermission() should show the notifications infobar again.
-        runJavaScript("Notification.requestPermission(sendToTest)");
-        infoBar = getInfobarBlocking();
-
-        // Denying the infobar should pass denied to the requestPermission callback.
-        Assert.assertTrue(InfoBarUtil.clickSecondaryButton(infoBar));
-        waitForInfobarToClose();
-        waitForTitle("denied");
+        mPermissionTestRule.runDenyTest(updateWaiter, NOTIFICATION_TEST_PAGE,
+                "Notification.requestPermission(addCountAndSendToTest)", 1, false, true);
 
         // This should have caused notifications permission to become denied.
         Assert.assertEquals("\"denied\"", runJavaScript("Notification.permission"));
         checkThatShowNotificationIsDenied();
 
         // Reload page to ensure the block is persisted.
-        mNotificationTestRule.loadUrl(
-                mEmbeddedTestServerRule.getServer().getURL(NOTIFICATION_TEST_PAGE));
+        mNotificationTestRule.loadUrl(mPermissionTestRule.getURL(NOTIFICATION_TEST_PAGE));
 
         // Notification.requestPermission() should immediately pass denied to the callback without
-        // showing an infobar.
+        // showing a dialog.
         runJavaScript("Notification.requestPermission(sendToTest)");
         waitForTitle("denied");
-        Assert.assertEquals(0, mNotificationTestRule.getInfoBars().size());
+        Assert.assertEquals(
+                null, PermissionDialogController.getInstance().getCurrentDialogForTesting());
 
         // Notifications permission should still be denied.
         Assert.assertEquals("\"denied\"", runJavaScript("Notification.permission"));
@@ -206,29 +168,25 @@
     /**
      * Verifies granting permission via the infobar.
      */
-    //@MediumTest
-    //@Feature({"Browser", "Notifications"})
-    // crbug.com/707528
+    @MediumTest
+    @Feature({"Browser", "Notifications"})
     @Test
-    @DisabledTest
     public void testPermissionGranted() throws Exception {
         // Notifications permission should initially be prompt, and showing should fail.
         Assert.assertEquals("\"default\"", runJavaScript("Notification.permission"));
         checkThatShowNotificationIsDenied();
 
-        // Notification.requestPermission() should show the notifications infobar.
-        Assert.assertEquals(0, mNotificationTestRule.getInfoBars().size());
-        runJavaScript("Notification.requestPermission(sendToTest)");
-        InfoBar infoBar = getInfobarBlocking();
+        PermissionTestRule.PermissionUpdateWaiter updateWaiter =
+                new PermissionTestRule.PermissionUpdateWaiter(
+                        "granted: ", mNotificationTestRule.getActivity());
 
-        // Accepting the infobar should pass granted to the requestPermission callback.
-        Assert.assertTrue(InfoBarUtil.clickPrimaryButton(infoBar));
-        waitForInfobarToClose();
-        waitForTitle("granted");
+        mNotificationTestRule.getActivity().getActivityTab().addObserver(updateWaiter);
+
+        mPermissionTestRule.runAllowTest(updateWaiter, NOTIFICATION_TEST_PAGE,
+                "Notification.requestPermission(addCountAndSendToTest)", 1, false, true);
 
         // Reload page to ensure the grant is persisted.
-        mNotificationTestRule.loadUrl(
-                mEmbeddedTestServerRule.getServer().getURL(NOTIFICATION_TEST_PAGE));
+        mNotificationTestRule.loadUrl(mPermissionTestRule.getURL(NOTIFICATION_TEST_PAGE));
 
         // Notifications permission should now be granted, and showing should succeed.
         Assert.assertEquals("\"granted\"", runJavaScript("Notification.permission"));
@@ -245,13 +203,13 @@
     @RetryOnFailure
     public void testDefaultNotificationProperties() throws Exception {
         mNotificationTestRule.setNotificationContentSettingForOrigin(
-                ContentSetting.ALLOW, mEmbeddedTestServerRule.getOrigin());
+                ContentSetting.ALLOW, mPermissionTestRule.getOrigin());
         Context context = InstrumentationRegistry.getTargetContext();
 
         Notification notification = showAndGetNotification("MyNotification", "{body: 'Hello'}");
 
-        String expectedOrigin = UrlFormatter.formatUrlForSecurityDisplayOmitScheme(
-                mEmbeddedTestServerRule.getOrigin());
+        String expectedOrigin =
+                UrlFormatter.formatUrlForSecurityDisplayOmitScheme(mPermissionTestRule.getOrigin());
 
         // Validate the contents of the notification.
         Assert.assertEquals("MyNotification", NotificationTestUtil.getExtraTitle(notification));
@@ -309,7 +267,7 @@
     @Feature({"Browser", "Notifications"})
     public void testShowNotificationWithTextAction() throws Exception {
         mNotificationTestRule.setNotificationContentSettingForOrigin(
-                ContentSetting.ALLOW, mEmbeddedTestServerRule.getOrigin());
+                ContentSetting.ALLOW, mPermissionTestRule.getOrigin());
 
         Notification notification = showAndGetNotification("MyNotification",
                 "{ "
@@ -340,7 +298,7 @@
     @Feature({"Browser", "Notifications"})
     public void testReplyToNotification() throws Exception {
         mNotificationTestRule.setNotificationContentSettingForOrigin(
-                ContentSetting.ALLOW, mEmbeddedTestServerRule.getOrigin());
+                ContentSetting.ALLOW, mPermissionTestRule.getOrigin());
         Context context = InstrumentationRegistry.getTargetContext();
 
         UserActionTester actionTester = new UserActionTester();
@@ -388,7 +346,7 @@
     @Feature({"Browser", "Notifications"})
     public void testReplyToNotificationWithEmptyReply() throws Exception {
         mNotificationTestRule.setNotificationContentSettingForOrigin(
-                ContentSetting.ALLOW, mEmbeddedTestServerRule.getOrigin());
+                ContentSetting.ALLOW, mPermissionTestRule.getOrigin());
         Context context = InstrumentationRegistry.getTargetContext();
 
         // +0.5 engagement from navigating to the test page.
@@ -448,7 +406,7 @@
     @Feature({"Browser", "Notifications"})
     public void testReplyToNotificationWithNoRemoteInput() throws Exception {
         mNotificationTestRule.setNotificationContentSettingForOrigin(
-                ContentSetting.ALLOW, mEmbeddedTestServerRule.getOrigin());
+                ContentSetting.ALLOW, mPermissionTestRule.getOrigin());
 
         // +0.5 engagement from navigating to the test page.
         Assert.assertEquals(0.5, getEngagementScoreBlocking(), 0);
@@ -475,7 +433,7 @@
     @Feature({"Browser", "Notifications"})
     public void testNotificationRenotifyProperty() throws Exception {
         mNotificationTestRule.setNotificationContentSettingForOrigin(
-                ContentSetting.ALLOW, mEmbeddedTestServerRule.getOrigin());
+                ContentSetting.ALLOW, mPermissionTestRule.getOrigin());
 
         Notification notification =
                 showAndGetNotification("MyNotification", "{ tag: 'myTag', renotify: true }");
@@ -492,7 +450,7 @@
     @Feature({"Browser", "Notifications"})
     public void testNotificationSilentProperty() throws Exception {
         mNotificationTestRule.setNotificationContentSettingForOrigin(
-                ContentSetting.ALLOW, mEmbeddedTestServerRule.getOrigin());
+                ContentSetting.ALLOW, mPermissionTestRule.getOrigin());
 
         Notification notification = showAndGetNotification("MyNotification", "{ silent: true }");
 
@@ -503,7 +461,7 @@
     private void verifyVibrationNotRequestedWhenDisabledInPrefs(String notificationOptions)
             throws Exception {
         mNotificationTestRule.setNotificationContentSettingForOrigin(
-                ContentSetting.ALLOW, mEmbeddedTestServerRule.getOrigin());
+                ContentSetting.ALLOW, mPermissionTestRule.getOrigin());
 
         // Disable notification vibration in preferences.
         ThreadUtils.runOnUiThreadBlocking(new Runnable() {
@@ -557,7 +515,7 @@
     @Feature({"Browser", "Notifications"})
     public void testNotificationVibrateCustomPattern() throws Exception {
         mNotificationTestRule.setNotificationContentSettingForOrigin(
-                ContentSetting.ALLOW, mEmbeddedTestServerRule.getOrigin());
+                ContentSetting.ALLOW, mPermissionTestRule.getOrigin());
 
         // By default, vibration is enabled in notifications.
         ThreadUtils.runOnUiThreadBlocking(new Runnable() {
@@ -590,7 +548,7 @@
     @Feature({"Browser", "Notifications"})
     public void testShowNotificationWithBadge() throws Exception {
         mNotificationTestRule.setNotificationContentSettingForOrigin(
-                ContentSetting.ALLOW, mEmbeddedTestServerRule.getOrigin());
+                ContentSetting.ALLOW, mPermissionTestRule.getOrigin());
 
         Notification notification =
                 showAndGetNotification("MyNotification", "{badge: 'badge.png'}");
@@ -604,8 +562,8 @@
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
             // Custom badges are only supported on M+.
             // 1. Check the notification badge.
-            URL badgeUrl = new URL(mEmbeddedTestServerRule.getServer().getURL(
-                    "/chrome/test/data/notifications/badge.png"));
+            URL badgeUrl = new URL(
+                    mPermissionTestRule.getURL("/chrome/test/data/notifications/badge.png"));
             Bitmap bitmap = BitmapFactory.decodeStream(badgeUrl.openStream());
             Bitmap expected = bitmap.copy(bitmap.getConfig(), true);
             NotificationBuilderBase.applyWhiteOverlayToBitmap(expected);
@@ -644,7 +602,7 @@
     @RetryOnFailure
     public void testShowNotificationWithIcon() throws Exception {
         mNotificationTestRule.setNotificationContentSettingForOrigin(
-                ContentSetting.ALLOW, mEmbeddedTestServerRule.getOrigin());
+                ContentSetting.ALLOW, mPermissionTestRule.getOrigin());
 
         Notification notification = showAndGetNotification("MyNotification", "{icon: 'red.png'}");
 
@@ -667,7 +625,7 @@
     @RetryOnFailure
     public void testShowNotificationWithoutIcon() throws Exception {
         mNotificationTestRule.setNotificationContentSettingForOrigin(
-                ContentSetting.ALLOW, mEmbeddedTestServerRule.getOrigin());
+                ContentSetting.ALLOW, mPermissionTestRule.getOrigin());
 
         Notification notification = showAndGetNotification("NoIconNotification", "{}");
 
@@ -686,7 +644,7 @@
         RoundedIconGenerator generator =
                 NotificationBuilderBase.createIconGenerator(context.getResources());
 
-        Bitmap generatedIcon = generator.generateIconForUrl(mEmbeddedTestServerRule.getOrigin());
+        Bitmap generatedIcon = generator.generateIconForUrl(mPermissionTestRule.getOrigin());
         Assert.assertNotNull(generatedIcon);
         Assert.assertTrue(generatedIcon.sameAs(
                 NotificationTestUtil.getLargeIconFromNotification(context, notification)));
@@ -703,7 +661,7 @@
     @RetryOnFailure
     public void testNotificationContentIntentClosesNotification() throws Exception {
         mNotificationTestRule.setNotificationContentSettingForOrigin(
-                ContentSetting.ALLOW, mEmbeddedTestServerRule.getOrigin());
+                ContentSetting.ALLOW, mPermissionTestRule.getOrigin());
         // +0.5 engagement from navigating to the test page.
         Assert.assertEquals(0.5, getEngagementScoreBlocking(), 0);
 
@@ -749,7 +707,7 @@
     @RetryOnFailure
     public void testNotificationContentIntentCreatesTab() throws Exception {
         mNotificationTestRule.setNotificationContentSettingForOrigin(
-                ContentSetting.ALLOW, mEmbeddedTestServerRule.getOrigin());
+                ContentSetting.ALLOW, mPermissionTestRule.getOrigin());
 
         Assert.assertEquals(
                 "Expected the notification test page to be the sole tab in the current model", 1,
@@ -790,7 +748,7 @@
     @Feature({"Browser", "Notifications"})
     public void testNotificationTagReplacement() throws Exception {
         mNotificationTestRule.setNotificationContentSettingForOrigin(
-                ContentSetting.ALLOW, mEmbeddedTestServerRule.getOrigin());
+                ContentSetting.ALLOW, mPermissionTestRule.getOrigin());
         // +0.5 engagement from navigating to the test page.
         Assert.assertEquals(0.5, getEngagementScoreBlocking(), 0);
 
@@ -829,7 +787,7 @@
     @Feature({"Browser", "Notifications"})
     public void testShowAndCloseMultipleNotifications() throws Exception {
         mNotificationTestRule.setNotificationContentSettingForOrigin(
-                ContentSetting.ALLOW, mEmbeddedTestServerRule.getOrigin());
+                ContentSetting.ALLOW, mPermissionTestRule.getOrigin());
         // +0.5 engagement from navigating to the test page.
         Assert.assertEquals(0.5, getEngagementScoreBlocking(), 0);
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/permissions/GeolocationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/permissions/GeolocationTest.java
index c48c8ac..76d09383 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/permissions/GeolocationTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/permissions/GeolocationTest.java
@@ -44,6 +44,7 @@
 
     @Before
     public void setUp() throws Exception {
+        mPermissionRule.setUpActivity();
         LocationSettingsTestUtil.setSystemLocationSettingEnabled(true);
         LocationProviderOverrider.setLocationProviderImpl(new MockLocationProvider());
     }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/permissions/MediaTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/permissions/MediaTest.java
index 5ba0d05..7d62aa21 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/permissions/MediaTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/permissions/MediaTest.java
@@ -6,6 +6,7 @@
 
 import android.support.test.filters.MediumTest;
 
+import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -34,6 +35,11 @@
 
     public MediaTest() {}
 
+    @Before
+    public void setUp() throws Exception {
+        mPermissionRule.setUpActivity();
+    }
+
     private void testMediaPermissionsPlumbing(String prefix, String script, int numUpdates,
             boolean withGesture, boolean isDialog) throws Exception {
         Tab tab = mPermissionRule.getActivity().getActivityTab();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/permissions/PermissionNavigationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/permissions/PermissionNavigationTest.java
index fcfe0b93..a17644d0 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/permissions/PermissionNavigationTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/permissions/PermissionNavigationTest.java
@@ -4,6 +4,7 @@
 
 package org.chromium.chrome.browser.permissions;
 
+import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -33,6 +34,11 @@
 
     public PermissionNavigationTest() {}
 
+    @Before
+    public void setUp() throws Exception {
+        mPermissionRule.setUpActivity();
+    }
+
     /**
      * Check that modal permission prompts and queued permission requests are removed upon
      * navigation.
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/permissions/PermissionTestRule.java b/chrome/android/javatests/src/org/chromium/chrome/browser/permissions/PermissionTestRule.java
index 9060b07..8ae3be51 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/permissions/PermissionTestRule.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/permissions/PermissionTestRule.java
@@ -60,7 +60,7 @@
      * Waits till a JavaScript callback which updates the page title is called the specified number
      * of times. The page title is expected to be of the form <prefix>: <count>.
      */
-    protected static class PermissionUpdateWaiter extends EmptyTabObserver {
+    public static class PermissionUpdateWaiter extends EmptyTabObserver {
         private CallbackHelper mCallbackHelper;
         private String mPrefix;
         private int mExpectedCount;
@@ -136,13 +136,19 @@
     }
 
     private void ruleSetUp() throws Throwable {
+        // TODO(https://crbug.com/867446): Refactor to use EmbeddedTestServerRule.
+        mTestServer = EmbeddedTestServer.createAndStartServer(InstrumentationRegistry.getContext());
+    }
+
+    /**
+     * Starts an activity and listens for info-bars appearing/disappearing.
+     */
+    void setUpActivity() throws InterruptedException {
         startMainActivityOnBlankPage();
         InfoBarContainer container =
                 getActivity().getTabModelSelector().getCurrentTab().getInfoBarContainer();
         mListener = new InfoBarTestAnimationListener();
         container.addAnimationListener(mListener);
-        // TODO(yolandyan): refactor to use EmbeddedTestServerRule
-        mTestServer = EmbeddedTestServer.createAndStartServer(InstrumentationRegistry.getContext());
     }
 
     private void ruleTearDown() throws Exception {
@@ -150,9 +156,16 @@
     }
 
     protected void setUpUrl(final String url) throws InterruptedException {
-        loadUrl(mTestServer.getURL(url));
+        loadUrl(getURL(url));
     }
 
+    public String getURL(String url) {
+        return mTestServer.getURL(url);
+    }
+
+    public String getOrigin() {
+        return mTestServer.getURL("/");
+    }
     /**
      * Simulates clicking a button on an PermissionDialogView.
      */
@@ -181,23 +194,55 @@
             String javascript, int nUpdates, boolean withGesture, boolean isDialog)
             throws Exception {
         setUpUrl(url);
-
         if (withGesture) {
-            runJavaScriptCodeInCurrentTab("functionToRun = '" + javascript + "'");
-            TouchCommon.singleClickView(getActivity().getActivityTab().getView());
+            runJavaScriptCodeInCurrentTabWithGesture(javascript);
         } else {
             runJavaScriptCodeInCurrentTab(javascript);
         }
+        replyToPromptAndWaitForUpdates(updateWaiter, true, nUpdates, isDialog);
+    }
 
+    /**
+     * Runs a permission prompt test that grants the permission and expects the page title to be
+     * updated in response.
+     * @param updateWaiter  The update waiter to wait for callbacks. Should be added as an observer
+     *                      to the current tab prior to calling this method.
+     * @param javascript    The JS function to run in the current tab to execute the test and update
+     *                      the page title.
+     * @param nUpdates      How many updates of the page title to wait for.
+     * @param withGesture   True if we require a user gesture to trigger the prompt.
+     * @param isDialog      True if we are expecting a permission dialog, false for an infobar.
+     * @throws Exception
+     */
+    public void runDenyTest(PermissionUpdateWaiter updateWaiter, final String url,
+            String javascript, int nUpdates, boolean withGesture, boolean isDialog)
+            throws Exception {
+        setUpUrl(url);
+        if (withGesture) {
+            runJavaScriptCodeInCurrentTabWithGesture(javascript);
+        } else {
+            runJavaScriptCodeInCurrentTab(javascript);
+        }
+        replyToPromptAndWaitForUpdates(updateWaiter, false, nUpdates, isDialog);
+    }
+
+    private void replyToPromptAndWaitForUpdates(PermissionUpdateWaiter updateWaiter, boolean allow,
+            int nUpdates, boolean isDialog) throws Exception {
         if (isDialog) {
             DialogShownCriteria criteria = new DialogShownCriteria("Dialog not shown", true);
             CriteriaHelper.pollUiThread(criteria);
-            replyToDialogAndWaitForUpdates(updateWaiter, criteria.getDialog(), nUpdates, true);
+            replyToDialogAndWaitForUpdates(updateWaiter, criteria.getDialog(), nUpdates, allow);
         } else {
-            replyToInfoBarAndWaitForUpdates(updateWaiter, nUpdates, true);
+            replyToInfoBarAndWaitForUpdates(updateWaiter, nUpdates, allow);
         }
     }
 
+    private void runJavaScriptCodeInCurrentTabWithGesture(String javascript)
+            throws InterruptedException, java.util.concurrent.TimeoutException {
+        runJavaScriptCodeInCurrentTab("functionToRun = '" + javascript + "'");
+        TouchCommon.singleClickView(getActivity().getActivityTab().getView());
+    }
+
     /**
      * Replies to an infobar permission prompt and waits for a provided number
      * of updates to the page title in response.
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/permissions/QuotaTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/permissions/QuotaTest.java
index bc8cccf6..3b9434a4f 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/permissions/QuotaTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/permissions/QuotaTest.java
@@ -6,6 +6,7 @@
 
 import android.support.test.filters.MediumTest;
 
+import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -30,6 +31,11 @@
 
     private static final String TEST_FILE = "/content/test/data/android/quota_permissions.html";
 
+    @Before
+    public void setUp() throws Exception {
+        mPermissionRule.setUpActivity();
+    }
+
     public QuotaTest() {}
 
     private void testQuotaPermissionsPlumbing(
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingControllerTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingControllerTest.java
index ac2abf52..208cad79 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingControllerTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingControllerTest.java
@@ -149,15 +149,15 @@
         Tab firstTab = addTab(mediator, 1111, null);
         mController.registerPasswordProvider(firstTabProvider);
         firstTabProvider.notifyObservers(new Item[] {
-                Item.createSuggestion("FirstPassword", "FirstPassword", true, result -> {})});
+                Item.createSuggestion("FirstPassword", "FirstPassword", true, result -> {}, null)});
         assertThat(mediator.getPasswordAccessorySheet().getModelForTesting().get(0).getCaption(),
                 is("FirstPassword"));
 
         // Simulate creating a second tab:
         Tab secondTab = addTab(mediator, 2222, firstTab);
         mController.registerPasswordProvider(secondTabProvider);
-        secondTabProvider.notifyObservers(new Item[] {
-                Item.createSuggestion("SecondPassword", "SecondPassword", true, result -> {})});
+        secondTabProvider.notifyObservers(new Item[] {Item.createSuggestion(
+                "SecondPassword", "SecondPassword", true, result -> {}, null)});
         assertThat(mediator.getPasswordAccessorySheet().getModelForTesting().get(0).getCaption(),
                 is("SecondPassword"));
 
diff --git a/chrome/android/webapk/libs/client/src/org/chromium/webapk/lib/client/WebApkServiceConnectionManager.java b/chrome/android/webapk/libs/client/src/org/chromium/webapk/lib/client/WebApkServiceConnectionManager.java
index 2193f099..10430bc 100644
--- a/chrome/android/webapk/libs/client/src/org/chromium/webapk/lib/client/WebApkServiceConnectionManager.java
+++ b/chrome/android/webapk/libs/client/src/org/chromium/webapk/lib/client/WebApkServiceConnectionManager.java
@@ -150,12 +150,13 @@
     public void disconnectAll(final Context appContext) {
         if (mConnections.isEmpty()) return;
 
-        Connection[] values = mConnections.values().toArray(new Connection[mConnections.size()]);
+        final Connection[] values =
+                mConnections.values().toArray(new Connection[mConnections.size()]);
         mConnections.clear();
 
-        new AsyncTask<Connection, Void, Void>() {
+        new AsyncTask<Void, Void, Void>() {
             @Override
-            protected final Void doInBackground(Connection... values) {
+            protected final Void doInBackground(Void... params) {
                 for (Connection connection : values) {
                     if (connection.getService() != null) {
                         appContext.unbindService(connection);
@@ -163,7 +164,8 @@
                 }
                 return null;
             }
-        }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, values);
+        }
+                .executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
     }
 
     public WebApkServiceConnectionManager(String category, String action) {
diff --git a/chrome/app/chrome_main_delegate.cc b/chrome/app/chrome_main_delegate.cc
index a6726bf..8fb66e8 100644
--- a/chrome/app/chrome_main_delegate.cc
+++ b/chrome/app/chrome_main_delegate.cc
@@ -761,12 +761,6 @@
 #endif
 
 #if defined(OS_MACOSX)
-  // On the Mac, the child executable lives at a predefined location within
-  // the app bundle's versioned directory.
-  base::PathService::Override(content::CHILD_PROCESS_EXE,
-                              chrome::GetVersionedDirectory().Append(
-                                  chrome::kHelperProcessExecutablePath));
-
   InitMacCrashReporter(command_line, process_type);
   SetUpInstallerPreferences(command_line);
 #endif
diff --git a/chrome/app/chrome_main_mac.mm b/chrome/app/chrome_main_mac.mm
index 5a37a170..72d4089 100644
--- a/chrome/app/chrome_main_mac.mm
+++ b/chrome/app/chrome_main_mac.mm
@@ -13,8 +13,11 @@
 #import "base/mac/bundle_locations.h"
 #import "base/mac/foundation_util.h"
 #import "base/mac/scoped_nsautorelease_pool.h"
+#include "base/path_service.h"
 #include "base/strings/sys_string_conversions.h"
+#include "chrome/common/chrome_constants.h"
 #include "chrome/common/chrome_paths_internal.h"
+#include "content/public/common/content_paths.h"
 
 void SetUpBundleOverrides() {
   base::mac::ScopedNSAutoreleasePool pool;
@@ -23,4 +26,10 @@
 
   NSBundle* base_bundle = chrome::OuterAppBundle();
   base::mac::SetBaseBundleID([[base_bundle bundleIdentifier] UTF8String]);
+
+  // On the Mac, the child executable lives at a predefined location within
+  // the app bundle's versioned directory.
+  base::PathService::Override(content::CHILD_PROCESS_EXE,
+                              chrome::GetVersionedDirectory().Append(
+                                  chrome::kHelperProcessExecutablePath));
 }
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index a824921..00d178b 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -2428,6 +2428,7 @@
       "//chrome/browser/android/webapk:proto",
       "//chrome/services/media_gallery_util:manifest",  # TODO(xingliu): Tries to remove this.
       "//chrome/services/media_gallery_util/public/cpp",
+      "//components/autofill_assistant/browser",
       "//components/cdm/browser",
       "//components/embedder_support/android:web_contents_delegate",
       "//components/feed:buildflags",
diff --git a/chrome/browser/android/password_manager/password_accessory_view_android.cc b/chrome/browser/android/password_manager/password_accessory_view_android.cc
index 4c1a3b3..a4e0a51 100644
--- a/chrome/browser/android/password_manager/password_accessory_view_android.cc
+++ b/chrome/browser/android/password_manager/password_accessory_view_android.cc
@@ -9,6 +9,7 @@
 #include <memory>
 #include <vector>
 
+#include "base/android/callback_android.h"
 #include "base/android/jni_android.h"
 #include "base/android/jni_array.h"
 #include "base/android/jni_string.h"
@@ -16,6 +17,8 @@
 #include "jni/PasswordAccessoryBridge_jni.h"
 #include "ui/android/view_android.h"
 #include "ui/android/window_android.h"
+#include "ui/gfx/android/java_bitmap.h"
+#include "ui/gfx/image/image.h"
 
 PasswordAccessoryViewAndroid::PasswordAccessoryViewAndroid(
     PasswordAccessoryController* controller)
@@ -71,6 +74,16 @@
       env, java_object_, available /* available */);
 }
 
+void PasswordAccessoryViewAndroid::OnFaviconRequested(
+    JNIEnv* env,
+    const base::android::JavaParamRef<jobject>& obj,
+    const base::android::JavaParamRef<jobject>& j_callback) {
+  controller_->GetFavicon(
+      base::BindOnce(&PasswordAccessoryViewAndroid::OnImageFetched,
+                     base::Unretained(this),  // Outlives or cancels request.
+                     base::android::ScopedJavaGlobalRef<jobject>(j_callback)));
+}
+
 void PasswordAccessoryViewAndroid::OnFillingTriggered(
     JNIEnv* env,
     const base::android::JavaParamRef<jobject>& obj,
@@ -94,6 +107,16 @@
   controller_->OnGenerationRequested();
 }
 
+void PasswordAccessoryViewAndroid::OnImageFetched(
+    const base::android::ScopedJavaGlobalRef<jobject>& j_callback,
+    const gfx::Image& image) {
+  base::android::ScopedJavaLocalRef<jobject> j_bitmap;
+  if (!image.IsEmpty())
+    j_bitmap = gfx::ConvertToJavaBitmap(image.ToSkBitmap());
+
+  RunObjectCallbackAndroid(j_callback, j_bitmap);
+}
+
 // static
 std::unique_ptr<PasswordAccessoryViewInterface>
 PasswordAccessoryViewInterface::Create(
diff --git a/chrome/browser/android/password_manager/password_accessory_view_android.h b/chrome/browser/android/password_manager/password_accessory_view_android.h
index c8169ae..cac9a07 100644
--- a/chrome/browser/android/password_manager/password_accessory_view_android.h
+++ b/chrome/browser/android/password_manager/password_accessory_view_android.h
@@ -10,6 +10,10 @@
 #include "base/android/scoped_java_ref.h"
 #include "chrome/browser/password_manager/password_accessory_view_interface.h"
 
+namespace gfx {
+class Image;
+}
+
 class PasswordAccessoryController;
 
 // This Android-specific implementation of the |PasswordAccessoryViewInterface|
@@ -27,6 +31,10 @@
   void OnAutomaticGenerationStatusChanged(bool available) override;
 
   // Called from Java via JNI:
+  void OnFaviconRequested(
+      JNIEnv* env,
+      const base::android::JavaParamRef<jobject>& obj,
+      const base::android::JavaParamRef<jobject>& j_callback);
   void OnFillingTriggered(
       JNIEnv* env,
       const base::android::JavaParamRef<jobject>& obj,
@@ -40,6 +48,10 @@
                              const base::android::JavaParamRef<jobject>& obj);
 
  private:
+  void OnImageFetched(
+      const base::android::ScopedJavaGlobalRef<jobject>& j_callback,
+      const gfx::Image& image);
+
   // The controller provides data for this view and owns it.
   PasswordAccessoryController* controller_;
 
diff --git a/chrome/browser/android/tab_android.cc b/chrome/browser/android/tab_android.cc
index fd6fb396..d3f1f1e5 100644
--- a/chrome/browser/android/tab_android.cc
+++ b/chrome/browser/android/tab_android.cc
@@ -33,6 +33,7 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_android.h"
 #include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/browser/resource_coordinator/tab_load_tracker.h"
 #include "chrome/browser/sessions/session_tab_helper.h"
 #include "chrome/browser/sessions/tab_restore_service_factory.h"
 #include "chrome/browser/sync/glue/synced_tab_delegate_android.h"
@@ -343,6 +344,11 @@
     std::unique_ptr<content::WebContents> new_contents,
     bool did_start_load,
     bool did_finish_load) {
+  // TODO(crbug.com/836409): TabLoadTracker should not rely on being notified
+  // directly about tab contents swaps.
+  resource_coordinator::TabLoadTracker::Get()->SwapTabContents(
+      old_contents, new_contents.get());
+
   JNIEnv* env = base::android::AttachCurrentThread();
   Java_Tab_swapWebContents(env, weak_java_tab_.get(env),
                            new_contents->GetJavaWebContents(), did_start_load,
diff --git a/chrome/browser/android/vr/BUILD.gn b/chrome/browser/android/vr/BUILD.gn
index d4095c9..58e8924 100644
--- a/chrome/browser/android/vr/BUILD.gn
+++ b/chrome/browser/android/vr/BUILD.gn
@@ -79,14 +79,19 @@
     ":vr_jni_headers",
     "//base",
     "//cc",
-    "//chrome/browser/vr:vr_gl_utils",
+    "//chrome/browser/ui:ui",
     "//chrome/browser/vr:vr_common",
+    "//chrome/browser/vr:vr_gl_utils",
+    "//chrome/common:common",
+    "//chrome/common:constants",
     "//components/omnibox/browser",
     "//components/rappor",
+    "//components/search_engines:search_engines",
     "//content/public/browser",
     "//content/public/common",
     "//device/gamepad",
     "//device/vr",
+    "//device/vr/buildflags:buildflags",
     "//services/device/public/mojom",
     "//services/metrics/public/cpp:ukm_builders",
     "//services/ui/public/cpp/gpu",
diff --git a/chrome/browser/autofill/autofill_interactive_uitest.cc b/chrome/browser/autofill/autofill_interactive_uitest.cc
index da7d3157..c1ac862 100644
--- a/chrome/browser/autofill/autofill_interactive_uitest.cc
+++ b/chrome/browser/autofill/autofill_interactive_uitest.cc
@@ -2711,6 +2711,84 @@
   ExpectFieldValue("phone", "15125551234");
 }
 
+// Test that we can autofill forms that dynamically change the element that
+// has been clicked on.
+IN_PROC_BROWSER_TEST_P(AutofillDynamicFormInteractiveTest,
+                       DynamicFormFill_FirstElementDisappears) {
+  CreateTestProfile();
+
+  GURL url = embedded_test_server()->GetURL(
+      "a.com", "/autofill/dynamic_form_element_invalid.html");
+  ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL(browser(), url));
+  TriggerFormFill("firstname");
+
+  // Wait for the re-fill to happen.
+  bool has_refilled = false;
+  ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
+      GetWebContents(), "hasRefilled()", &has_refilled));
+  ASSERT_TRUE(has_refilled);
+
+  // Make sure the new form was filled correctly.
+  ExpectFieldValue("firstname2", "Milton");
+  ExpectFieldValue("address1", "4120 Freidrich Lane");
+  ExpectFieldValue("city", "Austin");
+  ExpectFieldValue("company", "Initech");
+  ExpectFieldValue("email", "red.swingline@initech.com");
+  ExpectFieldValue("phone", "15125551234");
+}
+
+// Test that we can autofill forms that dynamically change the element that
+// has been clicked on, even though the form has no name.
+IN_PROC_BROWSER_TEST_P(AutofillDynamicFormInteractiveTest,
+                       DynamicFormFill_FirstElementDisappearsNoNameForm) {
+  CreateTestProfile();
+
+  GURL url = embedded_test_server()->GetURL(
+      "a.com", "/autofill/dynamic_form_element_invalid_noname_form.html");
+  ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL(browser(), url));
+  TriggerFormFill("firstname");
+
+  // Wait for the re-fill to happen.
+  bool has_refilled = false;
+  ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
+      GetWebContents(), "hasRefilled()", &has_refilled));
+  ASSERT_TRUE(has_refilled);
+
+  // Make sure the new form was filled correctly.
+  ExpectFieldValue("firstname2", "Milton");
+  ExpectFieldValue("address1", "4120 Freidrich Lane");
+  ExpectFieldValue("city", "Austin");
+  ExpectFieldValue("company", "Initech");
+  ExpectFieldValue("email", "red.swingline@initech.com");
+  ExpectFieldValue("phone", "15125551234");
+}
+
+// Test that we can autofill forms that dynamically change the element that
+// has been clicked on, even though the elements are unowned.
+IN_PROC_BROWSER_TEST_P(AutofillDynamicFormInteractiveTest,
+                       DynamicFormFill_FirstElementDisappearsUnowned) {
+  CreateTestProfile();
+
+  GURL url = embedded_test_server()->GetURL(
+      "a.com", "/autofill/dynamic_form_element_invalid_unowned.html");
+  ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL(browser(), url));
+  TriggerFormFill("firstname");
+
+  // Wait for the re-fill to happen.
+  bool has_refilled = false;
+  ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
+      GetWebContents(), "hasRefilled()", &has_refilled));
+  ASSERT_TRUE(has_refilled);
+
+  // Make sure the new form was filled correctly.
+  ExpectFieldValue("firstname2", "Milton");
+  ExpectFieldValue("address1", "4120 Freidrich Lane");
+  ExpectFieldValue("city", "Austin");
+  ExpectFieldValue("company", "Initech");
+  ExpectFieldValue("email", "red.swingline@initech.com");
+  ExpectFieldValue("phone", "15125551234");
+}
+
 // Test that credit card fields are never re-filled.
 IN_PROC_BROWSER_TEST_P(AutofillDynamicFormInteractiveTest,
                        DynamicChangingFormFill_NotForCreditCard) {
diff --git a/chrome/browser/captive_portal/captive_portal_tab_reloader.cc b/chrome/browser/captive_portal/captive_portal_tab_reloader.cc
index b5c99d3..f2b3909 100644
--- a/chrome/browser/captive_portal/captive_portal_tab_reloader.cc
+++ b/chrome/browser/captive_portal/captive_portal_tab_reloader.cc
@@ -266,8 +266,10 @@
 
 void CaptivePortalTabReloader::ReloadTab() {
   content::NavigationController* controller = &web_contents_->GetController();
-  if (!controller->GetLastCommittedEntry()->GetHasPostData())
+  if (controller->GetLastCommittedEntry() &&
+      !controller->GetLastCommittedEntry()->GetHasPostData()) {
     controller->Reload(content::ReloadType::NORMAL, true);
+  }
 }
 
 void CaptivePortalTabReloader::MaybeOpenCaptivePortalLoginTab() {
diff --git a/chrome/browser/component_updater/cros_component_installer_chromeos.cc b/chrome/browser/component_updater/cros_component_installer_chromeos.cc
index d11a15e..4d586ce 100644
--- a/chrome/browser/component_updater/cros_component_installer_chromeos.cc
+++ b/chrome/browser/component_updater/cros_component_installer_chromeos.cc
@@ -33,7 +33,7 @@
 const ComponentConfig kConfigs[] = {
     {"epson-inkjet-printer-escpr", "2.1",
      "1913a5e0a6cad30b6f03e176177e0d7ed62c5d6700a9c66da556d7c3f5d6a47e"},
-    {"cros-termina", "1.1",
+    {"cros-termina", "70.1",
      "e9d960f84f628e1f42d05de4046bb5b3154b6f1f65c08412c6af57a29aecaffb"},
     {"rtanalytics-light", "4.1",
      "69f09d33c439c2ab55bbbe24b47ab55cb3f6c0bd1f1ef46eefea3216ec925038"},
diff --git a/chrome/browser/media/webrtc/webrtc_event_log_manager.cc b/chrome/browser/media/webrtc/webrtc_event_log_manager.cc
index 5d019ce8..288f148 100644
--- a/chrome/browser/media/webrtc/webrtc_event_log_manager.cc
+++ b/chrome/browser/media/webrtc/webrtc_event_log_manager.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2017 The Chromium Authors. All rights reserved.
+// 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.
 
diff --git a/chrome/browser/media/webrtc/webrtc_event_log_manager.h b/chrome/browser/media/webrtc/webrtc_event_log_manager.h
index 74c081d6..626dc5b 100644
--- a/chrome/browser/media/webrtc/webrtc_event_log_manager.h
+++ b/chrome/browser/media/webrtc/webrtc_event_log_manager.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2017 The Chromium Authors. All rights reserved.
+// 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.
 
diff --git a/chrome/browser/media/webrtc/webrtc_event_log_manager_common.cc b/chrome/browser/media/webrtc/webrtc_event_log_manager_common.cc
index 82a6723b..652d94d 100644
--- a/chrome/browser/media/webrtc/webrtc_event_log_manager_common.cc
+++ b/chrome/browser/media/webrtc/webrtc_event_log_manager_common.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2018 The Chromium Authors. All rights reserved.
+// 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.
 
diff --git a/chrome/browser/media/webrtc/webrtc_event_log_manager_common.h b/chrome/browser/media/webrtc/webrtc_event_log_manager_common.h
index 4fdb07f..a3b6595 100644
--- a/chrome/browser/media/webrtc/webrtc_event_log_manager_common.h
+++ b/chrome/browser/media/webrtc/webrtc_event_log_manager_common.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2017 The Chromium Authors. All rights reserved.
+// 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.
 
diff --git a/chrome/browser/media/webrtc/webrtc_event_log_manager_local.cc b/chrome/browser/media/webrtc/webrtc_event_log_manager_local.cc
index 50e9ddb..4046605 100644
--- a/chrome/browser/media/webrtc/webrtc_event_log_manager_local.cc
+++ b/chrome/browser/media/webrtc/webrtc_event_log_manager_local.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2017 The Chromium Authors. All rights reserved.
+// 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.
 
diff --git a/chrome/browser/media/webrtc/webrtc_event_log_manager_local.h b/chrome/browser/media/webrtc/webrtc_event_log_manager_local.h
index 877856b..7b70e75 100644
--- a/chrome/browser/media/webrtc/webrtc_event_log_manager_local.h
+++ b/chrome/browser/media/webrtc/webrtc_event_log_manager_local.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2017 The Chromium Authors. All rights reserved.
+// 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.
 
diff --git a/chrome/browser/media/webrtc/webrtc_event_log_manager_remote.cc b/chrome/browser/media/webrtc/webrtc_event_log_manager_remote.cc
index 581135e..547b28f 100644
--- a/chrome/browser/media/webrtc/webrtc_event_log_manager_remote.cc
+++ b/chrome/browser/media/webrtc/webrtc_event_log_manager_remote.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2018 The Chromium Authors. All rights reserved.
+// 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.
 
diff --git a/chrome/browser/media/webrtc/webrtc_event_log_manager_remote.h b/chrome/browser/media/webrtc/webrtc_event_log_manager_remote.h
index 4d84049..c914772 100644
--- a/chrome/browser/media/webrtc/webrtc_event_log_manager_remote.h
+++ b/chrome/browser/media/webrtc/webrtc_event_log_manager_remote.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2018 The Chromium Authors. All rights reserved.
+// 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.
 
diff --git a/chrome/browser/media/webrtc/webrtc_event_log_uploader.cc b/chrome/browser/media/webrtc/webrtc_event_log_uploader.cc
index f683e4b..e7305716 100644
--- a/chrome/browser/media/webrtc/webrtc_event_log_uploader.cc
+++ b/chrome/browser/media/webrtc/webrtc_event_log_uploader.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2018 The Chromium Authors. All rights reserved.
+// 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.
 
diff --git a/chrome/browser/media/webrtc/webrtc_event_log_uploader.h b/chrome/browser/media/webrtc/webrtc_event_log_uploader.h
index 61b3288..b40b3ad5 100644
--- a/chrome/browser/media/webrtc/webrtc_event_log_uploader.h
+++ b/chrome/browser/media/webrtc/webrtc_event_log_uploader.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2018 The Chromium Authors. All rights reserved.
+// 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.
 
diff --git a/chrome/browser/media/webrtc/webrtc_event_log_uploader_impl_unittest.cc b/chrome/browser/media/webrtc/webrtc_event_log_uploader_impl_unittest.cc
index e99ed88d..65e032d3 100644
--- a/chrome/browser/media/webrtc/webrtc_event_log_uploader_impl_unittest.cc
+++ b/chrome/browser/media/webrtc/webrtc_event_log_uploader_impl_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2018 The Chromium Authors. All rights reserved.
+// 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.
 
diff --git a/chrome/browser/password_manager/chrome_password_manager_client.cc b/chrome/browser/password_manager/chrome_password_manager_client.cc
index 6f62c20..f2201ad 100644
--- a/chrome/browser/password_manager/chrome_password_manager_client.cc
+++ b/chrome/browser/password_manager/chrome_password_manager_client.cc
@@ -461,7 +461,7 @@
       !base::FeatureList::IsEnabled(features::kExperimentalUi)) {
     return;  // No need to even create the bridge if it's not going to be used.
   }
-  // If an accessory exists already, |CreateForWebContents| is a NoOp.
+  // If an accessory exists already, |CreateForWebContents| is a NoOp
   PasswordAccessoryController::CreateForWebContents(web_contents());
   PasswordAccessoryController::FromWebContents(web_contents())
       ->SavePasswordsForOrigin(best_matches, url::Origin::Create(origin));
@@ -561,7 +561,12 @@
   web_contents()->GetRenderViewHost()->GetWidget()->RemoveInputEventObserver(
       this);
   web_contents()->GetRenderViewHost()->GetWidget()->AddInputEventObserver(this);
-#endif
+#else   // defined(OS_ANDROID)
+  PasswordAccessoryController* accessory =
+      PasswordAccessoryController::FromWebContents(web_contents());
+  if (accessory)
+    accessory->DidNavigateMainFrame();
+#endif  // defined(OS_ANDROID)
 }
 
 #if !defined(OS_ANDROID)
@@ -1078,16 +1083,17 @@
       !base::FeatureList::IsEnabled(features::kExperimentalUi)) {
     return;  // No need to even create the bridge if it's not going to be used.
   }
-  if (is_fillable)  // Refresh but don't create a new accessory in this case.
+  if (is_fillable) {  // If not fillable, update existing an accessory only.
     PasswordAccessoryController::CreateForWebContents(web_contents());
+  }
   PasswordAccessoryController* accessory =
       PasswordAccessoryController::FromWebContents(web_contents());
-  if (!accessory)
-    return;  // No accessory needs change here.
-  accessory->RefreshSuggestionsForField(
-      password_manager_driver_bindings_.GetCurrentTargetFrame()
-          ->GetLastCommittedOrigin(),
-      is_fillable, is_password_field);
+  if (accessory) {
+    accessory->RefreshSuggestionsForField(
+        password_manager_driver_bindings_.GetCurrentTargetFrame()
+            ->GetLastCommittedOrigin(),
+        is_fillable, is_password_field);
+  }
 #endif  // defined(OS_ANDROID)
 }
 
diff --git a/chrome/browser/password_manager/password_accessory_controller.cc b/chrome/browser/password_manager/password_accessory_controller.cc
index 11d7906..df082bc 100644
--- a/chrome/browser/password_manager/password_accessory_controller.cc
+++ b/chrome/browser/password_manager/password_accessory_controller.cc
@@ -6,14 +6,18 @@
 
 #include <vector>
 
+#include "base/callback.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/android/preferences/preferences_launcher.h"
+#include "chrome/browser/favicon/favicon_service_factory.h"
 #include "chrome/browser/password_manager/password_generation_dialog_view_interface.h"
+#include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/passwords/manage_passwords_view_utils.h"
 #include "chrome/grit/generated_resources.h"
 #include "components/autofill/content/browser/content_autofill_driver.h"
 #include "components/autofill/content/browser/content_autofill_driver_factory.h"
 #include "components/autofill/core/common/password_form.h"
+#include "components/favicon/core/favicon_service.h"
 #include "components/password_manager/content/browser/content_password_manager_driver.h"
 #include "components/password_manager/content/browser/content_password_manager_driver_factory.h"
 #include "components/password_manager/core/browser/password_manager_driver.h"
@@ -65,22 +69,35 @@
   Item::Type username_type;
 };
 
+struct PasswordAccessoryController::FaviconRequestData {
+  // List of requests waiting for favicons to be available.
+  std::vector<base::OnceCallback<void(const gfx::Image&)>> pending_requests;
+
+  // Cached image for this origin. |IsEmpty()| unless a favicon was found.
+  gfx::Image cached_icon;
+};
+
 PasswordAccessoryController::PasswordAccessoryController(
     content::WebContents* web_contents)
     : web_contents_(web_contents),
       view_(PasswordAccessoryViewInterface::Create(this)),
       create_dialog_factory_(
           base::BindRepeating(&PasswordGenerationDialogViewInterface::Create)),
+      favicon_service_(FaviconServiceFactory::GetForProfile(
+          Profile::FromBrowserContext(web_contents->GetBrowserContext()),
+          ServiceAccessType::EXPLICIT_ACCESS)),
       weak_factory_(this) {}
 
 // Additional creation functions in unit tests only:
 PasswordAccessoryController::PasswordAccessoryController(
     content::WebContents* web_contents,
     std::unique_ptr<PasswordAccessoryViewInterface> view,
-    CreateDialogFactory create_dialog_factory)
+    CreateDialogFactory create_dialog_factory,
+    favicon::FaviconService* favicon_service)
     : web_contents_(web_contents),
       view_(std::move(view)),
       create_dialog_factory_(create_dialog_factory),
+      favicon_service_(favicon_service),
       weak_factory_(this) {}
 
 PasswordAccessoryController::~PasswordAccessoryController() = default;
@@ -89,13 +106,14 @@
 void PasswordAccessoryController::CreateForWebContentsForTesting(
     content::WebContents* web_contents,
     std::unique_ptr<PasswordAccessoryViewInterface> view,
-    CreateDialogFactory create_dialog_factory) {
+    CreateDialogFactory create_dialog_factory,
+    favicon::FaviconService* favicon_service) {
   DCHECK(web_contents) << "Need valid WebContents to attach controller to!";
   DCHECK(!FromWebContents(web_contents)) << "Controller already attached!";
   web_contents->SetUserData(
-      UserDataKey(),
-      base::WrapUnique(new PasswordAccessoryController(
-          web_contents, std::move(view), create_dialog_factory)));
+      UserDataKey(), base::WrapUnique(new PasswordAccessoryController(
+                         web_contents, std::move(view), create_dialog_factory,
+                         favicon_service)));
 }
 
 void PasswordAccessoryController::SavePasswordsForOrigin(
@@ -135,6 +153,67 @@
   view_->OnAutomaticGenerationStatusChanged(available);
 }
 
+void PasswordAccessoryController::OnFilledIntoFocusedField(
+    autofill::FillingStatus status) {
+  // TODO(crbug/853766): Record success rate.
+  // TODO(fhorschig): Update UI by hiding the sheet or communicating the error.
+}
+
+void PasswordAccessoryController::RefreshSuggestionsForField(
+    const url::Origin& origin,
+    bool is_fillable,
+    bool is_password_field) {
+  // TODO(crbug/853766): Record CTR metric.
+  if (is_fillable) {
+    current_origin_ = origin;
+    view_->OnItemsAvailable(CreateViewItems(origin, origin_suggestions_[origin],
+                                            is_password_field));
+  } else {
+    // For unfillable fields, reset the origin and send the empty state message.
+    current_origin_ = url::Origin();
+    view_->OnItemsAvailable(CreateViewItems(
+        origin, std::vector<SuggestionElementData>(), is_password_field));
+  }
+}
+
+void PasswordAccessoryController::DidNavigateMainFrame() {
+  if (current_origin_.IsSameOriginWith(
+          web_contents_->GetMainFrame()->GetLastCommittedOrigin()))
+    return;  // Clean requests only if the navigation was across origins.
+  favicon_tracker_.TryCancelAll();  // If there is a request pending, cancel it.
+  current_origin_ = url::Origin();
+  icons_request_data_.clear();
+  origin_suggestions_.clear();
+}
+
+void PasswordAccessoryController::GetFavicon(
+    base::OnceCallback<void(const gfx::Image&)> icon_callback) {
+  url::Origin origin = current_origin_;  // Copy origin in case it changes.
+  // Check whether this request can be immediately answered with a cached icon.
+  // It is empty if there wasn't at least one request that found an icon yet.
+  FaviconRequestData* icon_request = &icons_request_data_[origin];
+  if (!icon_request->cached_icon.IsEmpty()) {
+    std::move(icon_callback).Run(icon_request->cached_icon);
+    return;
+  }
+  if (!favicon_service_) {  // This might happen in tests.
+    std::move(icon_callback).Run(gfx::Image());
+    return;
+  }
+
+  // The cache is empty. Queue the callback.
+  icon_request->pending_requests.emplace_back(std::move(icon_callback));
+  if (icon_request->pending_requests.size() > 1)
+    return;  // The favicon for this origin was already requested.
+
+  favicon_service_->GetFaviconImageForPageURL(
+      origin.GetURL(),
+      base::BindRepeating(  // FaviconService doesn't support BindOnce yet.
+          &PasswordAccessoryController::OnImageFetched,
+          weak_factory_.GetWeakPtr(), origin),
+      &favicon_tracker_);
+}
+
 void PasswordAccessoryController::OnFillingTriggered(
     bool is_password,
     const base::string16& textToFill) {
@@ -200,24 +279,6 @@
   chrome::android::PreferencesLauncher::ShowPasswordSettings();
 }
 
-void PasswordAccessoryController::OnFilledIntoFocusedField(
-    autofill::FillingStatus status) {
-  // TODO(crbug/853766): Record success rate.
-  // TODO(fhorschig): Update UI by hiding the sheet or communicating the error.
-}
-
-void PasswordAccessoryController::RefreshSuggestionsForField(
-    const url::Origin& origin,
-    bool is_fillable,
-    bool is_password_field) {
-  // TODO(crbug/853766): Record CTR metric.
-  view_->OnItemsAvailable(
-      CreateViewItems(origin,
-                      is_fillable ? origin_suggestions_[origin]
-                                  : std::vector<SuggestionElementData>(),
-                      is_password_field));
-}
-
 gfx::NativeView PasswordAccessoryController::container_view() const {
   return web_contents_->GetNativeView();
 }
@@ -268,3 +329,17 @@
                      Item::Type::OPTION);
   return items;
 }
+
+void PasswordAccessoryController::OnImageFetched(
+    url::Origin origin,
+    const favicon_base::FaviconImageResult& image_result) {
+  FaviconRequestData* icon_request = &icons_request_data_[origin];
+  icon_request->cached_icon = image_result.image;
+  // Only trigger all the callbacks if they still affect a displayed origin.
+  if (origin == current_origin_) {
+    for (auto& callback : icon_request->pending_requests) {
+      std::move(callback).Run(icon_request->cached_icon);
+    }
+  }
+  icon_request->pending_requests.clear();
+}
diff --git a/chrome/browser/password_manager/password_accessory_controller.h b/chrome/browser/password_manager/password_accessory_controller.h
index 2231d353..4121bf9c4 100644
--- a/chrome/browser/password_manager/password_accessory_controller.h
+++ b/chrome/browser/password_manager/password_accessory_controller.h
@@ -10,13 +10,16 @@
 #include <utility>
 #include <vector>
 
-#include "base/callback.h"
+#include "base/callback_forward.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "base/strings/string16.h"
+#include "base/task/cancelable_task_tracker.h"
 #include "chrome/browser/password_manager/password_accessory_view_interface.h"
 #include "components/autofill/core/common/filling_status.h"
 #include "components/autofill/core/common/password_generation_util.h"
+#include "components/favicon_base/favicon_types.h"
+#include "content/public/browser/browser_context.h"
 #include "content/public/browser/web_contents_user_data.h"
 #include "ui/gfx/native_widget_types.h"
 #include "url/gurl.h"
@@ -25,6 +28,10 @@
 struct PasswordForm;
 }  // namespace autofill
 
+namespace favicon {
+class FaviconService;
+}
+
 namespace password_manager {
 class PasswordManagerDriver;
 }  // namespace password_manager
@@ -52,6 +59,10 @@
       PasswordGenerationDialogViewInterface>(PasswordAccessoryController*)>;
   ~PasswordAccessoryController() override;
 
+  // -----------------------------
+  // Methods called by the client:
+  // -----------------------------
+
   // Saves credentials for an origin so that they can be used in the sheet.
   void SavePasswordsForOrigin(
       const std::map<base::string16, const autofill::PasswordForm*>&
@@ -65,6 +76,30 @@
           autofill::password_generation::PasswordGenerationUIData>& ui_data,
       const base::WeakPtr<password_manager::PasswordManagerDriver>& driver);
 
+  // Completes a filling attempt by recording metrics, giving feedback to the
+  // user and dismissing the accessory sheet.
+  void OnFilledIntoFocusedField(autofill::FillingStatus status);
+
+  // Makes sure, that all shown suggestions are appropriate for the currently
+  // focused field and for fields that lost the focus. If a field lost focus,
+  // |is_fillable| will be false.
+  void RefreshSuggestionsForField(const url::Origin& origin,
+                                  bool is_fillable,
+                                  bool is_password_field);
+
+  // Reacts to a navigation on the main frame, e.g. by clearing caches.
+  void DidNavigateMainFrame();
+
+  // --------------------------
+  // Methods called by UI code:
+  // --------------------------
+
+  // Uses the give |favicon_service| to get an icon for the currently focused
+  // frame. The given callback is called with an image unless an icon for a new
+  // origin was called. In the latter case, the callback is dropped.
+  // The callback is called with an |IsEmpty()| image if there is no favicon.
+  void GetFavicon(base::OnceCallback<void(const gfx::Image&)> icon_callback);
+
   // Called by the UI code to request that |textToFill| is to be filled into the
   // currently focused field.
   void OnFillingTriggered(bool is_password, const base::string16& textToFill);
@@ -86,16 +121,9 @@
   // in the explanation text that leads to the saved passwords.
   void OnSavedPasswordsLinkClicked();
 
-  // Compeletes a filling attempt by recording metrics, giving feedback to the
-  // user and dismissing the accessory sheet.
-  void OnFilledIntoFocusedField(autofill::FillingStatus status);
-
-  // Makes sure, that all shown suggestions are appropriate for the currently
-  // focused field and for fields that lost the focus. If a field lost focus,
-  // |is_fillable| will be false.
-  void RefreshSuggestionsForField(const url::Origin& origin,
-                                  bool is_fillable,
-                                  bool is_password_field);
+  // -----------------
+  // Member accessors:
+  // -----------------
 
   // The web page view containing the focused field.
   gfx::NativeView container_view() const;
@@ -107,7 +135,8 @@
   static void CreateForWebContentsForTesting(
       content::WebContents* web_contents,
       std::unique_ptr<PasswordAccessoryViewInterface> test_view,
-      CreateDialogFactory create_dialog_callback);
+      CreateDialogFactory create_dialog_callback,
+      favicon::FaviconService* favicon_service);
 
 #if defined(UNIT_TEST)
   // Returns the held view for testing.
@@ -122,6 +151,9 @@
   // Data for a credential pair that is transformed into a suggestion.
   struct SuggestionElementData;
 
+  // Data allowing to cache favicons and favicon-related requests.
+  struct FaviconRequestData;
+
   // Required for construction via |CreateForWebContents|:
   explicit PasswordAccessoryController(content::WebContents* contents);
   friend class content::WebContentsUserData<PasswordAccessoryController>;
@@ -130,7 +162,8 @@
   PasswordAccessoryController(
       content::WebContents* web_contents,
       std::unique_ptr<PasswordAccessoryViewInterface> view,
-      CreateDialogFactory create_dialog_callback);
+      CreateDialogFactory create_dialog_callback,
+      favicon::FaviconService* favicon_service);
 
   // Creates the view items based on the given |suggestions|.
   // If |is_password_field| is false, password suggestions won't be interactive.
@@ -139,6 +172,11 @@
                   const std::vector<SuggestionElementData>& suggestions,
                   bool is_password_field);
 
+  // Handles a favicon response requested by |GetFavicon| and calls the waiting
+  // last_icon_callback_ with a (possibly empty) icon bitmap.
+  void OnImageFetched(url::Origin origin,
+                      const favicon_base::FaviconImageResult& image_result);
+
   // Contains the last set of credentials by origin.
   std::map<url::Origin, std::vector<SuggestionElementData>> origin_suggestions_;
 
@@ -148,6 +186,19 @@
   // Data for the generation element used to generate the password.
   std::unique_ptr<GenerationElementData> generation_element_data_;
 
+  // The origin of the currently focused frame. It's used to ensure that
+  // favicons are not displayed across origins.
+  url::Origin current_origin_;
+
+  // TODO(fhorschig): Find a way to use unordered_map with origin keys.
+  // A cache for all favicons that were requested. This includes all iframes
+  // for which the accessory was displayed.
+  std::map<url::Origin, FaviconRequestData> icons_request_data_;
+
+  // Used to track a requested favicon. If the set of suggestion changes, this
+  // object aborts the request. Upon destruction, requests are cancelled, too.
+  base::CancelableTaskTracker favicon_tracker_;
+
   // Password manager driver for the target frame used for password generation.
   base::WeakPtr<password_manager::PasswordManagerDriver> target_frame_driver_;
 
@@ -166,6 +217,9 @@
   // Creation callback for the modal dialog view meant to facilitate testing.
   CreateDialogFactory create_dialog_factory_;
 
+  // The favicon service used to make retrieve icons for a given origin.
+  favicon::FaviconService* favicon_service_;
+
   base::WeakPtrFactory<PasswordAccessoryController> weak_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(PasswordAccessoryController);
diff --git a/chrome/browser/password_manager/password_accessory_controller_unittest.cc b/chrome/browser/password_manager/password_accessory_controller_unittest.cc
index c5603a5..a92c1b92 100644
--- a/chrome/browser/password_manager/password_accessory_controller_unittest.cc
+++ b/chrome/browser/password_manager/password_accessory_controller_unittest.cc
@@ -8,11 +8,13 @@
 #include <string>
 #include <vector>
 
+#include "base/callback.h"
 #include "base/memory/weak_ptr.h"
 #include "base/optional.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/mock_callback.h"
+#include "base/test/scoped_task_environment.h"
 #include "chrome/browser/password_manager/password_accessory_view_interface.h"
 #include "chrome/browser/password_manager/password_generation_dialog_view_interface.h"
 #include "chrome/grit/generated_resources.h"
@@ -20,12 +22,14 @@
 #include "components/autofill/core/common/password_form.h"
 #include "components/autofill/core/common/password_generation_util.h"
 #include "components/autofill/core/common/signatures_util.h"
+#include "components/favicon/core/test/mock_favicon_service.h"
 #include "components/password_manager/core/browser/password_generation_manager.h"
 #include "components/password_manager/core/browser/stub_password_manager_client.h"
 #include "components/password_manager/core/browser/stub_password_manager_driver.h"
 #include "components/strings/grit/components_strings.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/skia/include/core/SkBitmap.h"
 #include "ui/base/l10n/l10n_util.h"
 
 namespace {
@@ -237,14 +241,19 @@
 
 class PasswordAccessoryControllerTest : public ChromeRenderViewHostTestHarness {
  public:
+  PasswordAccessoryControllerTest()
+      : mock_favicon_service_(
+            std::make_unique<
+                testing::StrictMock<favicon::MockFaviconService>>()) {}
+
   void SetUp() override {
     ChromeRenderViewHostTestHarness::SetUp();
     NavigateAndCommit(GURL(kExampleSite));
     PasswordAccessoryController::CreateForWebContentsForTesting(
         web_contents(),
         std::make_unique<StrictMock<MockPasswordAccessoryView>>(),
-        mock_dialog_factory_.Get());
-    NavigateAndCommit(GURL("https://example.com"));
+        mock_dialog_factory_.Get(), favicon_service());
+    NavigateAndCommit(GURL(kExampleSite));
   }
 
   PasswordAccessoryController* controller() {
@@ -260,9 +269,15 @@
     return mock_dialog_factory_;
   }
 
+  favicon::MockFaviconService* favicon_service() {
+    return mock_favicon_service_.get();
+  }
+
  private:
   base::MockCallback<PasswordAccessoryController::CreateDialogFactory>
       mock_dialog_factory_;
+  std::unique_ptr<testing::StrictMock<favicon::MockFaviconService>>
+      mock_favicon_service_;
 };
 
 TEST_F(PasswordAccessoryControllerTest, IsNotRecreatedForSameWebContents) {
@@ -275,6 +290,9 @@
 }
 
 TEST_F(PasswordAccessoryControllerTest, TransformsMatchesToSuggestions) {
+  controller()->SavePasswordsForOrigin({CreateEntry("Ben", "S3cur3").first},
+                                       url::Origin::Create(GURL(kExampleSite)));
+
   EXPECT_CALL(*view(),
               OnItemsAvailable(ElementsAre(
                   MatchesLabel(passwords_title_str(kExampleDomain)),
@@ -283,9 +301,6 @@
                   MatchesItem(ASCIIToUTF16("S3cur3"), password_for_str("Ben"),
                               true, ItemType::NON_INTERACTIVE_SUGGESTION),
                   IsDivider(), MatchesOption(manage_passwords_str()))));
-
-  controller()->SavePasswordsForOrigin({CreateEntry("Ben", "S3cur3").first},
-                                       url::Origin::Create(GURL(kExampleSite)));
   controller()->RefreshSuggestionsForField(
       url::Origin::Create(GURL(kExampleSite)),
       /*is_fillable=*/true,
@@ -293,6 +308,9 @@
 }
 
 TEST_F(PasswordAccessoryControllerTest, HintsToEmptyUserNames) {
+  controller()->SavePasswordsForOrigin({CreateEntry("", "S3cur3").first},
+                                       url::Origin::Create(GURL(kExampleSite)));
+
   EXPECT_CALL(
       *view(),
       OnItemsAvailable(ElementsAre(
@@ -302,9 +320,6 @@
           MatchesItem(ASCIIToUTF16("S3cur3"), password_for_str(no_user_str()),
                       true, ItemType::NON_INTERACTIVE_SUGGESTION),
           IsDivider(), MatchesOption(manage_passwords_str()))));
-
-  controller()->SavePasswordsForOrigin({CreateEntry("", "S3cur3").first},
-                                       url::Origin::Create(GURL(kExampleSite)));
   controller()->RefreshSuggestionsForField(
       url::Origin::Create(GURL(kExampleSite)),
       /*is_fillable=*/true,
@@ -312,6 +327,11 @@
 }
 
 TEST_F(PasswordAccessoryControllerTest, SortsAlphabeticalDuringTransform) {
+  controller()->SavePasswordsForOrigin(
+      {CreateEntry("Ben", "S3cur3").first, CreateEntry("Zebra", "M3h").first,
+       CreateEntry("Alf", "PWD").first, CreateEntry("Cat", "M1@u").first},
+      url::Origin::Create(GURL(kExampleSite)));
+
   EXPECT_CALL(*view(),
               OnItemsAvailable(ElementsAre(
                   MatchesLabel(passwords_title_str(kExampleDomain)),
@@ -336,11 +356,6 @@
                   MatchesItem(ASCIIToUTF16("M3h"), password_for_str("Zebra"),
                               true, ItemType::NON_INTERACTIVE_SUGGESTION),
                   IsDivider(), MatchesOption(manage_passwords_str()))));
-
-  controller()->SavePasswordsForOrigin(
-      {CreateEntry("Ben", "S3cur3").first, CreateEntry("Zebra", "M3h").first,
-       CreateEntry("Alf", "PWD").first, CreateEntry("Cat", "M1@u").first},
-      url::Origin::Create(GURL(kExampleSite)));
   controller()->RefreshSuggestionsForField(
       url::Origin::Create(GURL(kExampleSite)),
       /*is_fillable=*/true,
@@ -348,6 +363,10 @@
 }
 
 TEST_F(PasswordAccessoryControllerTest, RepeatsSuggestionsForSameFrame) {
+  controller()->SavePasswordsForOrigin({CreateEntry("Ben", "S3cur3").first},
+                                       url::Origin::Create(GURL(kExampleSite)));
+
+  // Pretend that any input in the same frame was focused.
   EXPECT_CALL(*view(),
               OnItemsAvailable(ElementsAre(
                   MatchesLabel(passwords_title_str(kExampleDomain)),
@@ -356,12 +375,6 @@
                   MatchesItem(ASCIIToUTF16("S3cur3"), password_for_str("Ben"),
                               true, ItemType::NON_INTERACTIVE_SUGGESTION),
                   IsDivider(), MatchesOption(manage_passwords_str()))));
-
-  // Set any, non-empty password list.
-  controller()->SavePasswordsForOrigin({CreateEntry("Ben", "S3cur3").first},
-                                       url::Origin::Create(GURL(kExampleSite)));
-
-  // Pretend that any input in the same frame was focused.
   controller()->RefreshSuggestionsForField(
       url::Origin::Create(GURL(kExampleSite)),
       /*is_fillable=*/true,
@@ -369,14 +382,14 @@
 }
 
 TEST_F(PasswordAccessoryControllerTest, ProvidesEmptySuggestionsMessage) {
+  controller()->SavePasswordsForOrigin({},
+                                       url::Origin::Create(GURL(kExampleSite)));
+
   EXPECT_CALL(
       *view(),
       OnItemsAvailable(
           ElementsAre(MatchesLabel(passwords_empty_str(kExampleDomain)),
                       IsDivider(), MatchesOption(manage_passwords_str()))));
-
-  controller()->SavePasswordsForOrigin({},
-                                       url::Origin::Create(GURL(kExampleSite)));
   controller()->RefreshSuggestionsForField(
       url::Origin::Create(GURL(kExampleSite)),
       /*is_fillable=*/true,
@@ -436,6 +449,10 @@
 }
 
 TEST_F(PasswordAccessoryControllerTest, PasswordFieldChangesSuggestionType) {
+  controller()->SavePasswordsForOrigin({CreateEntry("Ben", "S3cur3").first},
+                                       url::Origin::Create(GURL(kExampleSite)));
+  // Pretend a username field was focused. This should result in non-interactive
+  // suggestion.
   EXPECT_CALL(*view(),
               OnItemsAvailable(ElementsAre(
                   MatchesLabel(passwords_title_str(kExampleDomain)),
@@ -444,10 +461,6 @@
                   MatchesItem(ASCIIToUTF16("S3cur3"), password_for_str("Ben"),
                               true, ItemType::NON_INTERACTIVE_SUGGESTION),
                   IsDivider(), MatchesOption(manage_passwords_str()))));
-  // Set any, non-empty password list and pretend a username field was focused.
-  // This should result in the non-interactive suggestion expected above.
-  controller()->SavePasswordsForOrigin({CreateEntry("Ben", "S3cur3").first},
-                                       url::Origin::Create(GURL(kExampleSite)));
   controller()->RefreshSuggestionsForField(
       url::Origin::Create(GURL(kExampleSite)),
       /*is_fillable=*/true,
@@ -470,6 +483,8 @@
 }
 
 TEST_F(PasswordAccessoryControllerTest, CachesIsReplacedByNewPasswords) {
+  controller()->SavePasswordsForOrigin({CreateEntry("Ben", "S3cur3").first},
+                                       url::Origin::Create(GURL(kExampleSite)));
   EXPECT_CALL(*view(),
               OnItemsAvailable(ElementsAre(
                   MatchesLabel(passwords_title_str(kExampleDomain)),
@@ -478,13 +493,13 @@
                   MatchesItem(ASCIIToUTF16("S3cur3"), password_for_str("Ben"),
                               true, ItemType::NON_INTERACTIVE_SUGGESTION),
                   IsDivider(), MatchesOption(manage_passwords_str()))));
-  controller()->SavePasswordsForOrigin({CreateEntry("Ben", "S3cur3").first},
-                                       url::Origin::Create(GURL(kExampleSite)));
   controller()->RefreshSuggestionsForField(
       url::Origin::Create(GURL(kExampleSite)),
       /*is_fillable=*/true,
       /*is_password_field=*/false);
 
+  controller()->SavePasswordsForOrigin({CreateEntry("Alf", "M3lm4k").first},
+                                       url::Origin::Create(GURL(kExampleSite)));
   EXPECT_CALL(*view(),
               OnItemsAvailable(ElementsAre(
                   MatchesLabel(passwords_title_str(kExampleDomain)),
@@ -493,8 +508,6 @@
                   MatchesItem(ASCIIToUTF16("M3lm4k"), password_for_str("Alf"),
                               true, ItemType::NON_INTERACTIVE_SUGGESTION),
                   IsDivider(), MatchesOption(manage_passwords_str()))));
-  controller()->SavePasswordsForOrigin({CreateEntry("Alf", "M3lm4k").first},
-                                       url::Origin::Create(GURL(kExampleSite)));
   controller()->RefreshSuggestionsForField(
       url::Origin::Create(GURL(kExampleSite)),
       /*is_fillable=*/true,
@@ -502,6 +515,10 @@
 }
 
 TEST_F(PasswordAccessoryControllerTest, UnfillableFieldClearsSuggestions) {
+  controller()->SavePasswordsForOrigin({CreateEntry("Ben", "S3cur3").first},
+                                       url::Origin::Create(GURL(kExampleSite)));
+  // Pretend a username field was focused. This should result in non-emtpy
+  // suggestions.
   EXPECT_CALL(*view(),
               OnItemsAvailable(ElementsAre(
                   MatchesLabel(passwords_title_str(kExampleDomain)),
@@ -510,10 +527,6 @@
                   MatchesItem(ASCIIToUTF16("S3cur3"), password_for_str("Ben"),
                               true, ItemType::NON_INTERACTIVE_SUGGESTION),
                   IsDivider(), MatchesOption(manage_passwords_str()))));
-  // Set any, non-empty password list and pretend a username field was focused.
-  // This should result in the non-emtpy suggestions expected above.
-  controller()->SavePasswordsForOrigin({CreateEntry("Ben", "S3cur3").first},
-                                       url::Origin::Create(GURL(kExampleSite)));
   controller()->RefreshSuggestionsForField(
       url::Origin::Create(GURL(kExampleSite)),
       /*is_fillable=*/true,
@@ -530,3 +543,147 @@
       /*is_fillable=*/false,
       /*is_password_field=*/false);  // Unused.
 }
+
+TEST_F(PasswordAccessoryControllerTest, NavigatingMainFrameClearsSuggestions) {
+  // Set any, non-empty password list and pretend a username field was focused.
+  // This should result in non-emtpy suggestions.
+  controller()->SavePasswordsForOrigin({CreateEntry("Ben", "S3cur3").first},
+                                       url::Origin::Create(GURL(kExampleSite)));
+  EXPECT_CALL(*view(),
+              OnItemsAvailable(ElementsAre(
+                  MatchesLabel(passwords_title_str(kExampleDomain)),
+                  MatchesItem(ASCIIToUTF16("Ben"), ASCIIToUTF16("Ben"), false,
+                              ItemType::SUGGESTION),
+                  MatchesItem(ASCIIToUTF16("S3cur3"), password_for_str("Ben"),
+                              true, ItemType::NON_INTERACTIVE_SUGGESTION),
+                  IsDivider(), MatchesOption(manage_passwords_str()))));
+  controller()->RefreshSuggestionsForField(
+      url::Origin::Create(GURL(kExampleSite)),
+      /*is_fillable=*/true,
+      /*is_password_field=*/false);
+
+  // Pretend that the focus was lost or moved to an unfillable field.
+  NavigateAndCommit(GURL("https://random.other-site.org/"));
+  controller()->DidNavigateMainFrame();
+
+  // Now, only the empty state message should be sent.
+  EXPECT_CALL(*view(),
+              OnItemsAvailable(ElementsAre(
+                  MatchesLabel(passwords_empty_str("random.other-site.org")),
+                  IsDivider(), MatchesOption(manage_passwords_str()))));
+  controller()->RefreshSuggestionsForField(
+      url::Origin::Create(GURL("https://random.other-site.org/")),
+      /*is_fillable=*/true,
+      /*is_password_field=*/false);  // Unused.
+}
+
+TEST_F(PasswordAccessoryControllerTest, FetchFaviconForCurrentUrl) {
+  base::MockCallback<base::OnceCallback<void(const gfx::Image&)>> mock_callback;
+
+  EXPECT_CALL(*view(), OnItemsAvailable(_));
+  controller()->RefreshSuggestionsForField(
+      url::Origin::Create(GURL(kExampleSite)),
+      /*is_fillable=*/true,
+      /*is_password_field=*/false);
+
+  EXPECT_CALL(*favicon_service(),
+              GetFaviconImageForPageURL(GURL(kExampleSite), _, _))
+      .WillOnce(favicon::PostReply<3>(favicon_base::FaviconImageResult()));
+  EXPECT_CALL(mock_callback, Run);
+  controller()->GetFavicon(mock_callback.Get());
+  base::RunLoop().RunUntilIdle();
+}
+
+TEST_F(PasswordAccessoryControllerTest, RequestsFaviconsOnceForOneOrigin) {
+  base::MockCallback<base::OnceCallback<void(const gfx::Image&)>> mock_callback;
+
+  EXPECT_CALL(*view(), OnItemsAvailable(_));
+  controller()->RefreshSuggestionsForField(
+      url::Origin::Create(GURL(kExampleSite)),
+      /*is_fillable=*/true,
+      /*is_password_field=*/false);
+
+  EXPECT_CALL(*favicon_service(),
+              GetFaviconImageForPageURL(GURL(kExampleSite), _, _))
+      .WillOnce(favicon::PostReply<3>(favicon_base::FaviconImageResult()));
+  EXPECT_CALL(mock_callback, Run).Times(2);
+  controller()->GetFavicon(mock_callback.Get());
+  // The favicon service should already start to work on the request.
+  Mock::VerifyAndClearExpectations(favicon_service());
+
+  // This call is only enqueued (and the callback will be called afterwards).
+  controller()->GetFavicon(mock_callback.Get());
+
+  // After the async task is finished, both callbacks must be called.
+  base::RunLoop().RunUntilIdle();
+}
+
+TEST_F(PasswordAccessoryControllerTest, FaviconsAreCachedUntilNavigation) {
+  base::MockCallback<base::OnceCallback<void(const gfx::Image&)>> mock_callback;
+
+  // We need a result with a non-empty image or it won't get cached.
+  favicon_base::FaviconImageResult non_empty_result;
+  SkBitmap bitmap;
+  bitmap.allocN32Pixels(32, 32);
+  non_empty_result.image = gfx::Image::CreateFrom1xBitmap(bitmap);
+
+  // Populate the cache by requesting a favicon.
+  EXPECT_CALL(*view(), OnItemsAvailable(_));
+  controller()->RefreshSuggestionsForField(
+      url::Origin::Create(GURL(kExampleSite)),
+      /*is_fillable=*/true,
+      /*is_password_field=*/false);
+
+  EXPECT_CALL(*favicon_service(),
+              GetFaviconImageForPageURL(GURL(kExampleSite), _, _))
+      .WillOnce(favicon::PostReply<3>(non_empty_result));
+  EXPECT_CALL(mock_callback, Run).Times(1);
+  controller()->GetFavicon(mock_callback.Get());
+
+  base::RunLoop().RunUntilIdle();
+  Mock::VerifyAndClearExpectations(&mock_callback);
+
+  // This call is handled by the cache - no favicon service, no async request.
+  EXPECT_CALL(mock_callback, Run).Times(1);
+  controller()->GetFavicon(mock_callback.Get());
+  Mock::VerifyAndClearExpectations(&mock_callback);
+  Mock::VerifyAndClearExpectations(favicon_service());
+
+  // The navigation to another origin clears the cache.
+  NavigateAndCommit(GURL("https://random.other-site.org/"));
+  controller()->DidNavigateMainFrame();
+  NavigateAndCommit(GURL(kExampleSite));  // Same origin as intially.
+  controller()->DidNavigateMainFrame();
+  EXPECT_CALL(*view(), OnItemsAvailable(_));
+  controller()->RefreshSuggestionsForField(
+      url::Origin::Create(GURL(kExampleSite)), true, false);
+
+  // The cache was cleared, so now the service has to be queried again.
+  EXPECT_CALL(*favicon_service(),
+              GetFaviconImageForPageURL(GURL(kExampleSite), _, _))
+      .WillOnce(favicon::PostReply<3>(non_empty_result));
+  EXPECT_CALL(mock_callback, Run).Times(1);
+  controller()->GetFavicon(mock_callback.Get());
+  base::RunLoop().RunUntilIdle();
+}
+
+TEST_F(PasswordAccessoryControllerTest, NoFaviconCallbacksWhenOriginChanges) {
+  base::MockCallback<base::OnceCallback<void(const gfx::Image&)>> mock_callback;
+
+  EXPECT_CALL(*view(), OnItemsAvailable(_)).Times(2);
+  controller()->RefreshSuggestionsForField(
+      url::Origin::Create(GURL(kExampleSite)), true, false);
+
+  // Right after starting the favicon request for example.com, another frame on
+  // the same site is focused. Even if the request is completed, the callback
+  // should not be called because the origin of the suggestions has changed.
+  EXPECT_CALL(*favicon_service(),
+              GetFaviconImageForPageURL(GURL(kExampleSite), _, _))
+      .WillOnce(favicon::PostReply<3>(favicon_base::FaviconImageResult()));
+  EXPECT_CALL(mock_callback, Run).Times(0);
+  controller()->GetFavicon(mock_callback.Get());
+  controller()->RefreshSuggestionsForField(
+      url::Origin::Create(GURL("https://other.frame.com/")), true, false);
+
+  base::RunLoop().RunUntilIdle();
+}
diff --git a/chrome/browser/policy/browser_dm_token_storage_mac.mm b/chrome/browser/policy/browser_dm_token_storage_mac.mm
index f0fd5a67..68fa61c8 100644
--- a/chrome/browser/policy/browser_dm_token_storage_mac.mm
+++ b/chrome/browser/policy/browser_dm_token_storage_mac.mm
@@ -16,7 +16,6 @@
 #include "base/mac/foundation_util.h"
 #include "base/mac/scoped_cftyperef.h"
 #include "base/mac/scoped_ioobject.h"
-#import "base/mac/scoped_nsautorelease_pool.h"
 #include "base/no_destructor.h"
 #include "base/path_service.h"
 #include "base/sha1.h"
@@ -37,8 +36,8 @@
 
 const char kDmTokenBaseDir[] =
     FILE_PATH_LITERAL("Google/Chrome Cloud Enrollment/");
-NSString* const kEnrollmentTokenPolicyName =
-    @"MachineLevelUserCloudPolicyEnrollmentToken";
+const CFStringRef kEnrollmentTokenPolicyName =
+    CFSTR("MachineLevelUserCloudPolicyEnrollmentToken");
 
 bool GetDmTokenFilePath(base::FilePath* token_file_path,
                         const std::string& client_id,
@@ -111,16 +110,29 @@
 }
 
 std::string BrowserDMTokenStorageMac::InitEnrollmentToken() {
-  base::mac::ScopedNSAutoreleasePool pool;
-
   // Since the configuration management infrastructure is not initialized when
   // this code runs, read the policy preference directly.
-  NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
-  NSString* value = [defaults stringForKey:kEnrollmentTokenPolicyName];
-  if (value && [defaults objectIsForcedForKey:kEnrollmentTokenPolicyName])
-    return base::SysNSStringToUTF8(value);
-  else
+#if defined(GOOGLE_CHROME_BUILD)
+  // Explicitly access the "com.google.Chrome" bundle ID, no matter what this
+  // app's bundle ID actually is. All channels of Chrome should obey the same
+  // policies.
+  CFStringRef bundle_id = CFSTR("com.google.Chrome");
+#else
+  base::ScopedCFTypeRef<CFStringRef> bundle_id(
+      base::SysUTF8ToCFStringRef(base::mac::BaseBundleID()));
+#endif
+
+  base::ScopedCFTypeRef<CFPropertyListRef> value(
+      CFPreferencesCopyAppValue(kEnrollmentTokenPolicyName, bundle_id));
+
+  if (!value ||
+      !CFPreferencesAppValueIsForced(kEnrollmentTokenPolicyName, bundle_id))
     return std::string();
+  CFStringRef value_string = base::mac::CFCast<CFStringRef>(value);
+  if (!value_string)
+    return std::string();
+
+  return base::SysCFStringRefToUTF8(value_string);
 }
 
 std::string BrowserDMTokenStorageMac::InitDMToken() {
diff --git a/chrome/browser/policy/policy_path_parser_mac.mm b/chrome/browser/policy/policy_path_parser_mac.mm
index 92e32e4..eb093e8 100644
--- a/chrome/browser/policy/policy_path_parser_mac.mm
+++ b/chrome/browser/policy/policy_path_parser_mac.mm
@@ -14,7 +14,8 @@
 
 #include "base/files/file_path.h"
 #include "base/logging.h"
-#import "base/mac/scoped_nsautorelease_pool.h"
+#include "base/mac/foundation_util.h"
+#include "base/mac/scoped_cftyperef.h"
 #include "base/macros.h"
 #include "base/strings/sys_string_conversions.h"
 #include "components/policy/policy_constants.h"
@@ -28,16 +29,15 @@
 const char kMacUsersDirectory[] = "${users}";
 const char kMacDocumentsFolderVarName[] = "${documents}";
 
-struct MacFolderNamesToSPDMaping {
+struct MacFolderNamesToSPDMapping {
   const char* name;
   NSSearchPathDirectory id;
 };
 
 // Mapping from variable names to MacOS NSSearchPathDirectory ids.
-const MacFolderNamesToSPDMaping mac_folder_mapping[] = {
-    { kMacUsersDirectory, NSUserDirectory},
-    { kMacDocumentsFolderVarName, NSDocumentDirectory}
-};
+const MacFolderNamesToSPDMapping mac_folder_mapping[] = {
+    {kMacUsersDirectory, NSUserDirectory},
+    {kMacDocumentsFolderVarName, NSDocumentDirectory}};
 
 // Replaces all variable occurrences in the policy string with the respective
 // system settings values.
@@ -54,14 +54,14 @@
     result = result.substr(1, result.length() - 2);
   }
   // First translate all path variables we recognize.
-  for (size_t i = 0; i < arraysize(mac_folder_mapping); ++i) {
-    size_t position = result.find(mac_folder_mapping[i].name);
+  for (const auto& mapping : mac_folder_mapping) {
+    size_t position = result.find(mapping.name);
     if (position != std::string::npos) {
       NSArray* searchpaths = NSSearchPathForDirectoriesInDomains(
-          mac_folder_mapping[i].id, NSAllDomainsMask, true);
+          mapping.id, NSAllDomainsMask, true);
       if ([searchpaths count] > 0) {
         NSString *variable_value = [searchpaths objectAtIndex:0];
-        result.replace(position, strlen(mac_folder_mapping[i].name),
+        result.replace(position, strlen(mapping.name),
                        base::SysNSStringToUTF8(variable_value));
       }
     }
@@ -79,39 +79,51 @@
   }
   position = result.find(kMachineNamePolicyVarName);
   if (position != std::string::npos) {
-    SCDynamicStoreContext context = { 0, NULL, NULL, NULL };
-    SCDynamicStoreRef store = SCDynamicStoreCreate(kCFAllocatorDefault,
-                                                   CFSTR("policy_subsystem"),
-                                                   NULL, &context);
-    CFStringRef machinename = SCDynamicStoreCopyLocalHostName(store);
+    SCDynamicStoreContext context = {0, nullptr, nullptr, nullptr};
+    base::ScopedCFTypeRef<SCDynamicStoreRef> store(SCDynamicStoreCreate(
+        kCFAllocatorDefault, CFSTR("policy_subsystem"), nullptr, &context));
+    base::ScopedCFTypeRef<CFStringRef> machinename(
+        SCDynamicStoreCopyLocalHostName(store));
     if (machinename) {
       result.replace(position, strlen(kMachineNamePolicyVarName),
                      base::SysCFStringRefToUTF8(machinename));
-      CFRelease(machinename);
     } else {
       int error = SCError();
       LOG(ERROR) << "Machine name variable can not be resolved. Error: "
                  << error << " - " << SCErrorString(error);
     }
-    CFRelease(store);
   }
   return result;
 }
 
 void CheckUserDataDirPolicy(base::FilePath* user_data_dir) {
-  base::mac::ScopedNSAutoreleasePool pool;
-
   // Since the configuration management infrastructure is not initialized when
   // this code runs, read the policy preference directly.
-  NSString* key = base::SysUTF8ToNSString(policy::key::kUserDataDir);
-  NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
-  NSString* value = [defaults stringForKey:key];
-  if (value && [defaults objectIsForcedForKey:key]) {
-    std::string string_value = base::SysNSStringToUTF8(value);
-    // Now replace any vars the user might have used.
-    string_value = policy::path_parser::ExpandPathVariables(string_value);
-    *user_data_dir = base::FilePath(string_value);
-  }
+#if defined(GOOGLE_CHROME_BUILD)
+  // Explicitly access the "com.google.Chrome" bundle ID, no matter what this
+  // app's bundle ID actually is. All channels of Chrome should obey the same
+  // policies.
+  CFStringRef bundle_id = CFSTR("com.google.Chrome");
+#else
+  base::ScopedCFTypeRef<CFStringRef> bundle_id(
+      base::SysUTF8ToCFStringRef(base::mac::BaseBundleID()));
+#endif
+
+  base::ScopedCFTypeRef<CFStringRef> key(
+      base::SysUTF8ToCFStringRef(policy::key::kUserDataDir));
+  base::ScopedCFTypeRef<CFPropertyListRef> value(
+      CFPreferencesCopyAppValue(key, bundle_id));
+
+  if (!value || !CFPreferencesAppValueIsForced(key, bundle_id))
+    return;
+  CFStringRef value_string = base::mac::CFCast<CFStringRef>(value);
+  if (!value_string)
+    return;
+
+  // Now replace any vars the user might have used.
+  std::string string_value = base::SysCFStringRefToUTF8(value_string);
+  string_value = policy::path_parser::ExpandPathVariables(string_value);
+  *user_data_dir = base::FilePath(string_value);
 }
 
 void CheckDiskCacheDirPolicy(base::FilePath* user_data_dir) {
diff --git a/chrome/browser/renderer_host/site_per_process_text_input_browsertest.cc b/chrome/browser/renderer_host/site_per_process_text_input_browsertest.cc
index c06ff41..5c8bdc8c 100644
--- a/chrome/browser/renderer_host/site_per_process_text_input_browsertest.cc
+++ b/chrome/browser/renderer_host/site_per_process_text_input_browsertest.cc
@@ -10,6 +10,8 @@
 #include "build/build_config.h"
 #include "chrome/browser/chrome_content_browser_client.h"
 #include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_window.h"
+#include "chrome/browser/ui/location_bar/location_bar.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/interactive_test_utils.h"
@@ -639,6 +641,41 @@
   reset_state_observer.Wait();
 }
 
+#if defined(USE_AURA)
+// This test creates a blank page and adds an <input> to it. Then, the <input>
+// is focused, UI is focused, then the input is refocused. The test verifies
+// that selection bounds change with the refocus (see https://crbug.com/864563).
+IN_PROC_BROWSER_TEST_F(SitePerProcessTextInputManagerTest,
+                       SelectionBoundsChangeAfterRefocusInput) {
+  CreateIframePage("a()");
+  content::RenderFrameHost* main_frame = GetFrame(IndexVector{});
+  content::RenderWidgetHostView* view = main_frame->GetView();
+  content::WebContents* web_contents = active_contents();
+  AddInputFieldToFrame(main_frame, "text", "", false);
+
+  auto focus_input_and_wait_for_selection_bounds_change =
+      [&main_frame, &web_contents, &view]() {
+        ViewSelectionBoundsChangedObserver bounds_observer(web_contents, view);
+        // SimulateKeyPress(web_contents, ui::DomKey::TAB, ui::DomCode::TAB,
+        //               ui::VKEY_TAB, false, true, false, false);
+        EXPECT_TRUE(ExecuteScript(main_frame,
+                                  "document.querySelector('input').focus();"));
+        bounds_observer.Wait();
+      };
+
+  focus_input_and_wait_for_selection_bounds_change();
+
+  // Focus location bar.
+  BrowserWindow* window = browser()->window();
+  ASSERT_TRUE(window);
+  LocationBar* location_bar = window->GetLocationBar();
+  ASSERT_TRUE(location_bar);
+  location_bar->FocusLocation(true);
+
+  focus_input_and_wait_for_selection_bounds_change();
+}
+#endif
+
 // This test verifies that if we have a focused <input> in the main frame and
 // the tab is closed, TextInputManager handles unregistering itself and
 // notifying the observers properly (see https://crbug.com/669375).
diff --git a/chrome/browser/resource_coordinator/leveldb_site_characteristics_database.cc b/chrome/browser/resource_coordinator/leveldb_site_characteristics_database.cc
index 015a61e..6bb8317d 100644
--- a/chrome/browser/resource_coordinator/leveldb_site_characteristics_database.cc
+++ b/chrome/browser/resource_coordinator/leveldb_site_characteristics_database.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/resource_coordinator/leveldb_site_characteristics_database.h"
 
+#include <limits>
 #include <string>
 
 #include "base/files/file_util.h"
@@ -11,6 +12,7 @@
 #include "base/memory/ptr_util.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/metrics/histogram_macros.h"
+#include "base/strings/string_number_conversions.h"
 #include "base/task_runner_util.h"
 #include "base/threading/thread_restrictions.h"
 #include "chrome/browser/resource_coordinator/utils.h"
@@ -84,6 +86,23 @@
 
 }  // namespace
 
+// Version history:
+//
+// - {no version}:
+//     - Initial launch of the Database.
+// - 1:
+//     - Ignore the title/favicon events happening during the first fews seconds
+//       after a tab being loaded.
+//     - Ignore the audio events happening during the first fews seconds after a
+//       tab being backgrounded.
+//
+// Transform logic:
+//     - From {no version} to v1: The database is erased entirely.
+const size_t LevelDBSiteCharacteristicsDatabase::kDbVersion = 1U;
+
+const char LevelDBSiteCharacteristicsDatabase::kDbMetadataKey[] =
+    "database_metadata";
+
 // Helper class used to run all the blocking operations posted by
 // LocalSiteCharacteristicDatabase on a TaskScheduler sequence with the
 // |MayBlock()| trait.
@@ -102,7 +121,8 @@
   }
   ~AsyncHelper() = default;
 
-  // Open the database from |db_path_| after creating it if it didn't exist.
+  // Open the database from |db_path_| after creating it if it didn't exist,
+  // this reset the database if it's not at the expected version.
   void OpenOrCreateDatabase();
 
   // Implementations of the DB manipulation functions of
@@ -118,7 +138,22 @@
 
   bool DBIsInitialized() { return db_ != nullptr; }
 
+  leveldb::DB* GetDBForTesting() {
+    DCHECK(DBIsInitialized());
+    return db_.get();
+  }
+
  private:
+  enum class OpeningType {
+    // A new database has been created.
+    kNewDb,
+    // An existing database has been used.
+    kExistingDb,
+  };
+
+  // Implementation for the OpenOrCreateDatabase function.
+  OpeningType OpenOrCreateDatabaseImpl();
+
   // The on disk location of the database.
   const base::FilePath db_path_;
   // The connection to the LevelDB database.
@@ -133,43 +168,42 @@
 };
 
 void LevelDBSiteCharacteristicsDatabase::AsyncHelper::OpenOrCreateDatabase() {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  DCHECK(!db_) << "Database already open";
-  base::AssertBlockingAllowed();
-
-  // Report the on disk size of the database if it already exists.
-  if (base::DirectoryExists(db_path_)) {
-    int64_t db_ondisk_size_in_bytes = base::ComputeDirectorySize(db_path_);
-    UMA_HISTOGRAM_MEMORY_KB("ResourceCoordinator.LocalDB.OnDiskSize",
-                            db_ondisk_size_in_bytes / 1024);
+  OpeningType opening_type = OpenOrCreateDatabaseImpl();
+  if (!db_)
+    return;
+  std::string db_metadata;
+  leveldb::Status s = db_->Get(
+      read_options_, LevelDBSiteCharacteristicsDatabase::kDbMetadataKey,
+      &db_metadata);
+  bool is_expected_version = false;
+  if (s.ok()) {
+    // The metadata only contains the version of the database as a size_t value
+    // for now.
+    size_t version = std::numeric_limits<size_t>::max();
+    CHECK(base::StringToSizeT(db_metadata, &version));
+    if (version == LevelDBSiteCharacteristicsDatabase::kDbVersion)
+      is_expected_version = true;
   }
-
-  leveldb_env::Options options;
-  options.create_if_missing = true;
-  leveldb::Status status =
-      leveldb_env::OpenDB(options, db_path_.AsUTF8Unsafe(), &db_);
-
-  ReportInitStatus(kInitStatusHistogramLabel, status);
-
-  if (status.ok())
-    return;
-
-  if (!ShouldAttemptDbRepair(status))
-    return;
-
-  if (RepairDatabase(db_path_.AsUTF8Unsafe())) {
-    status = leveldb_env::OpenDB(options, db_path_.AsUTF8Unsafe(), &db_);
-    ReportInitStatus(kInitStatusAfterRepairHistogramLabel, status);
-    if (status.ok())
+  // TODO(sebmarchand): Add a migration engine rather than flushing the database
+  // for every version change, https://crbug.com/866540.
+  if ((opening_type == OpeningType::kExistingDb) && !is_expected_version) {
+    DLOG(ERROR) << "Invalid DB version, recreating it.";
+    ClearDatabase();
+    // The database might fail to open.
+    if (!db_)
       return;
+    opening_type = OpeningType::kNewDb;
   }
-
-  // Delete the database and try to open it one last time.
-  if (leveldb_chrome::DeleteDB(db_path_, options).ok()) {
-    status = leveldb_env::OpenDB(options, db_path_.AsUTF8Unsafe(), &db_);
-    ReportInitStatus(kInitStatusAfterDeleteHistogramLabel, status);
-    if (!status.ok())
-      db_.reset();
+  if (opening_type == OpeningType::kNewDb) {
+    std::string metadata =
+        base::NumberToString(LevelDBSiteCharacteristicsDatabase::kDbVersion);
+    s = db_->Put(write_options_,
+                  LevelDBSiteCharacteristicsDatabase::kDbMetadataKey,
+                  metadata);
+    if (!s.ok()) {
+      DLOG(ERROR) << "Error while inserting the metadata in the site "
+                  << "characteristics database: " << s.ToString();
+    }
   }
 }
 
@@ -190,8 +224,8 @@
     site_characteristic_proto = SiteCharacteristicsProto();
     if (!site_characteristic_proto->ParseFromString(protobuf_value)) {
       site_characteristic_proto = base::nullopt;
-      LOG(ERROR) << "Error while trying to parse a SiteCharacteristicsProto "
-                 << "protobuf.";
+      DLOG(ERROR) << "Error while trying to parse a SiteCharacteristicsProto "
+                  << "protobuf.";
     }
   }
   return site_characteristic_proto;
@@ -211,8 +245,9 @@
       db_->Put(write_options_, SerializeOriginIntoDatabaseKey(origin),
                site_characteristic_proto.SerializeAsString());
   if (!s.ok()) {
-    LOG(ERROR) << "Error while inserting an element in the site characteristic "
-               << "database: " << s.ToString();
+    DLOG(ERROR)
+        << "Error while inserting an element in the site characteristics "
+        << "database: " << s.ToString();
   }
 }
 
@@ -245,13 +280,60 @@
   db_.reset();
   leveldb::Status status = leveldb::DestroyDB(db_path_.AsUTF8Unsafe(), options);
   if (status.ok()) {
-    OpenOrCreateDatabase();
+    OpenOrCreateDatabaseImpl();
   } else {
     LOG(WARNING) << "Failed to destroy the site characteristics database: "
                  << status.ToString();
   }
 }
 
+LevelDBSiteCharacteristicsDatabase::AsyncHelper::OpeningType
+LevelDBSiteCharacteristicsDatabase::AsyncHelper::OpenOrCreateDatabaseImpl() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  DCHECK(!db_) << "Database already open";
+  base::AssertBlockingAllowed();
+
+  OpeningType opening_type = OpeningType::kNewDb;
+
+  // Report the on disk size of the database if it already exists.
+  if (base::DirectoryExists(db_path_)) {
+    opening_type = OpeningType::kExistingDb;
+    int64_t db_ondisk_size_in_bytes = base::ComputeDirectorySize(db_path_);
+    UMA_HISTOGRAM_MEMORY_KB("ResourceCoordinator.LocalDB.OnDiskSize",
+                            db_ondisk_size_in_bytes / 1024);
+  }
+
+  leveldb_env::Options options;
+  options.create_if_missing = true;
+  leveldb::Status status =
+      leveldb_env::OpenDB(options, db_path_.AsUTF8Unsafe(), &db_);
+
+  ReportInitStatus(kInitStatusHistogramLabel, status);
+
+  if (status.ok())
+    return opening_type;
+
+  if (!ShouldAttemptDbRepair(status))
+    return opening_type;
+
+  if (RepairDatabase(db_path_.AsUTF8Unsafe())) {
+    status = leveldb_env::OpenDB(options, db_path_.AsUTF8Unsafe(), &db_);
+    ReportInitStatus(kInitStatusAfterRepairHistogramLabel, status);
+    if (status.ok())
+      return opening_type;
+  }
+
+  // Delete the database and try to open it one last time.
+  if (leveldb_chrome::DeleteDB(db_path_, options).ok()) {
+    status = leveldb_env::OpenDB(options, db_path_.AsUTF8Unsafe(), &db_);
+    ReportInitStatus(kInitStatusAfterDeleteHistogramLabel, status);
+    if (!status.ok())
+      db_.reset();
+  }
+
+  return opening_type;
+}
+
 LevelDBSiteCharacteristicsDatabase::LevelDBSiteCharacteristicsDatabase(
     const base::FilePath& db_path)
     : blocking_task_runner_(base::CreateSequencedTaskRunnerWithTraits(
@@ -322,4 +404,8 @@
   return async_helper_->DBIsInitialized();
 }
 
+leveldb::DB* LevelDBSiteCharacteristicsDatabase::GetDBForTesting() {
+  return async_helper_->GetDBForTesting();
+}
+
 }  // namespace resource_coordinator
diff --git a/chrome/browser/resource_coordinator/leveldb_site_characteristics_database.h b/chrome/browser/resource_coordinator/leveldb_site_characteristics_database.h
index 65351cc8..e51244b 100644
--- a/chrome/browser/resource_coordinator/leveldb_site_characteristics_database.h
+++ b/chrome/browser/resource_coordinator/leveldb_site_characteristics_database.h
@@ -45,6 +45,16 @@
 
   bool DatabaseIsInitializedForTesting();
 
+  // Returns a raw pointer to the database for testing purposes. Note that as
+  // the DB operations are made on a separate sequence it's recommended to call
+  // ScopedTaskEnvironment::RunUntilIdle before calling this function to ensure
+  // that the database has been fully initialized. The LevelDB implementation is
+  // thread safe.
+  leveldb::DB* GetDBForTesting();
+
+  static const size_t kDbVersion;
+  static const char kDbMetadataKey[];
+
  private:
   class AsyncHelper;
 
diff --git a/chrome/browser/resource_coordinator/leveldb_site_characteristics_database_unittest.cc b/chrome/browser/resource_coordinator/leveldb_site_characteristics_database_unittest.cc
index d3b5fae..d968b646 100644
--- a/chrome/browser/resource_coordinator/leveldb_site_characteristics_database_unittest.cc
+++ b/chrome/browser/resource_coordinator/leveldb_site_characteristics_database_unittest.cc
@@ -4,9 +4,12 @@
 
 #include "chrome/browser/resource_coordinator/leveldb_site_characteristics_database.h"
 
+#include <limits>
+
 #include "base/bind.h"
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
+#include "base/strings/string_number_conversions.h"
 #include "base/strings/stringprintf.h"
 #include "base/test/metrics/histogram_tester.h"
 #include "base/test/scoped_task_environment.h"
@@ -83,15 +86,19 @@
     EXPECT_TRUE(temp_dir_.Delete());
   }
 
-  void OpenDB() { OpenDB(temp_dir_.GetPath()); }
+  void OpenDB() {
+    OpenDB(temp_dir_.GetPath().Append(FILE_PATH_LITERAL("LocalDB")));
+  }
 
   void OpenDB(base::FilePath path) {
     db_ = std::make_unique<LevelDBSiteCharacteristicsDatabase>(path);
     WaitForAsyncOperationsToComplete();
     EXPECT_TRUE(db_);
+    db_path_ = path;
   }
 
   const base::FilePath& GetTempPath() { return temp_dir_.GetPath(); }
+  const base::FilePath& GetDBPath() { return db_path_; }
 
  protected:
   // Try to read an entry from the database, returns true if the entry is
@@ -136,6 +143,7 @@
 
   const url::Origin kDummyOrigin = url::Origin::Create(GURL("http://foo.com"));
 
+  base::FilePath db_path_;
   base::test::ScopedTaskEnvironment task_env_;
   base::ScopedTempDir temp_dir_;
   std::unique_ptr<LevelDBSiteCharacteristicsDatabase> db_;
@@ -192,7 +200,7 @@
 
   db_.reset();
 
-  EXPECT_TRUE(leveldb_chrome::CorruptClosedDBForTesting(temp_dir_.GetPath()));
+  EXPECT_TRUE(leveldb_chrome::CorruptClosedDBForTesting(GetDBPath()));
 
   base::HistogramTester histogram_tester;
   histogram_tester.ExpectTotalCount("ResourceCoordinator.LocalDB.DatabaseInit",
@@ -234,4 +242,41 @@
   WaitForAsyncOperationsToComplete();
 }
 
+TEST_F(LevelDBSiteCharacteristicsDatabaseTest, DBGetsClearedOnVersionUpgrade) {
+  leveldb::DB* raw_db = db_->GetDBForTesting();
+  EXPECT_TRUE(raw_db);
+
+  // Remove the entry containing the DB version number, this will cause the DB
+  // to be cleared the next time it gets opened.
+  leveldb::Status s =
+      raw_db->Delete(leveldb::WriteOptions(),
+                     LevelDBSiteCharacteristicsDatabase::kDbMetadataKey);
+  EXPECT_TRUE(s.ok());
+
+  // Add some dummy data to the database to ensure the database gets cleared
+  // when upgrading it to the new version.
+  ::google::protobuf::int64 test_value = 42;
+  SiteCharacteristicsProto stored_proto;
+  InitSiteCharacteristicProto(&stored_proto, test_value);
+  db_->WriteSiteCharacteristicsIntoDB(kDummyOrigin, stored_proto);
+  WaitForAsyncOperationsToComplete();
+
+  db_.reset();
+
+  // Reopen the database and ensure that it has been cleared.
+  OpenDB();
+  raw_db = db_->GetDBForTesting();
+  std::string db_metadata;
+  s = raw_db->Get(leveldb::ReadOptions(),
+                  LevelDBSiteCharacteristicsDatabase::kDbMetadataKey,
+                  &db_metadata);
+  EXPECT_TRUE(s.ok());
+  size_t version = std::numeric_limits<size_t>::max();
+  EXPECT_TRUE(base::StringToSizeT(db_metadata, &version));
+  EXPECT_EQ(LevelDBSiteCharacteristicsDatabase::kDbVersion, version);
+
+  SiteCharacteristicsProto proto_temp;
+  EXPECT_FALSE(ReadFromDB(kDummyOrigin, &proto_temp));
+}
+
 }  // namespace resource_coordinator
diff --git a/chrome/browser/resource_coordinator/tab_load_tracker.cc b/chrome/browser/resource_coordinator/tab_load_tracker.cc
index 6a1bba4..3aac683 100644
--- a/chrome/browser/resource_coordinator/tab_load_tracker.cc
+++ b/chrome/browser/resource_coordinator/tab_load_tracker.cc
@@ -4,8 +4,11 @@
 
 #include "chrome/browser/resource_coordinator/tab_load_tracker.h"
 
+#include <utility>
+
+#include "base/logging.h"
 #include "base/stl_util.h"
-#include "chrome/browser/ui/browser_tab_strip_tracker.h"
+#include "chrome/browser/prerender/prerender_contents.h"
 #include "content/public/browser/navigation_controller.h"
 #include "content/public/browser/navigation_entry.h"
 #include "content/public/browser/web_contents.h"
@@ -66,6 +69,33 @@
   return state_counts_[static_cast<size_t>(LOADED)];
 }
 
+size_t TabLoadTracker::GetUiTabCount() const {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  return ui_tab_state_counts_[static_cast<size_t>(UNLOADED)] +
+         ui_tab_state_counts_[static_cast<size_t>(LOADING)] +
+         ui_tab_state_counts_[static_cast<size_t>(LOADED)];
+}
+
+size_t TabLoadTracker::GetUiTabCount(LoadingState loading_state) const {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  return ui_tab_state_counts_[static_cast<size_t>(loading_state)];
+}
+
+size_t TabLoadTracker::GetUnloadedUiTabCount() const {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  return ui_tab_state_counts_[static_cast<size_t>(UNLOADED)];
+}
+
+size_t TabLoadTracker::GetLoadingUiTabCount() const {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  return ui_tab_state_counts_[static_cast<size_t>(LOADING)];
+}
+
+size_t TabLoadTracker::GetLoadedUiTabCount() const {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  return ui_tab_state_counts_[static_cast<size_t>(LOADED)];
+}
+
 void TabLoadTracker::AddObserver(Observer* observer) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   observers_.AddObserver(observer);
@@ -98,8 +128,11 @@
   data.loading_state = loading_state;
   if (data.loading_state == LOADING)
     data.did_start_loading_seen = true;
+  data.is_ui_tab = IsUiTab(web_contents);
   tabs_.insert(std::make_pair(web_contents, data));
   ++state_counts_[static_cast<size_t>(data.loading_state)];
+  if (data.is_ui_tab)
+    ++ui_tab_state_counts_[static_cast<size_t>(data.loading_state)];
 
   for (Observer& observer : observers_)
     observer.OnStartTracking(web_contents, loading_state);
@@ -113,6 +146,12 @@
   auto loading_state = it->second.loading_state;
   DCHECK_NE(0u, state_counts_[static_cast<size_t>(it->second.loading_state)]);
   --state_counts_[static_cast<size_t>(it->second.loading_state)];
+  if (it->second.is_ui_tab) {
+    DCHECK_NE(
+        0u,
+        ui_tab_state_counts_[static_cast<size_t>(it->second.loading_state)]);
+    --ui_tab_state_counts_[static_cast<size_t>(it->second.loading_state)];
+  }
   tabs_.erase(it);
 
   for (Observer& observer : observers_)
@@ -260,6 +299,11 @@
   --state_counts_[static_cast<size_t>(previous_state)];
   it->second.loading_state = loading_state;
   ++state_counts_[static_cast<size_t>(loading_state)];
+  if (it->second.is_ui_tab) {
+    ++ui_tab_state_counts_[static_cast<size_t>(loading_state)];
+    DCHECK_NE(0u, ui_tab_state_counts_[static_cast<size_t>(previous_state)]);
+    --ui_tab_state_counts_[static_cast<size_t>(previous_state)];
+  }
 
   // If the destination state is LOADED, then also clear the
   // |did_start_loading_seen| state.
@@ -274,6 +318,53 @@
     observer.OnLoadingStateChange(web_contents, previous_state, loading_state);
 }
 
+bool TabLoadTracker::IsUiTab(content::WebContents* web_contents) {
+  // TODO(crbug.com/836409): This should be able to check directly with the
+  // tabstrip UI or use a platform-independent tabstrip observer interface to
+  // learn about |web_contents| associated with the tabstrip, rather than
+  // checking for specific cases where |web_contents| is not a ui tab.
+  if (prerender::PrerenderContents::FromWebContents(web_contents) != nullptr)
+    return false;
+  return true;
+}
+
+void TabLoadTracker::SwapTabContents(content::WebContents* old_contents,
+                                     content::WebContents* new_contents) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  // TODO(crbug.com/836409): This should work by directly tracking tabs that are
+  // attached to UI surfaces instead of relying on being notified directly about
+  // tab contents swaps.
+
+  // Transition |old_contents| to a non-UI tab. If a tab is being swapped out,
+  // then it should exist, we should be tracking it, and it should be a UI tab.
+  DCHECK(old_contents);
+  auto it = tabs_.find(old_contents);
+  DCHECK(it != tabs_.end());
+  DCHECK(it->second.is_ui_tab);
+  it->second.is_ui_tab = false;
+  DCHECK_NE(
+      0u, ui_tab_state_counts_[static_cast<size_t>(it->second.loading_state)]);
+  --ui_tab_state_counts_[static_cast<size_t>(it->second.loading_state)];
+
+  // Transition |new_contents| to a UI tab.
+  DCHECK(IsUiTab(new_contents));
+  it = tabs_.find(new_contents);
+  // |new_contents| will not be tracked if a tab helper wasn't attached yet,
+  // which currently happens for dom distiller. In this case, the tab helper
+  // will be attached and we will start tracking it when it's swapped into the
+  // tab UI, which will happen later in this code path.
+  if (it == tabs_.end())
+    return;
+
+  // |new_contents| shouldn't be considered a UI tab yet. This should catch any
+  // new cases of non-tab web contents that attach tab helpers that we aren't
+  // handling.
+  DCHECK(!it->second.is_ui_tab);
+  // Promote |new_contents| to a UI tab.
+  it->second.is_ui_tab = true;
+  ++ui_tab_state_counts_[static_cast<size_t>(it->second.loading_state)];
+}
+
 TabLoadTracker::Observer::Observer() {}
 
 TabLoadTracker::Observer::~Observer() {}
diff --git a/chrome/browser/resource_coordinator/tab_load_tracker.h b/chrome/browser/resource_coordinator/tab_load_tracker.h
index a2818f8..89239c7 100644
--- a/chrome/browser/resource_coordinator/tab_load_tracker.h
+++ b/chrome/browser/resource_coordinator/tab_load_tracker.h
@@ -90,6 +90,18 @@
   size_t GetLoadingTabCount() const;
   size_t GetLoadedTabCount() const;
 
+  // Returns the total number of UI tabs that are being tracked by this class.
+  // Some WebContents being tracked by this class may not yet be associated with
+  // a UI tab, e.g. prerender contents. To exclude these tabs from counts, use
+  // the Get*UiTabCount() methods.
+  size_t GetUiTabCount() const;
+
+  // Returns the number of UI tabs in each state.
+  size_t GetUiTabCount(LoadingState loading_state) const;
+  size_t GetUnloadedUiTabCount() const;
+  size_t GetLoadingUiTabCount() const;
+  size_t GetLoadedUiTabCount() const;
+
   // Adds/removes an observer. It is up to the observer to ensure their lifetime
   // exceeds that of the TabLoadTracker, as is removed prior to its destruction.
   void AddObserver(Observer* observer);
@@ -99,6 +111,11 @@
   void TransitionStateForTesting(content::WebContents* web_contents,
                                  LoadingState loading_state);
 
+  // Called from CoreTabHelperDelegates when |new_contents| is replacing
+  // |old_contents| in a tab.
+  void SwapTabContents(content::WebContents* old_contents,
+                       content::WebContents* new_contents);
+
  protected:
   // This allows the singleton constructor access to the protected constructor.
   friend class base::NoDestructor<TabLoadTracker>;
@@ -141,6 +158,14 @@
   // from the TabManager.
   void OnPageAlmostIdle(content::WebContents* web_contents);
 
+  // Returns true if |web_contents| is a UI tab and false otherwise. This is
+  // used to filter out cases where tab helpers are attached to a non-UI tab
+  // WebContents, e.g prerender contents.
+  //
+  // This is virtual and protected for unittesting to control when web
+  // contentses are considered ui tabs.
+  virtual bool IsUiTab(content::WebContents* web_contents);
+
  private:
   // For unittesting.
   friend class TestTabLoadTracker;
@@ -149,6 +174,7 @@
   struct WebContentsData {
     LoadingState loading_state = LoadingState::UNLOADED;
     bool did_start_loading_seen = false;
+    bool is_ui_tab = false;
   };
 
   using TabMap = base::flat_map<content::WebContents*, WebContentsData>;
@@ -168,12 +194,17 @@
                        LoadingState loading_state,
                        bool validate_transition);
 
-  // The list of known WebContents and their states.
+  // The list of known WebContents and their states. This includes both UI and
+  // non-UI tabs.
   TabMap tabs_;
 
   // The counts of tabs in each state.
   size_t state_counts_[static_cast<size_t>(LoadingState::kMaxValue) + 1] = {0};
 
+  // The counts of UI tabs in each state.
+  size_t ui_tab_state_counts_[static_cast<size_t>(LoadingState::kMaxValue) +
+                              1] = {0};
+
   base::ObserverList<Observer> observers_;
 
   SEQUENCE_CHECKER(sequence_checker_);
diff --git a/chrome/browser/resource_coordinator/tab_load_tracker_unittest.cc b/chrome/browser/resource_coordinator/tab_load_tracker_unittest.cc
index 9dfdfa3b..2b0a2c9 100644
--- a/chrome/browser/resource_coordinator/tab_load_tracker_unittest.cc
+++ b/chrome/browser/resource_coordinator/tab_load_tracker_unittest.cc
@@ -4,10 +4,18 @@
 
 #include "chrome/browser/resource_coordinator/tab_load_tracker.h"
 
+#include <memory>
+#include <vector>
+
 #include "base/process/kill.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/scoped_feature_list.h"
+#include "chrome/browser/prerender/prerender_handle.h"
+#include "chrome/browser/prerender/prerender_manager.h"
+#include "chrome/browser/prerender/prerender_manager_factory.h"
+#include "chrome/browser/prerender/prerender_test_utils.h"
 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
+#include "chrome/test/base/testing_profile.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "content/public/test/mock_render_process_host.h"
 #include "content/public/test/web_contents_tester.h"
@@ -35,7 +43,7 @@
   using TabLoadTracker::OnPageAlmostIdle;
   using TabLoadTracker::DetermineLoadingState;
 
-  TestTabLoadTracker() {}
+  TestTabLoadTracker() : all_tabs_are_non_ui_tabs_(false) {}
   virtual ~TestTabLoadTracker() {}
 
   // Some accessors for TabLoadTracker internals.
@@ -49,6 +57,19 @@
       return false;
     return it->second.did_start_loading_seen;
   }
+
+  bool IsUiTab(content::WebContents* web_contents) override {
+    if (all_tabs_are_non_ui_tabs_)
+      return false;
+    return TabLoadTracker::IsUiTab(web_contents);
+  }
+
+  void SetAllTabsAreNonUiTabs(bool enabled) {
+    all_tabs_are_non_ui_tabs_ = enabled;
+  }
+
+ private:
+  bool all_tabs_are_non_ui_tabs_;
 };
 
 // A mock observer class.
@@ -143,7 +164,18 @@
     EXPECT_EQ(loaded, tracker().GetLoadedTabCount());
   }
 
-  void StateTransitionsTest(bool enable_pai);
+  void ExpectUiTabCounts(size_t tabs,
+                         size_t unloaded,
+                         size_t loading,
+                         size_t loaded) {
+    EXPECT_EQ(tabs, unloaded + loading + loaded);
+    EXPECT_EQ(tabs, tracker().GetUiTabCount());
+    EXPECT_EQ(unloaded, tracker().GetUnloadedUiTabCount());
+    EXPECT_EQ(loading, tracker().GetLoadingUiTabCount());
+    EXPECT_EQ(loaded, tracker().GetLoadedUiTabCount());
+  }
+
+  void StateTransitionsTest(bool enable_pai, bool use_non_ui_tabs);
 
   TestTabLoadTracker& tracker() { return tracker_; }
   MockObserver& observer() { return observer_; }
@@ -169,6 +201,17 @@
     SCOPED_TRACE("");                 \
     ExpectTabCounts(a, b, c, d);      \
   }
+#define EXPECT_UI_TAB_COUNTS(a, b, c, d) \
+  {                                      \
+    SCOPED_TRACE("");                    \
+    ExpectUiTabCounts(a, b, c, d);       \
+  }
+#define EXPECT_TAB_AND_UI_TAB_COUNTS(a, b, c, d) \
+  {                                              \
+    SCOPED_TRACE("");                            \
+    ExpectTabCounts(a, b, c, d);                 \
+    ExpectUiTabCounts(a, b, c, d);               \
+  }
 
 TEST_F(TabLoadTrackerTest, DetermineLoadingState) {
   auto* tester1 = content::WebContentsTester::For(contents1());
@@ -186,8 +229,10 @@
   EXPECT_EQ(LoadingState::LOADED, tracker().DetermineLoadingState(contents1()));
 }
 
-void TabLoadTrackerTest::StateTransitionsTest(bool enable_pai) {
+void TabLoadTrackerTest::StateTransitionsTest(bool enable_pai,
+                                              bool use_non_ui_tabs) {
   SetPageAlmostIdleFeatureEnabled(enable_pai);
+  tracker().SetAllTabsAreNonUiTabs(use_non_ui_tabs);
 
   auto* tester1 = content::WebContentsTester::For(contents1());
   auto* tester2 = content::WebContentsTester::For(contents2());
@@ -199,20 +244,35 @@
   tester3->NavigateAndCommit(GURL("http://bar.com"));
   tester3->TestSetIsLoading(false);
 
-  // Add the contents to the trackers.
+  // Add the contents to the tracker.
   EXPECT_CALL(observer(), OnStartTracking(contents1(), LoadingState::UNLOADED));
   tracker().StartTracking(contents1());
-  EXPECT_TAB_COUNTS(1, 1, 0, 0);
+  if (use_non_ui_tabs) {
+    EXPECT_TAB_COUNTS(1, 1, 0, 0);
+    EXPECT_UI_TAB_COUNTS(0, 0, 0, 0);
+  } else {
+    EXPECT_TAB_AND_UI_TAB_COUNTS(1, 1, 0, 0);
+  }
   testing::Mock::VerifyAndClearExpectations(&observer());
 
   EXPECT_CALL(observer(), OnStartTracking(contents2(), LoadingState::LOADING));
   tracker().StartTracking(contents2());
-  EXPECT_TAB_COUNTS(2, 1, 1, 0);
+  if (use_non_ui_tabs) {
+    EXPECT_TAB_COUNTS(2, 1, 1, 0);
+    EXPECT_UI_TAB_COUNTS(0, 0, 0, 0);
+  } else {
+    EXPECT_TAB_AND_UI_TAB_COUNTS(2, 1, 1, 0);
+  }
   testing::Mock::VerifyAndClearExpectations(&observer());
 
   EXPECT_CALL(observer(), OnStartTracking(contents3(), LoadingState::LOADED));
   tracker().StartTracking(contents3());
-  EXPECT_TAB_COUNTS(3, 1, 1, 1);
+  if (use_non_ui_tabs) {
+    EXPECT_TAB_COUNTS(3, 1, 1, 1);
+    EXPECT_UI_TAB_COUNTS(0, 0, 0, 0);
+  } else {
+    EXPECT_TAB_AND_UI_TAB_COUNTS(3, 1, 1, 1);
+  }
   testing::Mock::VerifyAndClearExpectations(&observer());
 
   // Start observers for the contents.
@@ -230,10 +290,20 @@
   if (enable_pai) {
     // The state transition should only occur *after* the PAI signal when that
     // feature is enabled.
-    EXPECT_TAB_COUNTS(3, 1, 1, 1);
+    if (use_non_ui_tabs) {
+      EXPECT_TAB_COUNTS(3, 1, 1, 1);
+      EXPECT_UI_TAB_COUNTS(0, 0, 0, 0);
+    } else {
+      EXPECT_TAB_AND_UI_TAB_COUNTS(3, 1, 1, 1);
+    }
     tracker().OnPageAlmostIdle(contents2());
   }
-  EXPECT_TAB_COUNTS(3, 1, 0, 2);
+  if (use_non_ui_tabs) {
+    EXPECT_TAB_COUNTS(3, 1, 0, 2);
+    EXPECT_UI_TAB_COUNTS(0, 0, 0, 0);
+  } else {
+    EXPECT_TAB_AND_UI_TAB_COUNTS(3, 1, 0, 2);
+  }
   testing::Mock::VerifyAndClearExpectations(&observer());
 
   // Start the loading for contents1.
@@ -241,7 +311,12 @@
               OnLoadingStateChange(contents1(), LoadingState::UNLOADED,
                                    LoadingState::LOADING));
   tester1->NavigateAndCommit(GURL("http://baz.com"));
-  EXPECT_TAB_COUNTS(3, 0, 1, 2);
+  if (use_non_ui_tabs) {
+    EXPECT_TAB_COUNTS(3, 0, 1, 2);
+    EXPECT_UI_TAB_COUNTS(0, 0, 0, 0);
+  } else {
+    EXPECT_TAB_AND_UI_TAB_COUNTS(3, 0, 1, 2);
+  }
   testing::Mock::VerifyAndClearExpectations(&observer());
 
   // Stop the loading with an error. The tab should go back to a LOADED
@@ -251,7 +326,12 @@
                                    LoadingState::LOADED));
   tester1->TestDidFailLoadWithError(GURL("http://baz.com"), 500,
                                     base::UTF8ToUTF16("server error"));
-  ExpectTabCounts(3, 0, 0, 3);
+  if (use_non_ui_tabs) {
+    EXPECT_TAB_COUNTS(3, 0, 0, 3);
+    EXPECT_UI_TAB_COUNTS(0, 0, 0, 0);
+  } else {
+    EXPECT_TAB_AND_UI_TAB_COUNTS(3, 0, 0, 3);
+  }
   testing::Mock::VerifyAndClearExpectations(&observer());
 
   // Crash the render process corresponding to the main frame of a tab. This
@@ -263,16 +343,163 @@
       static_cast<content::MockRenderProcessHost*>(
           contents1()->GetMainFrame()->GetProcess());
   rph->SimulateCrash();
-  ExpectTabCounts(3, 1, 0, 2);
+  if (use_non_ui_tabs) {
+    EXPECT_TAB_COUNTS(3, 1, 0, 2);
+    EXPECT_UI_TAB_COUNTS(0, 0, 0, 0);
+  } else {
+    EXPECT_TAB_AND_UI_TAB_COUNTS(3, 1, 0, 2);
+  }
   testing::Mock::VerifyAndClearExpectations(&observer());
 }
 
 TEST_F(TabLoadTrackerTest, StateTransitions) {
-  StateTransitionsTest(false);
+  StateTransitionsTest(false /* enable_pai */, false /* use_non_ui_tabs */);
 }
 
 TEST_F(TabLoadTrackerTest, StateTransitionsPAI) {
-  StateTransitionsTest(true);
+  StateTransitionsTest(true /* enable_pai */, false /* use_non_ui_tabs */);
+}
+
+TEST_F(TabLoadTrackerTest, StateTransitionsNonUiTabs) {
+  StateTransitionsTest(false /* enable_pai */, true /* use_non_ui_tabs */);
+}
+
+TEST_F(TabLoadTrackerTest, StateTransitionsPAINonUiTabs) {
+  StateTransitionsTest(true /* enable_pai */, true /* use_non_ui_tabs */);
+}
+
+TEST_F(TabLoadTrackerTest, PrerenderContentsDoesNotChangeUiTabCounts) {
+  auto* tester1 = content::WebContentsTester::For(contents1());
+  tester1->NavigateAndCommit(GURL("http://baz.com"));
+
+  // Add the contents to the tracker.
+  EXPECT_CALL(observer(), OnStartTracking(contents1(), LoadingState::LOADING));
+  tracker().StartTracking(contents1());
+  EXPECT_TAB_AND_UI_TAB_COUNTS(1, 0, 1, 0);
+  testing::Mock::VerifyAndClearExpectations(&observer());
+
+  EXPECT_CALL(observer(), OnStartTracking(contents2(), LoadingState::UNLOADED));
+  tracker().StartTracking(contents2());
+  EXPECT_TAB_AND_UI_TAB_COUNTS(2, 1, 1, 0);
+  testing::Mock::VerifyAndClearExpectations(&observer());
+
+  // Start observers for the contents.
+  TestWebContentsObserver observer1(contents1(), &tracker());
+  TestWebContentsObserver observer2(contents2(), &tracker());
+
+  // Prerender some contents.
+  prerender::test_utils::RestorePrerenderMode restore_prerender_mode;
+  prerender::PrerenderManager::SetMode(
+      prerender::PrerenderManager::PRERENDER_MODE_ENABLED);
+  prerender::PrerenderManager* prerender_manager =
+      prerender::PrerenderManagerFactory::GetForBrowserContext(profile());
+  GURL url("http://www.example.com");
+  const gfx::Size kSize(640, 480);
+  std::unique_ptr<prerender::PrerenderHandle> prerender_handle(
+      prerender_manager->AddPrerenderFromOmnibox(
+          url, contents1()->GetController().GetDefaultSessionStorageNamespace(),
+          kSize));
+  const std::vector<content::WebContents*> contentses =
+      prerender_manager->GetAllPrerenderingContents();
+  ASSERT_EQ(1U, contentses.size());
+
+  // Prerendering should not change the UI tab counts, but should increase
+  // overall tab count. Note, contentses[0] is UNLOADED since it is not a test
+  // web contents and therefore hasn't started receiving data.
+  TestWebContentsObserver prerender_observer(contentses[0], &tracker());
+  EXPECT_CALL(observer(),
+              OnStartTracking(contentses[0], LoadingState::UNLOADED));
+  tracker().StartTracking(contentses[0]);
+  EXPECT_TAB_COUNTS(3, 2, 1, 0);
+  EXPECT_UI_TAB_COUNTS(2, 1, 1, 0);
+  testing::Mock::VerifyAndClearExpectations(&observer());
+
+  prerender_manager->CancelAllPrerenders();
+}
+
+TEST_F(TabLoadTrackerTest, SwapInUiTabContents) {
+  auto* tester1 = content::WebContentsTester::For(contents1());
+  tester1->NavigateAndCommit(GURL("http://baz.com"));
+
+  // Add the contents to the tracker.
+  EXPECT_CALL(observer(), OnStartTracking(contents1(), LoadingState::LOADING));
+  tracker().StartTracking(contents1());
+  EXPECT_TAB_AND_UI_TAB_COUNTS(1, 0, 1, 0);
+  testing::Mock::VerifyAndClearExpectations(&observer());
+
+  EXPECT_CALL(observer(), OnStartTracking(contents2(), LoadingState::UNLOADED));
+  tracker().StartTracking(contents2());
+  EXPECT_TAB_AND_UI_TAB_COUNTS(2, 1, 1, 0);
+  testing::Mock::VerifyAndClearExpectations(&observer());
+
+  // Start observers for the contents.
+  TestWebContentsObserver observer1(contents1(), &tracker());
+  TestWebContentsObserver observer2(contents2(), &tracker());
+
+  // Simulate non-ui tab contents running in the background and getting swapped
+  // in. Non-ui tabs should not change the ui tab counts, but should change the
+  // overall tab counts.
+  std::unique_ptr<content::WebContents> non_ui_tab_contents =
+      CreateTestWebContents();
+  EXPECT_CALL(observer(), OnStartTracking(non_ui_tab_contents.get(),
+                                          LoadingState::UNLOADED));
+  tracker().SetAllTabsAreNonUiTabs(true);
+  tracker().StartTracking(non_ui_tab_contents.get());
+  EXPECT_TAB_COUNTS(3, 2, 1, 0);
+  EXPECT_UI_TAB_COUNTS(2, 1, 1, 0);
+  testing::Mock::VerifyAndClearExpectations(&observer());
+  // Swap in the prerender contents and simulate resulting tab strip swap.
+  // |non_ui_tab_contents| is already being tracked. The UI tab count should
+  // remain stable through the swap.
+  EXPECT_CALL(observer(), OnStopTracking(contents1(), LoadingState::LOADING));
+  tracker().SetAllTabsAreNonUiTabs(false);
+  tracker().SwapTabContents(contents1(), non_ui_tab_contents.get());
+  // After swap, but before we stop tracking the swapped-out contents. The UI
+  // tab counts should be in the end-state, but the total tab counts will be in
+  // the pre-swap state while the swapped-out contents is still being tracked.
+  EXPECT_TAB_COUNTS(3, 2, 1, 0);
+  EXPECT_UI_TAB_COUNTS(2, 2, 0, 0);
+  tracker().StopTracking(contents1());
+  EXPECT_TAB_AND_UI_TAB_COUNTS(2, 2, 0, 0);
+  testing::Mock::VerifyAndClearExpectations(&observer());
+}
+
+TEST_F(TabLoadTrackerTest, SwapInUntrackedContents) {
+  auto* tester1 = content::WebContentsTester::For(contents1());
+  tester1->NavigateAndCommit(GURL("http://baz.com"));
+
+  // Add the contents to the tracker.
+  EXPECT_CALL(observer(), OnStartTracking(contents1(), LoadingState::LOADING));
+  tracker().StartTracking(contents1());
+  EXPECT_TAB_AND_UI_TAB_COUNTS(1, 0, 1, 0);
+  testing::Mock::VerifyAndClearExpectations(&observer());
+
+  EXPECT_CALL(observer(), OnStartTracking(contents2(), LoadingState::UNLOADED));
+  tracker().StartTracking(contents2());
+  EXPECT_TAB_AND_UI_TAB_COUNTS(2, 1, 1, 0);
+  testing::Mock::VerifyAndClearExpectations(&observer());
+
+  // Create an untracked web contents in the UNLOADED state, and swap it with
+  // the contents in the LOADING state. Since |untracked_contents| has no tab
+  // helper attached, swapping it in shouldn't changed the tab count.
+  std::unique_ptr<content::WebContents> untracked_contents =
+      CreateTestWebContents();
+  tracker().SwapTabContents(contents1(), untracked_contents.get());
+  // The total counts will remain stable since swapping out doesn't cause any
+  // web contents to stop being tracking. However, the swapped-out contents are
+  // no longer included in UI tab counts, and the swapped-in contents won't be
+  // until it is tracked.
+  EXPECT_TAB_COUNTS(2, 1, 1, 0);
+  EXPECT_UI_TAB_COUNTS(1, 1, 0, 0);
+
+  // Simulate swap in tab strip, which would cause |untracked_contents| to be
+  // tracked and the tab counts to change.
+  EXPECT_CALL(observer(), OnStopTracking(contents1(), LoadingState::LOADING));
+  EXPECT_CALL(observer(), OnStartTracking(untracked_contents.get(),
+                                          LoadingState::UNLOADED));
+  tracker().StopTracking(contents1());
+  tracker().StartTracking(untracked_contents.get());
+  EXPECT_TAB_AND_UI_TAB_COUNTS(2, 2, 0, 0);
 }
 
 }  // namespace resource_coordinator
diff --git a/chrome/browser/safe_browsing/incident_reporting/resource_request_detector.cc b/chrome/browser/safe_browsing/incident_reporting/resource_request_detector.cc
index a94040f47..ad1a19a7 100644
--- a/chrome/browser/safe_browsing/incident_reporting/resource_request_detector.cc
+++ b/chrome/browser/safe_browsing/incident_reporting/resource_request_detector.cc
@@ -61,22 +61,28 @@
   using ResourceRequestIncidentMessage =
       ClientIncidentReport::IncidentData::ResourceRequestIncident;
 
-  typedef base::Callback<void(std::unique_ptr<ResourceRequestIncidentMessage>)>
-      OnResultCallback;
+  using OnResultCallback =
+      base::OnceCallback<void(std::unique_ptr<ResourceRequestIncidentMessage>)>;
 
-  ResourceRequestDetectorClient(
+  static void Start(
       const GURL& resource_url,
       const scoped_refptr<SafeBrowsingDatabaseManager>& database_manager,
-      const OnResultCallback& callback)
-      : database_manager_(database_manager)
-      , callback_(callback) {
+      OnResultCallback callback) {
+    auto client = base::WrapRefCounted(new ResourceRequestDetectorClient(
+        std::move(database_manager), std::move(callback)));
     content::BrowserThread::PostTask(
         content::BrowserThread::IO, FROM_HERE,
-        base::BindOnce(&ResourceRequestDetectorClient::StartCheck, this,
+        base::BindOnce(&ResourceRequestDetectorClient::StartCheck, client,
                        resource_url));
   }
 
  private:
+  ResourceRequestDetectorClient(
+      scoped_refptr<SafeBrowsingDatabaseManager> database_manager,
+      OnResultCallback callback)
+      : database_manager_(std::move(database_manager)),
+        callback_(std::move(callback)) {}
+
   friend class base::RefCountedThreadSafe<ResourceRequestDetectorClient>;
   ~ResourceRequestDetectorClient() override {}
 
@@ -106,7 +112,7 @@
       incident_data->set_digest(threat_hash);
       content::BrowserThread::PostTask(
           content::BrowserThread::UI, FROM_HERE,
-          base::BindOnce(callback_, std::move(incident_data)));
+          base::BindOnce(std::move(callback_), std::move(incident_data)));
     }
     Release();  // Balanced in StartCheck.
   }
@@ -152,11 +158,11 @@
   if (request->resource_type == content::RESOURCE_TYPE_SUB_FRAME ||
       request->resource_type == content::RESOURCE_TYPE_SCRIPT ||
       request->resource_type == content::RESOURCE_TYPE_OBJECT) {
-    new ResourceRequestDetectorClient(
+    ResourceRequestDetectorClient::Start(
         request->url, database_manager_,
-        base::Bind(&ResourceRequestDetector::ReportIncidentOnUIThread,
-                   weak_ptr_factory_.GetWeakPtr(), request->render_process_id,
-                   request->render_frame_id));
+        base::BindOnce(&ResourceRequestDetector::ReportIncidentOnUIThread,
+                       weak_ptr_factory_.GetWeakPtr(),
+                       request->render_process_id, request->render_frame_id));
   }
 }
 
diff --git a/chrome/browser/safe_browsing/safe_browsing_blocking_page_test.cc b/chrome/browser/safe_browsing/safe_browsing_blocking_page_test.cc
index e185f97..7fc6ac4 100644
--- a/chrome/browser/safe_browsing/safe_browsing_blocking_page_test.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_blocking_page_test.cc
@@ -247,7 +247,7 @@
   TestThreatDetailsFactory() : details_() {}
   ~TestThreatDetailsFactory() override {}
 
-  ThreatDetails* CreateThreatDetails(
+  scoped_refptr<ThreatDetails> CreateThreatDetails(
       BaseUIManager* delegate,
       WebContents* web_contents,
       const security_interstitials::UnsafeResource& unsafe_resource,
@@ -256,11 +256,13 @@
       ReferrerChainProvider* referrer_chain_provider,
       bool trim_to_ad_tags,
       ThreatDetailsDoneCallback done_callback) override {
-    details_ = new ThreatDetails(delegate, web_contents, unsafe_resource,
-                                 url_loader_factory, history_service,
-                                 referrer_chain_provider, trim_to_ad_tags,
-                                 done_callback);
-    return details_;
+    auto details = base::WrapRefCounted(new ThreatDetails(
+        delegate, web_contents, unsafe_resource, url_loader_factory,
+        history_service, referrer_chain_provider, trim_to_ad_tags,
+        done_callback));
+    details_ = details.get();
+    details->StartCollection();
+    return details;
   }
 
   ThreatDetails* get_details() { return details_; }
diff --git a/chrome/browser/safe_browsing/safe_browsing_service_browsertest.cc b/chrome/browser/safe_browsing/safe_browsing_service_browsertest.cc
index 992b172..0dfae99 100644
--- a/chrome/browser/safe_browsing/safe_browsing_service_browsertest.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_service_browsertest.cc
@@ -1043,14 +1043,7 @@
   EXPECT_TRUE(hit_report().is_subresource);
 }
 
-// TODO(https://crbug.com/860445) - Reenable this once potential race condition
-// is addressed, which is triggered in certain conditions under MSAN, see bug.
-#if defined(MEMORY_SANITIZER)
-#define MAYBE_MalwareImg DISABLED_MalwareImg
-#else
-#define MAYBE_MalwareImg MalwareImg
-#endif
-IN_PROC_BROWSER_TEST_P(SafeBrowsingServiceMetadataTest, MAYBE_MalwareImg) {
+IN_PROC_BROWSER_TEST_P(SafeBrowsingServiceMetadataTest, MalwareImg) {
   GURL main_url = embedded_test_server()->GetURL(kMalwarePage);
   GURL img_url = embedded_test_server()->GetURL(kMalwareImg);
 
diff --git a/chrome/browser/safe_browsing/threat_details_unittest.cc b/chrome/browser/safe_browsing/threat_details_unittest.cc
index 9f6fa03..082a1f2 100644
--- a/chrome/browser/safe_browsing/threat_details_unittest.cc
+++ b/chrome/browser/safe_browsing/threat_details_unittest.cc
@@ -142,6 +142,8 @@
 
   size_t done_callback_count() { return done_callback_count_; }
 
+  void StartCollection() { ThreatDetails::StartCollection(); }
+
  private:
   ~ThreatDetailsWrap() override {}
 
@@ -174,7 +176,7 @@
 
 class MockReferrerChainProvider : public ReferrerChainProvider {
  public:
-  virtual ~MockReferrerChainProvider(){};
+  virtual ~MockReferrerChainProvider() {}
   MOCK_METHOD3(IdentifyReferrerChainByWebContents,
                AttributionResult(content::WebContents* web_contents,
                                  int user_gesture_count_limit,
@@ -402,6 +404,7 @@
   scoped_refptr<ThreatDetailsWrap> report =
       new ThreatDetailsWrap(ui_manager_.get(), web_contents(), resource, NULL,
                             history_service(), referrer_chain_provider_.get());
+  report->StartCollection();
 
   std::string serialized = WaitForThreatDetailsDone(
       report.get(), true /* did_proceed*/, 1 /* num_visit */);
@@ -457,6 +460,7 @@
   scoped_refptr<ThreatDetailsWrap> report =
       new ThreatDetailsWrap(ui_manager_.get(), web_contents(), resource, NULL,
                             history_service(), referrer_chain_provider_.get());
+  report->StartCollection();
 
   std::string serialized = WaitForThreatDetailsDone(
       report.get(), true /* did_proceed*/, 1 /* num_visit */);
@@ -507,6 +511,7 @@
   scoped_refptr<ThreatDetailsWrap> report =
       new ThreatDetailsWrap(ui_manager_.get(), web_contents(), resource, NULL,
                             history_service(), referrer_chain_provider_.get());
+  report->StartCollection();
 
   std::string serialized = WaitForThreatDetailsDone(
       report.get(), false /* did_proceed*/, 1 /* num_visit */);
@@ -555,6 +560,7 @@
   scoped_refptr<ThreatDetailsWrap> report =
       new ThreatDetailsWrap(ui_manager_.get(), web_contents(), resource, NULL,
                             history_service(), referrer_chain_provider_.get());
+  report->StartCollection();
 
   // Send a message from the DOM, with 2 nodes, a parent and a child.
   std::vector<mojom::ThreatDOMDetailsNodePtr> params;
@@ -777,6 +783,7 @@
     scoped_refptr<ThreatDetailsWrap> report = new ThreatDetailsWrap(
         ui_manager_.get(), web_contents(), resource, NULL, history_service(),
         referrer_chain_provider_.get());
+    report->StartCollection();
 
     std::vector<mojom::ThreatDOMDetailsNodePtr> outer_params_copy;
     for (auto& node : outer_params) {
@@ -833,6 +840,7 @@
     scoped_refptr<ThreatDetailsWrap> report = new ThreatDetailsWrap(
         ui_manager_.get(), web_contents(), resource, NULL, history_service(),
         referrer_chain_provider_.get());
+    report->StartCollection();
 
     // Send both sets of nodes from different render frames.
     report->OnReceivedThreatDOMDetails(nullptr, child_rfh,
@@ -959,6 +967,8 @@
   scoped_refptr<ThreatDetailsWrap> report =
       new ThreatDetailsWrap(ui_manager_.get(), web_contents(), resource, NULL,
                             history_service(), referrer_chain_provider_.get());
+  report->StartCollection();
+
   base::HistogramTester histograms;
 
   // Send both sets of nodes from different render frames.
@@ -1214,6 +1224,7 @@
       new ThreatDetailsWrap(ui_manager_.get(), web_contents(), resource, NULL,
                             history_service(), referrer_chain_provider_.get(),
                             /*trim_to_ad_tags=*/true);
+  trimmed_report->StartCollection();
 
   // Send both sets of nodes from different render frames.
   trimmed_report->OnReceivedThreatDOMDetails(nullptr, child_rfh,
@@ -1287,6 +1298,7 @@
       new ThreatDetailsWrap(ui_manager_.get(), web_contents(), resource, NULL,
                             history_service(), referrer_chain_provider_.get(),
                             /*trim_to_ad_tags=*/true);
+  trimmed_report->StartCollection();
 
   // Send both sets of nodes from different render frames.
   trimmed_report->OnReceivedThreatDOMDetails(nullptr, child_rfh,
@@ -1318,6 +1330,7 @@
   scoped_refptr<ThreatDetailsWrap> report =
       new ThreatDetailsWrap(ui_manager_.get(), web_contents(), resource, NULL,
                             history_service(), referrer_chain_provider_.get());
+  report->StartCollection();
 
   std::string serialized = WaitForThreatDetailsDone(
       report.get(), true /* did_proceed*/, 0 /* num_visit */);
@@ -1390,6 +1403,7 @@
   scoped_refptr<ThreatDetailsWrap> report =
       new ThreatDetailsWrap(ui_manager_.get(), web_contents(), resource, NULL,
                             history_service(), referrer_chain_provider_.get());
+  report->StartCollection();
 
   // Simulate clicking don't proceed.
   controller().DiscardNonCommittedEntries();
@@ -1450,6 +1464,8 @@
   scoped_refptr<ThreatDetailsWrap> report =
       new ThreatDetailsWrap(ui_manager_.get(), web_contents(), resource, NULL,
                             history_service(), referrer_chain_provider_.get());
+  report->StartCollection();
+
   std::string serialized = WaitForThreatDetailsDone(
       report.get(), true /* did_proceed*/, 1 /* num_visit */);
 
@@ -1498,6 +1514,8 @@
   scoped_refptr<ThreatDetailsWrap> report =
       new ThreatDetailsWrap(ui_manager_.get(), web_contents(), resource, NULL,
                             history_service(), referrer_chain_provider_.get());
+  report->StartCollection();
+
   std::string serialized = WaitForThreatDetailsDone(
       report.get(), true /* did_proceed*/, 1 /* num_visit */);
 
@@ -1531,6 +1549,7 @@
   scoped_refptr<ThreatDetailsWrap> report = new ThreatDetailsWrap(
       ui_manager_.get(), web_contents(), resource, test_shared_loader_factory_,
       history_service(), referrer_chain_provider_.get());
+  report->StartCollection();
 
   SimulateFillCache(kThreatURL);
 
@@ -1609,6 +1628,7 @@
   scoped_refptr<ThreatDetailsWrap> report = new ThreatDetailsWrap(
       ui_manager_.get(), web_contents(), resource, test_shared_loader_factory_,
       history_service(), referrer_chain_provider_.get());
+  report->StartCollection();
 
   SimulateFillCache(kThreatURLHttps);
 
@@ -1684,6 +1704,7 @@
   scoped_refptr<ThreatDetailsWrap> report = new ThreatDetailsWrap(
       ui_manager_.get(), web_contents(), resource, test_shared_loader_factory_,
       history_service(), referrer_chain_provider_.get());
+  report->StartCollection();
 
   // Simulate no cache entry found.
   test_url_loader_factory_.AddResponse(
@@ -1749,6 +1770,7 @@
   scoped_refptr<ThreatDetailsWrap> report =
       new ThreatDetailsWrap(ui_manager_.get(), web_contents(), resource, NULL,
                             history_service(), referrer_chain_provider_.get());
+  report->StartCollection();
 
   // The redirects collection starts after the IPC from the DOM is fired.
   std::vector<mojom::ThreatDOMDetailsNodePtr> params;
diff --git a/chrome/browser/signin/dice_browsertest.cc b/chrome/browser/signin/dice_browsertest.cc
index 47de1aa..028555e 100644
--- a/chrome/browser/signin/dice_browsertest.cc
+++ b/chrome/browser/signin/dice_browsertest.cc
@@ -694,9 +694,9 @@
   SendRefreshTokenResponse();
   EXPECT_EQ(GetMainAccountID(),
             GetSigninManager()->GetAuthenticatedAccountId());
-  // Old token must be revoked silently.
+
+  // Old token must not be revoked (see http://crbug.com/865189).
   EXPECT_EQ(0, token_revoked_notification_count_);
-  WaitForTokenRevokedCount(1);
 
   EXPECT_EQ(1, reconcilor_blocked_count_);
   WaitForReconcilorUnblockedCount(1);
@@ -896,9 +896,10 @@
   SendRefreshTokenResponse();
   EXPECT_EQ(GetMainAccountID(),
             GetSigninManager()->GetAuthenticatedAccountId());
-  // Old token must be revoked silently.
+
+  // Old token must not be revoked (see http://crbug.com/865189).
   EXPECT_EQ(0, token_revoked_notification_count_);
-  WaitForTokenRevokedCount(1);
+
   EXPECT_EQ(1, reconcilor_blocked_count_);
   WaitForReconcilorUnblockedCount(1);
 }
diff --git a/chrome/browser/signin/mutable_profile_oauth2_token_service_delegate.cc b/chrome/browser/signin/mutable_profile_oauth2_token_service_delegate.cc
index 9751c77..adb742f 100644
--- a/chrome/browser/signin/mutable_profile_oauth2_token_service_delegate.cc
+++ b/chrome/browser/signin/mutable_profile_oauth2_token_service_delegate.cc
@@ -761,8 +761,9 @@
   DCHECK(!account_id.empty());
   DCHECK(!refresh_token.empty());
 
+  bool is_refresh_token_invalidated = refresh_token == kInvalidRefreshToken;
   GoogleServiceAuthError error =
-      (refresh_token == kInvalidRefreshToken)
+      is_refresh_token_invalidated
           ? GoogleServiceAuthError::FromInvalidGaiaCredentialsReason(
                 GoogleServiceAuthError::InvalidGaiaCredentialsReason::
                     CREDENTIALS_REJECTED_BY_CLIENT)
@@ -775,7 +776,21 @@
     DCHECK_NE(refresh_token, refresh_tokens_[account_id]->refresh_token());
     VLOG(1) << "MutablePO2TS::UpdateCredentials; Refresh Token was present. "
             << "account_id=" << account_id;
-    RevokeCredentialsOnServer(refresh_tokens_[account_id]->refresh_token());
+
+    // The old refresh token must be revoked on the server only when it is
+    // invalidated.
+    //
+    // The refresh token is updated to a new valid one in case of reauth.
+    // In the reauth case the old and the new refresh tokens have the same
+    // device ID. When revoking a refresh token on the server, Gaia revokes
+    // all the refresh tokens that have the same device ID.
+    // Therefore, the old refresh token must not be revoked on the server
+    // when it is updated to a new valid one (otherwise the new refresh token
+    // would also be invalidated server-side).
+    // See http://crbug.com/865189 for more information about this regression.
+    if (is_refresh_token_invalidated)
+      RevokeCredentialsOnServer(refresh_tokens_[account_id]->refresh_token());
+
     refresh_tokens_[account_id]->set_refresh_token(refresh_token);
     UpdateAuthError(account_id, error);
   } else {
diff --git a/chrome/browser/signin/mutable_profile_oauth2_token_service_delegate_unittest.cc b/chrome/browser/signin/mutable_profile_oauth2_token_service_delegate_unittest.cc
index d5776b5..c87d0e33 100644
--- a/chrome/browser/signin/mutable_profile_oauth2_token_service_delegate_unittest.cc
+++ b/chrome/browser/signin/mutable_profile_oauth2_token_service_delegate_unittest.cc
@@ -760,9 +760,10 @@
   EXPECT_TRUE(oauth2_service_delegate_->server_revokes_.empty());
   ExpectOneTokenAvailableNotification();
 
-  // Update the token.
+  // Updating the token does not revoke the old one.
+  // Regression test for http://crbug.com/865189
   oauth2_service_delegate_->UpdateCredentials("account_id", "refresh_token2");
-  EXPECT_EQ(1u, oauth2_service_delegate_->server_revokes_.size());
+  EXPECT_TRUE(oauth2_service_delegate_->server_revokes_.empty());
   ExpectOneTokenAvailableNotification();
 
   // Flush the server revokes.
diff --git a/chrome/browser/sync/chrome_sync_client.cc b/chrome/browser/sync/chrome_sync_client.cc
index 60b26cfa..e53ea55 100644
--- a/chrome/browser/sync/chrome_sync_client.cc
+++ b/chrome/browser/sync/chrome_sync_client.cc
@@ -47,6 +47,7 @@
 #include "components/autofill/core/browser/webdata/autocomplete_sync_bridge.h"
 #include "components/autofill/core/browser/webdata/autofill_profile_sync_bridge.h"
 #include "components/autofill/core/browser/webdata/autofill_profile_syncable_service.h"
+#include "components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge.h"
 #include "components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service.h"
 #include "components/autofill/core/browser/webdata/autofill_wallet_sync_bridge.h"
 #include "components/autofill/core/browser/webdata/autofill_wallet_syncable_service.h"
@@ -609,6 +610,17 @@
           ->change_processor()
           ->GetControllerDelegateOnUIThread();
     }
+    case syncer::AUTOFILL_WALLET_METADATA: {
+      // TODO(feuunk): This doesn't allow switching which database to use at
+      // runtime. This should be fixed as part of the USS migration for
+      // payments.
+      auto service = account_web_data_service_ ? account_web_data_service_
+                                               : profile_web_data_service_;
+      return autofill::AutofillWalletMetadataSyncBridge::FromWebDataService(
+                 service.get())
+          ->change_processor()
+          ->GetControllerDelegateOnUIThread();
+    }
 #if defined(OS_CHROMEOS)
     case syncer::PRINTERS:
       return chromeos::SyncedPrintersManagerFactory::GetForBrowserContext(
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 111041b4..03555a2 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -1889,8 +1889,6 @@
       "ash/network/network_portal_notification_controller.h",
       "ash/network/network_state_notifier.cc",
       "ash/network/network_state_notifier.h",
-      "ash/network/networking_config_delegate_chromeos.cc",
-      "ash/network/networking_config_delegate_chromeos.h",
       "ash/network/tether_notification_presenter.cc",
       "ash/network/tether_notification_presenter.h",
       "ash/session_controller_client.cc",
@@ -3486,9 +3484,7 @@
     }
 
     if (!is_chromeos) {
-      sources += [
-        "views/screen_capture_notification_ui_views.cc",
-      ]
+      sources += [ "views/screen_capture_notification_ui_views.cc" ]
     }
 
     if (is_mac) {
diff --git a/chrome/browser/ui/ash/chrome_shell_delegate.cc b/chrome/browser/ui/ash/chrome_shell_delegate.cc
index 32a7b88..151c564 100644
--- a/chrome/browser/ui/ash/chrome_shell_delegate.cc
+++ b/chrome/browser/ui/ash/chrome_shell_delegate.cc
@@ -22,7 +22,6 @@
 #include "chrome/browser/ui/ash/chrome_keyboard_ui.h"
 #include "chrome/browser/ui/ash/chrome_screenshot_grabber.h"
 #include "chrome/browser/ui/ash/multi_user/multi_user_util.h"
-#include "chrome/browser/ui/ash/network/networking_config_delegate_chromeos.h"
 #include "chrome/browser/ui/ash/session_controller_client.h"
 #include "chrome/browser/ui/ash/session_util.h"
 #include "chrome/browser/ui/browser.h"
@@ -86,12 +85,9 @@
 
 }  // namespace
 
-ChromeShellDelegate::ChromeShellDelegate()
-    : networking_config_delegate_(
-          std::make_unique<chromeos::NetworkingConfigDelegateChromeos>()) {
-}
+ChromeShellDelegate::ChromeShellDelegate() = default;
 
-ChromeShellDelegate::~ChromeShellDelegate() {}
+ChromeShellDelegate::~ChromeShellDelegate() = default;
 
 service_manager::Connector* ChromeShellDelegate::GetShellConnector() const {
   return content::ServiceManagerConnection::GetForProcess()->GetConnector();
@@ -140,11 +136,6 @@
   return new AccessibilityDelegateImpl;
 }
 
-ash::NetworkingConfigDelegate*
-ChromeShellDelegate::GetNetworkingConfigDelegate() {
-  return networking_config_delegate_.get();
-}
-
 std::unique_ptr<ash::ScreenshotDelegate>
 ChromeShellDelegate::CreateScreenshotDelegate() {
   return std::make_unique<ChromeScreenshotGrabber>();
diff --git a/chrome/browser/ui/ash/chrome_shell_delegate.h b/chrome/browser/ui/ash/chrome_shell_delegate.h
index 923d610..51e7944 100644
--- a/chrome/browser/ui/ash/chrome_shell_delegate.h
+++ b/chrome/browser/ui/ash/chrome_shell_delegate.h
@@ -26,15 +26,12 @@
   bool CanShowWindowForUser(aura::Window* window) const override;
   void PreInit() override;
   std::unique_ptr<keyboard::KeyboardUI> CreateKeyboardUI() override;
-  ash::NetworkingConfigDelegate* GetNetworkingConfigDelegate() override;
   std::unique_ptr<ash::ScreenshotDelegate> CreateScreenshotDelegate() override;
   ash::AccessibilityDelegate* CreateAccessibilityDelegate() override;
   void OpenKeyboardShortcutHelpPage() const override;
   ui::InputDeviceControllerClient* GetInputDeviceControllerClient() override;
 
  private:
-  std::unique_ptr<ash::NetworkingConfigDelegate> networking_config_delegate_;
-
   DISALLOW_COPY_AND_ASSIGN(ChromeShellDelegate);
 };
 
diff --git a/chrome/browser/ui/ash/network/DEPS b/chrome/browser/ui/ash/network/DEPS
index 96b7bd5..1601c9d 100644
--- a/chrome/browser/ui/ash/network/DEPS
+++ b/chrome/browser/ui/ash/network/DEPS
@@ -1,10 +1,3 @@
 include_rules = [
   "+components/captive_portal",
 ]
-
-specific_include_rules = {
-  # TODO(mash): Fix. https://crbug.com/651157
-  "networking_config_delegate_chromeos\.h": [
-    "+ash/system/networking_config_delegate.h",
-  ],
-}
diff --git a/chrome/browser/ui/ash/network/network_state_notifier.cc b/chrome/browser/ui/ash/network/network_state_notifier.cc
index c23fb7d..f4f0fee 100644
--- a/chrome/browser/ui/ash/network/network_state_notifier.cc
+++ b/chrome/browser/ui/ash/network/network_state_notifier.cc
@@ -227,7 +227,7 @@
 void NetworkStateNotifier::UpdateVpnConnectionState(const NetworkState* vpn) {
   if (vpn->path() == connected_vpn_) {
     if (!vpn->IsConnectedState() && !vpn->IsConnectingState()) {
-      if (vpn->vpn_provider_type() != shill::kProviderArcVpn) {
+      if (vpn->GetVpnProviderType() != shill::kProviderArcVpn) {
         ShowVpnDisconnectedNotification(vpn);
       }
       connected_vpn_.clear();
diff --git a/chrome/browser/ui/ash/network/networking_config_delegate_chromeos_browsertest.cc b/chrome/browser/ui/ash/network/networking_config_chromeos_browsertest.cc
similarity index 82%
rename from chrome/browser/ui/ash/network/networking_config_delegate_chromeos_browsertest.cc
rename to chrome/browser/ui/ash/network/networking_config_chromeos_browsertest.cc
index 25d0007d..fdf888a 100644
--- a/chrome/browser/ui/ash/network/networking_config_delegate_chromeos_browsertest.cc
+++ b/chrome/browser/ui/ash/network/networking_config_chromeos_browsertest.cc
@@ -2,8 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/ui/ash/network/networking_config_delegate_chromeos.h"
-
 #include "ash/public/cpp/ash_view_ids.h"
 #include "ash/public/interfaces/constants.mojom.h"
 #include "ash/public/interfaces/system_tray_test_api.mojom.h"
@@ -20,16 +18,15 @@
 
 namespace {
 
-using NetworkingConfigDelegateChromeosTest = extensions::ExtensionBrowserTest;
+using NetworkingConfigChromeosTest = extensions::ExtensionBrowserTest;
 
 // Tests that an extension registering itself as handling a Wi-Fi SSID updates
 // the ash system tray network item.
-IN_PROC_BROWSER_TEST_F(NetworkingConfigDelegateChromeosTest, SystemTrayItem) {
+IN_PROC_BROWSER_TEST_F(NetworkingConfigChromeosTest, SystemTrayItem) {
   // Load the extension and wait for the background page script to run. This
   // registers the extension as the network config handler for wifi1.
   ExtensionTestMessageListener listener("done", false);
-  ASSERT_TRUE(
-      LoadExtension(test_data_dir_.AppendASCII("networking_config_delegate")));
+  ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("networking_config")));
   ASSERT_TRUE(listener.WaitUntilSatisfied());
 
   // Connect to ash.
@@ -45,7 +42,7 @@
   // Expect that the extension-controlled VPN item appears.
   base::string16 expected_tooltip = l10n_util::GetStringFUTF16(
       IDS_ASH_STATUS_TRAY_EXTENSION_CONTROLLED_WIFI,
-      base::UTF8ToUTF16("NetworkingConfigDelegate test extension"));
+      base::UTF8ToUTF16("NetworkingConfig test extension"));
   base::string16 tooltip;
   wait_for.GetBubbleViewTooltip(ash::VIEW_ID_EXTENSION_CONTROLLED_WIFI,
                                 &tooltip);
diff --git a/chrome/browser/ui/ash/network/networking_config_delegate_chromeos.cc b/chrome/browser/ui/ash/network/networking_config_delegate_chromeos.cc
deleted file mode 100644
index e28a135..0000000
--- a/chrome/browser/ui/ash/network/networking_config_delegate_chromeos.cc
+++ /dev/null
@@ -1,65 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/ui/ash/network/networking_config_delegate_chromeos.h"
-
-#include <memory>
-#include <string>
-
-#include "base/strings/string_number_conversions.h"
-#include "chrome/browser/profiles/profile_manager.h"
-#include "chromeos/network/network_state.h"
-#include "chromeos/network/network_state_handler.h"
-#include "extensions/browser/api/networking_config/networking_config_service.h"
-#include "extensions/browser/api/networking_config/networking_config_service_factory.h"
-#include "extensions/browser/extension_registry.h"
-#include "extensions/common/extension.h"
-
-namespace chromeos {
-
-NetworkingConfigDelegateChromeos::NetworkingConfigDelegateChromeos() {}
-
-NetworkingConfigDelegateChromeos::~NetworkingConfigDelegateChromeos() {}
-
-std::unique_ptr<const ash::NetworkingConfigDelegate::ExtensionInfo>
-NetworkingConfigDelegateChromeos::LookUpExtensionForNetwork(
-    const std::string& guid) {
-  chromeos::NetworkStateHandler* handler =
-      chromeos::NetworkHandler::Get()->network_state_handler();
-  const chromeos::NetworkState* network_state =
-      handler->GetNetworkStateFromGuid(guid);
-  if (!network_state)
-    return nullptr;
-  std::string hex_ssid = network_state->GetHexSsid();
-  Profile* profile = ProfileManager::GetActiveUserProfile();
-  extensions::NetworkingConfigService* networking_config_service =
-      extensions::NetworkingConfigServiceFactory::GetForBrowserContext(profile);
-  const std::string extension_id =
-      networking_config_service->LookupExtensionIdForHexSsid(hex_ssid);
-  if (extension_id.empty())
-    return nullptr;
-  std::string extension_name = LookUpExtensionName(profile, extension_id);
-  if (extension_name.empty())
-    return std::unique_ptr<
-        const ash::NetworkingConfigDelegate::ExtensionInfo>();
-  std::unique_ptr<const ash::NetworkingConfigDelegate::ExtensionInfo>
-  extension_info(new const ash::NetworkingConfigDelegate::ExtensionInfo(
-      extension_id, extension_name));
-  return extension_info;
-}
-
-std::string NetworkingConfigDelegateChromeos::LookUpExtensionName(
-    content::BrowserContext* context,
-    std::string extension_id) const {
-  extensions::ExtensionRegistry* extension_registry =
-      extensions::ExtensionRegistry::Get(context);
-  DCHECK(extension_registry);
-  const extensions::Extension* extension = extension_registry->GetExtensionById(
-      extension_id, extensions::ExtensionRegistry::ENABLED);
-  if (extension == nullptr)
-    return std::string();
-  return extension->name();
-}
-
-}  // namespace chromeos
diff --git a/chrome/browser/ui/ash/network/networking_config_delegate_chromeos.h b/chrome/browser/ui/ash/network/networking_config_delegate_chromeos.h
deleted file mode 100644
index 901c22e..0000000
--- a/chrome/browser/ui/ash/network/networking_config_delegate_chromeos.h
+++ /dev/null
@@ -1,36 +0,0 @@
-// Copyright (c) 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_UI_ASH_NETWORK_NETWORKING_CONFIG_DELEGATE_CHROMEOS_H_
-#define CHROME_BROWSER_UI_ASH_NETWORK_NETWORKING_CONFIG_DELEGATE_CHROMEOS_H_
-
-#include <string>
-
-#include "ash/system/networking_config_delegate.h"
-#include "base/compiler_specific.h"
-#include "base/macros.h"
-#include "content/public/browser/browser_context.h"
-
-namespace chromeos {
-
-// A class which allows the ash tray to retrieve extension provided networking
-// configuration through the networking config service.
-class NetworkingConfigDelegateChromeos : public ash::NetworkingConfigDelegate {
- public:
-  NetworkingConfigDelegateChromeos();
-  ~NetworkingConfigDelegateChromeos() override;
-
-  std::unique_ptr<const ExtensionInfo> LookUpExtensionForNetwork(
-      const std::string& guid) override;
-
- private:
-  std::string LookUpExtensionName(content::BrowserContext* context,
-                                  std::string extension_id) const;
-
-  DISALLOW_COPY_AND_ASSIGN(NetworkingConfigDelegateChromeos);
-};
-
-}  // namespace chromeos
-
-#endif  // CHROME_BROWSER_UI_ASH_NETWORK_NETWORKING_CONFIG_DELEGATE_CHROMEOS_H_
diff --git a/chrome/browser/ui/ash/system_tray_client.cc b/chrome/browser/ui/ash/system_tray_client.cc
index 6319937..3d421da 100644
--- a/chrome/browser/ui/ash/system_tray_client.cc
+++ b/chrome/browser/ui/ash/system_tray_client.cc
@@ -106,7 +106,7 @@
 bool IsArcVpn(const std::string& network_id) {
   const chromeos::NetworkState* network_state = GetNetworkState(network_id);
   return network_state && network_state->type() == shill::kTypeVPN &&
-         network_state->vpn_provider_type() == shill::kProviderArcVpn;
+         network_state->GetVpnProviderType() == shill::kProviderArcVpn;
 }
 
 }  // namespace
diff --git a/chrome/browser/ui/autofill/autofill_popup_controller_impl_mac.mm b/chrome/browser/ui/autofill/autofill_popup_controller_impl_mac.mm
index 3fb15c9..933db087 100644
--- a/chrome/browser/ui/autofill/autofill_popup_controller_impl_mac.mm
+++ b/chrome/browser/ui/autofill/autofill_popup_controller_impl_mac.mm
@@ -5,8 +5,6 @@
 #include "chrome/browser/ui/autofill/autofill_popup_controller_impl_mac.h"
 
 #include "base/mac/availability.h"
-#import "chrome/browser/ui/cocoa/browser_window_controller.h"
-#import "chrome/browser/ui/cocoa/tab_contents/tab_contents_controller.h"
 #import "chrome/browser/ui/cocoa/touchbar/web_textfield_touch_bar_controller.h"
 #include "components/autofill/core/browser/autofill_popup_delegate.h"
 #include "components/autofill/core/browser/popup_item_ids.h"
@@ -64,13 +62,8 @@
     return;
 
   if (@available(macOS 10.12.2, *)) {
-    BrowserWindowController* bwc = [BrowserWindowController
-        browserWindowControllerForWindow:[container_view() window]];
-    TabContentsController* tabContentsController =
-        [[bwc tabStripController] activeTabContentsController];
-    touch_bar_controller_ =
-        [tabContentsController webTextfieldTouchBarController];
-
+    touch_bar_controller_ = [WebTextfieldTouchBarController
+        controllerForWindow:[container_view() window]];
     [touch_bar_controller_ showCreditCardAutofillWithController:this];
   }
 }
@@ -79,9 +72,8 @@
     const std::vector<base::string16>& values,
     const std::vector<base::string16>& labels) {
   AutofillPopupControllerImpl::UpdateDataListValues(values, labels);
-  if (touch_bar_controller_) {
+  if (touch_bar_controller_)
     [touch_bar_controller_ invalidateTouchBar];
-  }
 }
 
 void AutofillPopupControllerImplMac::Hide() {
diff --git a/chrome/browser/ui/browser.cc b/chrome/browser/ui/browser.cc
index 62e32d6..28824ed 100644
--- a/chrome/browser/ui/browser.cc
+++ b/chrome/browser/ui/browser.cc
@@ -78,6 +78,7 @@
 #include "chrome/browser/profiles/profile_metrics.h"
 #include "chrome/browser/profiles/profiles_state.h"
 #include "chrome/browser/repost_form_warning_controller.h"
+#include "chrome/browser/resource_coordinator/tab_load_tracker.h"
 #include "chrome/browser/resource_coordinator/tab_manager_web_contents_data.h"
 #include "chrome/browser/search/search.h"
 #include "chrome/browser/sessions/session_restore.h"
@@ -2003,6 +2004,11 @@
       new_view->TakeFallbackContentFrom(old_view);
   }
 
+  // TODO(crbug.com/836409): TabLoadTracker should not rely on being notified
+  // directly about tab contents swaps.
+  resource_coordinator::TabLoadTracker::Get()->SwapTabContents(
+      old_contents, new_contents.get());
+
   int index = tab_strip_model_->GetIndexOfWebContents(old_contents);
   DCHECK_NE(TabStripModel::kNoTab, index);
   return tab_strip_model_->ReplaceWebContentsAt(index, std::move(new_contents));
diff --git a/chrome/browser/ui/cocoa/tab_contents/tab_contents_controller.h b/chrome/browser/ui/cocoa/tab_contents/tab_contents_controller.h
index 7fe6d64..63a17bb 100644
--- a/chrome/browser/ui/cocoa/tab_contents/tab_contents_controller.h
+++ b/chrome/browser/ui/cocoa/tab_contents/tab_contents_controller.h
@@ -12,7 +12,6 @@
 #include "base/mac/scoped_nsobject.h"
 
 class FullscreenObserver;
-@class WebTextfieldTouchBarController;
 
 namespace content {
 class WebContents;
@@ -53,8 +52,6 @@
    // Reference to the fullscreen window created to display the WebContents
    // view separately.
    NSWindow* separateFullscreenWindow_;
-
-   base::scoped_nsobject<WebTextfieldTouchBarController> touchBarController_;
 }
 @property(readonly, nonatomic) content::WebContents* webContents;
 
@@ -100,8 +97,6 @@
 // widget or back to WebContentsView's widget.
 - (void)toggleFullscreenWidget:(BOOL)enterFullscreen;
 
-- (WebTextfieldTouchBarController*)webTextfieldTouchBarController;
-
 @end
 
 #endif  // CHROME_BROWSER_UI_COCOA_TAB_CONTENTS_TAB_CONTENTS_CONTROLLER_H_
diff --git a/chrome/browser/ui/cocoa/tab_contents/tab_contents_controller.mm b/chrome/browser/ui/cocoa/tab_contents/tab_contents_controller.mm
index 2067c7a..3929fd4 100644
--- a/chrome/browser/ui/cocoa/tab_contents/tab_contents_controller.mm
+++ b/chrome/browser/ui/cocoa/tab_contents/tab_contents_controller.mm
@@ -18,7 +18,6 @@
 #include "chrome/browser/ui/cocoa/fullscreen_placeholder_view.h"
 #include "chrome/browser/ui/cocoa/separate_fullscreen_window.h"
 #import "chrome/browser/ui/cocoa/themed_window.h"
-#import "chrome/browser/ui/cocoa/touchbar/web_textfield_touch_bar_controller.h"
 #include "chrome/browser/ui/exclusive_access/fullscreen_within_tab_helper.h"
 #include "chrome/browser/ui/view_ids.h"
 #include "chrome/common/chrome_features.h"
@@ -220,8 +219,6 @@
     fullscreenObserver_.reset(new FullscreenObserver(self));
     [self changeWebContents:contents];
     isPopup_ = popup;
-    touchBarController_.reset([[WebTextfieldTouchBarController alloc]
-        initWithTabContentsController:self]);
   }
   return self;
 }
@@ -241,10 +238,6 @@
   [self setView:view];
 }
 
-- (NSTouchBar*)makeTouchBar API_AVAILABLE(macos(10.12.2)) {
-  return [touchBarController_ makeTouchBar];
-}
-
 - (void)ensureContentsVisibleInSuperview:(NSView*)superview {
   if (!contents_)
     return;
@@ -424,10 +417,6 @@
   return isPopup_;
 }
 
-- (WebTextfieldTouchBarController*)webTextfieldTouchBarController {
-  return touchBarController_.get();
-}
-
 @end
 
 @implementation TabContentsController (SeparateFullscreenWindowDelegate)
diff --git a/chrome/browser/ui/cocoa/tabs/tab_strip_controller.h b/chrome/browser/ui/cocoa/tabs/tab_strip_controller.h
index a51d2a8d..dc19594c0 100644
--- a/chrome/browser/ui/cocoa/tabs/tab_strip_controller.h
+++ b/chrome/browser/ui/cocoa/tabs/tab_strip_controller.h
@@ -21,6 +21,7 @@
 @class CustomWindowControlsView;
 @class NewTabButtonCocoa;
 @class TabContentsController;
+@class TabControllerCocoa;
 @class TabViewCocoa;
 @class TabStripDragController;
 @class TabStripView;
diff --git a/chrome/browser/ui/cocoa/touchbar/browser_window_default_touch_bar.mm b/chrome/browser/ui/cocoa/touchbar/browser_window_default_touch_bar.mm
index 19e8228..fea91ee 100644
--- a/chrome/browser/ui/cocoa/touchbar/browser_window_default_touch_bar.mm
+++ b/chrome/browser/ui/cocoa/touchbar/browser_window_default_touch_bar.mm
@@ -23,8 +23,6 @@
 #import "chrome/browser/ui/cocoa/touchbar/browser_window_touch_bar_controller.h"
 #include "chrome/browser/ui/exclusive_access/exclusive_access_manager.h"
 #include "chrome/browser/ui/exclusive_access/fullscreen_controller.h"
-#include "chrome/browser/ui/tabs/tab_strip_model.h"
-#include "chrome/browser/ui/tabs/tab_strip_model_observer.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/grit/generated_resources.h"
 #include "components/omnibox/browser/vector_icons.h"
@@ -132,7 +130,6 @@
 // the profile preferences and the back/forward commands.
 class TouchBarNotificationBridge : public CommandObserver,
                                    public BookmarkTabHelperObserver,
-                                   public TabStripModelObserver,
                                    public content::WebContentsObserver {
  public:
   TouchBarNotificationBridge(BrowserWindowDefaultTouchBar* owner,
@@ -140,7 +137,6 @@
       : owner_(owner), browser_(browser), contents_(nullptr) {
     TabStripModel* model = browser_->tab_strip_model();
     DCHECK(model);
-    model->AddObserver(this);
 
     UpdateWebContents(model->GetActiveWebContents());
   }
@@ -148,10 +144,6 @@
   ~TouchBarNotificationBridge() override {
     if (contents_)
       BookmarkTabHelper::FromWebContents(contents_)->RemoveObserver(this);
-
-    TabStripModel* model = browser_->tab_strip_model();
-    if (model)
-      model->RemoveObserver(this);
   }
 
   void UpdateTouchBar() { [[owner_ controller] invalidateTouchBar]; }
@@ -182,16 +174,6 @@
     [owner_ setIsStarred:starred];
   }
 
-  // TabStripModelObserver:
-  void ActiveTabChanged(content::WebContents* old_contents,
-                        content::WebContents* new_contents,
-                        int index,
-                        int reason) override {
-    UpdateWebContents(new_contents);
-    contents_ = new_contents;
-    UpdateTouchBar();
-  }
-
  protected:
   // CommandObserver:
   void EnabledStateChangedForCommand(int command, bool enabled) override {
@@ -215,11 +197,6 @@
     [owner_ setIsPageLoading:NO];
   }
 
-  void WebContentsDestroyed() override {
-    // Clean up if the web contents is being destroyed.
-    UpdateWebContents(nullptr);
-  }
-
  private:
   BrowserWindowDefaultTouchBar* owner_;  // Weak.
   Browser* browser_;                     // Weak.
@@ -269,6 +246,7 @@
 
 // Creates and returns the search button.
 - (NSView*)searchTouchBarView API_AVAILABLE(macos(10.12));
+
 @end
 
 @implementation BrowserWindowDefaultTouchBar
diff --git a/chrome/browser/ui/cocoa/touchbar/browser_window_touch_bar_controller.h b/chrome/browser/ui/cocoa/touchbar/browser_window_touch_bar_controller.h
index 9d000d47..6f0e576 100644
--- a/chrome/browser/ui/cocoa/touchbar/browser_window_touch_bar_controller.h
+++ b/chrome/browser/ui/cocoa/touchbar/browser_window_touch_bar_controller.h
@@ -12,6 +12,11 @@
 
 class Browser;
 @class BrowserWindowDefaultTouchBar;
+@class WebTextfieldTouchBarController;
+
+namespace content {
+class WebContents;
+}
 
 // Provides a touch bar for the browser window. This class implements the
 // NSTouchBarDelegate and handles the items in the touch bar.
@@ -26,12 +31,16 @@
 // nil.
 - (void)invalidateTouchBar;
 
+- (void)updateWebContents:(content::WebContents*)contents;
+
+- (content::WebContents*)webContents;
 @end
 
 @interface BrowserWindowTouchBarController (ExposedForTesting)
 
 - (BrowserWindowDefaultTouchBar*)defaultTouchBar;
 
+- (WebTextfieldTouchBarController*)webTextfieldTouchBar;
 @end
 
 #endif  // CHROME_BROWSER_UI_COCOA_TOUCHBAR_BROWSER_WINDOW_TOUCH_BAR_CONTROLLER_H_
diff --git a/chrome/browser/ui/cocoa/touchbar/browser_window_touch_bar_controller.mm b/chrome/browser/ui/cocoa/touchbar/browser_window_touch_bar_controller.mm
index f31ffbe..43bc4d9e 100644
--- a/chrome/browser/ui/cocoa/touchbar/browser_window_touch_bar_controller.mm
+++ b/chrome/browser/ui/cocoa/touchbar/browser_window_touch_bar_controller.mm
@@ -12,17 +12,72 @@
 #import "base/mac/sdk_forward_declarations.h"
 #include "chrome/browser/ui/browser.h"
 #import "chrome/browser/ui/cocoa/touchbar/browser_window_default_touch_bar.h"
+#import "chrome/browser/ui/cocoa/touchbar/web_textfield_touch_bar_controller.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/browser/ui/tabs/tab_strip_model_observer.h"
 #include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_contents_observer.h"
 #import "ui/base/cocoa/touch_bar_util.h"
 
-@interface BrowserWindowTouchBarController () {
-  // The browser associated with the touch bar.
-  Browser* browser_;  // Weak.
+class WebContentsNotificationBridge : public TabStripModelObserver,
+                                      public content::WebContentsObserver {
+ public:
+  WebContentsNotificationBridge(BrowserWindowTouchBarController* owner,
+                                Browser* browser)
+      : owner_(owner), browser_(browser), contents_(nullptr) {
+    TabStripModel* model = browser_->tab_strip_model();
+    DCHECK(model);
+    model->AddObserver(this);
 
+    UpdateWebContents(model->GetActiveWebContents());
+  }
+
+  ~WebContentsNotificationBridge() override {
+    TabStripModel* model = browser_->tab_strip_model();
+    if (model)
+      model->RemoveObserver(this);
+  }
+
+  void UpdateWebContents(content::WebContents* new_contents) {
+    contents_ = new_contents;
+    Observe(contents_);
+
+    [owner_ updateWebContents:contents_];
+  }
+
+  // TabStripModelObserver:
+  void ActiveTabChanged(content::WebContents* old_contents,
+                        content::WebContents* new_contents,
+                        int index,
+                        int reason) override {
+    UpdateWebContents(new_contents);
+    contents_ = new_contents;
+  }
+
+  content::WebContents* contents() const { return contents_; }
+
+ protected:
+  // WebContentsObserver:
+  void WebContentsDestroyed() override {
+    // Clean up if the web contents is being destroyed.
+    UpdateWebContents(nullptr);
+  }
+
+ private:
+  BrowserWindowTouchBarController* owner_;  // Weak.
+  Browser* browser_;                        // Weak.
+  content::WebContents* contents_;          // Weak.
+};
+
+@interface BrowserWindowTouchBarController () {
   NSWindow* window_;  // Weak.
 
+  // Used to receive and handle notifications.
+  std::unique_ptr<WebContentsNotificationBridge> notificationBridge_;
+
   base::scoped_nsobject<BrowserWindowDefaultTouchBar> defaultTouchBar_;
+
+  base::scoped_nsobject<WebTextfieldTouchBarController> webTextfieldTouchBar_;
 }
 @end
 
@@ -30,10 +85,17 @@
 
 - (instancetype)initWithBrowser:(Browser*)browser window:(NSWindow*)window {
   if ((self = [super init])) {
+    DCHECK(browser);
+    window_ = window;
+
+    notificationBridge_ =
+        std::make_unique<WebContentsNotificationBridge>(self, browser);
+
     defaultTouchBar_.reset([[BrowserWindowDefaultTouchBar alloc]
         initWithBrowser:browser
              controller:self]);
-    window_ = window;
+    webTextfieldTouchBar_.reset(
+        [[WebTextfieldTouchBarController alloc] initWithController:self]);
   }
 
   return self;
@@ -45,9 +107,23 @@
 }
 
 - (NSTouchBar*)makeTouchBar {
+  NSTouchBar* touchBar = [webTextfieldTouchBar_ makeTouchBar];
+  if (touchBar)
+    return touchBar;
+
   return [defaultTouchBar_ makeTouchBar];
 }
 
+- (void)updateWebContents:(content::WebContents*)contents {
+  [defaultTouchBar_ updateWebContents:contents];
+  [webTextfieldTouchBar_ updateWebContents:contents];
+  [self invalidateTouchBar];
+}
+
+- (content::WebContents*)webContents {
+  return notificationBridge_->web_contents();
+}
+
 @end
 
 @implementation BrowserWindowTouchBarController (ExposedForTesting)
@@ -56,4 +132,8 @@
   return defaultTouchBar_.get();
 }
 
+- (WebTextfieldTouchBarController*)webTextfieldTouchBar {
+  return webTextfieldTouchBar_.get();
+}
+
 @end
diff --git a/chrome/browser/ui/cocoa/touchbar/suggested_text_touch_bar_controller.h b/chrome/browser/ui/cocoa/touchbar/suggested_text_touch_bar_controller.h
index d916ebcd..7e4c5d3 100644
--- a/chrome/browser/ui/cocoa/touchbar/suggested_text_touch_bar_controller.h
+++ b/chrome/browser/ui/cocoa/touchbar/suggested_text_touch_bar_controller.h
@@ -25,8 +25,6 @@
 - (instancetype)initWithWebContents:(content::WebContents*)webContents
                          controller:(WebTextfieldTouchBarController*)controller;
 
-- (void)initObserver;
-
 - (NSTouchBar*)makeTouchBar API_AVAILABLE(macos(10.12.2));
 
 - (NSTouchBarItem*)touchBar:(NSTouchBar*)touchBar
diff --git a/chrome/browser/ui/cocoa/touchbar/suggested_text_touch_bar_controller.mm b/chrome/browser/ui/cocoa/touchbar/suggested_text_touch_bar_controller.mm
index 85cb010f..0cfeb53 100644
--- a/chrome/browser/ui/cocoa/touchbar/suggested_text_touch_bar_controller.mm
+++ b/chrome/browser/ui/cocoa/touchbar/suggested_text_touch_bar_controller.mm
@@ -26,6 +26,10 @@
                           SuggestedTextTouchBarController* owner)
       : WebContentsObserver(web_contents), owner_(owner) {}
 
+  void UpdateWebContents(content::WebContents* web_contents) {
+    Observe(web_contents);
+  }
+
   void DidChangeTextSelection(const base::string16& text,
                               const gfx::Range& range) override {
     if (@available(macOS 10.12.2, *)) {
@@ -82,18 +86,15 @@
   if ((self = [super init])) {
     webContents_ = webContents;
     controller_ = controller;
+    observer_.reset(
+        new text_observer::WebContentsTextObserver(webContents_, self));
   }
 
   return self;
 }
 
-- (void)initObserver {
-  observer_.reset(
-      new text_observer::WebContentsTextObserver(webContents_, self));
-}
-
 - (NSTouchBar*)makeTouchBar {
-  if (!webContents_->IsFocusedElementEditable())
+  if (!webContents_ || !webContents_->IsFocusedElementEditable())
     return nil;
 
   base::scoped_nsobject<NSTouchBar> touchBar([[ui::NSTouchBar() alloc] init]);
@@ -253,7 +254,9 @@
 }
 
 - (void)setWebContents:(content::WebContents*)webContents {
+  // TODO(tnijssen): Update the text suggestions when we change web contents.
   webContents_ = webContents;
+  observer_->UpdateWebContents(webContents);
 }
 
 - (content::WebContents*)webContents {
diff --git a/chrome/browser/ui/cocoa/touchbar/web_textfield_touch_bar_controller.h b/chrome/browser/ui/cocoa/touchbar/web_textfield_touch_bar_controller.h
index 5237569..dbca4d7e 100644
--- a/chrome/browser/ui/cocoa/touchbar/web_textfield_touch_bar_controller.h
+++ b/chrome/browser/ui/cocoa/touchbar/web_textfield_touch_bar_controller.h
@@ -12,6 +12,7 @@
 #import "base/mac/scoped_nsobject.h"
 #import "ui/base/cocoa/touch_bar_forward_declarations.h"
 
+@class BrowserWindowTouchBarController;
 @class CreditCardAutofillTouchBarController;
 @class SuggestedTextTouchBarController;
 @class TabContentsController;
@@ -20,24 +21,32 @@
 class AutofillPopupController;
 }
 
+namespace content {
+class WebContents;
+}
+
 // Provides a touch bar for the textfields in the WebContents. This class
 // implements the NSTouchBarDelegate and handles the items in the touch bar.
 @interface WebTextfieldTouchBarController : NSObject<NSTouchBarDelegate> {
-  TabContentsController* owner_;  // weak.
+  BrowserWindowTouchBarController* controller_;  // weak.
   base::scoped_nsobject<CreditCardAutofillTouchBarController>
       autofillTouchBarController_;
   base::scoped_nsobject<SuggestedTextTouchBarController>
       suggestedTextTouchBarController_;
 }
 
++ (WebTextfieldTouchBarController*)controllerForWindow:(NSWindow*)window;
+
 // Designated initializer.
-- (instancetype)initWithTabContentsController:(TabContentsController*)owner;
+- (instancetype)initWithController:(BrowserWindowTouchBarController*)controller;
 
 - (void)showCreditCardAutofillWithController:
     (autofill::AutofillPopupController*)controller;
 
 - (void)hideCreditCardAutofillTouchBar;
 
+- (void)updateWebContents:(content::WebContents*)contents;
+
 - (void)invalidateTouchBar;
 
 // Creates and returns a touch bar.
diff --git a/chrome/browser/ui/cocoa/touchbar/web_textfield_touch_bar_controller.mm b/chrome/browser/ui/cocoa/touchbar/web_textfield_touch_bar_controller.mm
index 347f606..f51d0af6 100644
--- a/chrome/browser/ui/cocoa/touchbar/web_textfield_touch_bar_controller.mm
+++ b/chrome/browser/ui/cocoa/touchbar/web_textfield_touch_bar_controller.mm
@@ -8,25 +8,47 @@
 #include "base/mac/scoped_nsobject.h"
 #include "base/mac/sdk_forward_declarations.h"
 #include "chrome/browser/ui/autofill/autofill_popup_controller.h"
+#import "chrome/browser/ui/cocoa/browser_window_controller.h"
 #import "chrome/browser/ui/cocoa/tab_contents/tab_contents_controller.h"
+#import "chrome/browser/ui/cocoa/touchbar/browser_window_touch_bar_controller.h"
 #import "chrome/browser/ui/cocoa/touchbar/credit_card_autofill_touch_bar_controller.h"
 #import "chrome/browser/ui/cocoa/touchbar/suggested_text_touch_bar_controller.h"
+#include "chrome/browser/ui/views/frame/browser_frame_mac.h"
+#include "chrome/browser/ui/views/frame/browser_view.h"
 #include "chrome/common/chrome_features.h"
 #include "content/public/browser/web_contents.h"
 #import "ui/base/cocoa/touch_bar_util.h"
+#include "ui/base/ui_base_features.h"
 
 @implementation WebTextfieldTouchBarController
 
-- (instancetype)initWithTabContentsController:(TabContentsController*)owner {
-  if ((self = [super init])) {
-    owner_ = owner;
++ (WebTextfieldTouchBarController*)controllerForWindow:(NSWindow*)window {
+  if (features::IsViewsBrowserCocoa()) {
+    BrowserWindowController* bwc =
+        [BrowserWindowController browserWindowControllerForWindow:window];
+    return [[bwc browserWindowTouchBarController] webTextfieldTouchBar];
+  }
 
-    if (IsSuggestedTextTouchBarEnabled()) {
+  BrowserView* browser_view =
+      BrowserView::GetBrowserViewForNativeWindow(window);
+  if (!browser_view)
+    return nil;
+
+  BrowserFrameMac* browser_frame = static_cast<BrowserFrameMac*>(
+      browser_view->frame()->native_browser_frame());
+  return [browser_frame->GetTouchBarController() webTextfieldTouchBar];
+}
+
+- (instancetype)initWithController:
+    (BrowserWindowTouchBarController*)controller {
+  if ((self = [super init])) {
+    controller_ = controller;
+
+    if (base::FeatureList::IsEnabled(features::kSuggestedTextTouchBar)) {
       suggestedTextTouchBarController_.reset(
           [[SuggestedTextTouchBarController alloc]
-              initWithWebContents:[owner_ webContents]
+              initWithWebContents:[controller_ webContents]
                        controller:self]);
-      [suggestedTextTouchBarController_ initObserver];
     }
   }
 
@@ -51,13 +73,12 @@
   [self invalidateTouchBar];
 }
 
-bool IsSuggestedTextTouchBarEnabled() {
-  return base::FeatureList::IsEnabled(features::kSuggestedTextTouchBar);
+- (void)updateWebContents:(content::WebContents*)contents {
+  [suggestedTextTouchBarController_ setWebContents:contents];
 }
 
 - (void)invalidateTouchBar {
-  if ([owner_ respondsToSelector:@selector(setTouchBar:)])
-    [owner_ performSelector:@selector(setTouchBar:) withObject:nil];
+  [controller_ invalidateTouchBar];
 }
 
 - (NSTouchBar*)makeTouchBar {
diff --git a/chrome/browser/ui/views/frame/browser_frame.h b/chrome/browser/ui/views/frame/browser_frame.h
index 5e4b775d..36aa01a 100644
--- a/chrome/browser/ui/views/frame/browser_frame.h
+++ b/chrome/browser/ui/views/frame/browser_frame.h
@@ -120,6 +120,10 @@
   // Note that in multi user mode this will upon each call create a new model.
   ui::MenuModel* GetSystemMenuModel();
 
+  NativeBrowserFrame* native_browser_frame() const {
+    return native_browser_frame_;
+  }
+
  private:
   // Callback for MenuRunner.
   void OnMenuClosed();
diff --git a/chrome/browser/ui/views/frame/browser_frame_mac.h b/chrome/browser/ui/views/frame/browser_frame_mac.h
index d7a48c60..1a1aa8ee 100644
--- a/chrome/browser/ui/views/frame/browser_frame_mac.h
+++ b/chrome/browser/ui/views/frame/browser_frame_mac.h
@@ -13,7 +13,8 @@
 
 class BrowserFrame;
 class BrowserView;
-@protocol WindowTouchBarDelegate;
+@class BrowserWindowTouchBarController;
+@class BrowserWindowTouchBarViewsDelegate;
 @class ChromeCommandDispatcherDelegate;
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -25,6 +26,8 @@
  public:
   BrowserFrameMac(BrowserFrame* browser_frame, BrowserView* browser_view);
 
+  BrowserWindowTouchBarController* GetTouchBarController() const;
+
   // Overridden from views::NativeWidgetMac:
   int SheetPositionY() override;
   void OnWindowFullscreenStateChange() override;
@@ -57,7 +60,7 @@
   BrowserView* browser_view_;  // Weak. Our ClientView.
   base::scoped_nsobject<ChromeCommandDispatcherDelegate>
       command_dispatcher_delegate_;
-  base::scoped_nsprotocol<id<WindowTouchBarDelegate>> touch_bar_delegate_;
+  base::scoped_nsobject<BrowserWindowTouchBarViewsDelegate> touch_bar_delegate_;
 
   DISALLOW_COPY_AND_ASSIGN(BrowserFrameMac);
 };
diff --git a/chrome/browser/ui/views/frame/browser_frame_mac.mm b/chrome/browser/ui/views/frame/browser_frame_mac.mm
index 12c822a..ff426e6b 100644
--- a/chrome/browser/ui/views/frame/browser_frame_mac.mm
+++ b/chrome/browser/ui/views/frame/browser_frame_mac.mm
@@ -42,16 +42,18 @@
 
 // Bridge Obj-C class for WindowTouchBarDelegate and
 // BrowserWindowTouchBarController.
-@interface BrowserWindowTouchBarControllerViewsDelegate
+@interface BrowserWindowTouchBarViewsDelegate
     : NSObject<WindowTouchBarDelegate> {
   Browser* browser_;  // Weak.
   NSWindow* window_;  // Weak.
   base::scoped_nsobject<BrowserWindowTouchBarController> touchBarController_;
 }
 
+- (BrowserWindowTouchBarController*)touchBarController;
+
 @end
 
-@implementation BrowserWindowTouchBarControllerViewsDelegate
+@implementation BrowserWindowTouchBarViewsDelegate
 
 - (instancetype)initWithBrowser:(Browser*)browser window:(NSWindow*)window {
   if ((self = [super init])) {
@@ -62,6 +64,10 @@
   return self;
 }
 
+- (BrowserWindowTouchBarController*)touchBarController {
+  return touchBarController_.get();
+}
+
 - (NSTouchBar*)makeTouchBar API_AVAILABLE(macos(10.12.2)) {
   if (!touchBarController_) {
     touchBarController_.reset([[BrowserWindowTouchBarController alloc]
@@ -83,6 +89,11 @@
 BrowserFrameMac::~BrowserFrameMac() {
 }
 
+BrowserWindowTouchBarController* BrowserFrameMac::GetTouchBarController()
+    const {
+  return [touch_bar_delegate_ touchBarController];
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // BrowserFrameMac, views::NativeWidgetMac implementation:
 
@@ -137,10 +148,9 @@
   [ns_window setCommandHandler:[[[BrowserWindowCommandHandler alloc] init]
                                    autorelease]];
 
-  touch_bar_delegate_.reset(
-      [[BrowserWindowTouchBarControllerViewsDelegate alloc]
-          initWithBrowser:browser_view_->browser()
-                   window:ns_window]);
+  touch_bar_delegate_.reset([[BrowserWindowTouchBarViewsDelegate alloc]
+      initWithBrowser:browser_view_->browser()
+               window:ns_window]);
   [ns_window setWindowTouchBarDelegate:touch_bar_delegate_.get()];
 
   return ns_window.autorelease();
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.cc b/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.cc
index 0b967d6..b7c77b3 100644
--- a/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.cc
+++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.cc
@@ -9,13 +9,13 @@
 #include "ash/frame/caption_buttons/frame_back_button.h"  // mash-ok
 #include "ash/frame/caption_buttons/frame_caption_button_container_view.h"  // mash-ok
 #include "ash/frame/default_frame_header.h"      // mash-ok
-#include "ash/frame/frame_border_hit_test.h"     // mash-ok
 #include "ash/frame/frame_header_util.h"         // mash-ok
 #include "ash/public/cpp/app_list/app_list_features.h"
 #include "ash/public/cpp/app_types.h"
 #include "ash/public/cpp/ash_constants.h"
 #include "ash/public/cpp/ash_layout_constants.h"
 #include "ash/public/cpp/ash_switches.h"
+#include "ash/public/cpp/frame_border_hit_test.h"
 #include "ash/public/cpp/window_properties.h"
 #include "ash/public/interfaces/constants.mojom.h"
 #include "ash/public/interfaces/window_state_type.mojom.h"
@@ -450,19 +450,7 @@
 }
 
 int BrowserNonClientFrameViewAsh::NonClientHitTest(const gfx::Point& point) {
-  if (hosted_app_button_container_) {
-    gfx::Point client_point(point);
-    View::ConvertPointToTarget(this, hosted_app_button_container_,
-                               &client_point);
-    if (hosted_app_button_container_->HitTestPoint(client_point))
-      return HTCLIENT;
-  }
-
-  // TODO(sky): figure out how this interaction should work.
-  const int hit_test =
-      IsMash() ? HTCLIENT
-               : ash::FrameBorderNonClientHitTest(
-                     this, back_button_, caption_button_container_, point);
+  int hit_test = ash::FrameBorderNonClientHitTest(this, point);
 
   // When the window is restored we want a large click target above the tabs
   // to drag the window, so redirect clicks in the tab's shadow to caption.
@@ -470,9 +458,10 @@
       !frame()->IsFullscreen()) {
     gfx::Point client_point(point);
     View::ConvertPointToTarget(this, frame()->client_view(), &client_point);
-    gfx::Rect tabstrip_bounds(browser_view()->tabstrip()->bounds());
+    gfx::Rect tabstrip_shadow_bounds(browser_view()->tabstrip()->bounds());
     constexpr int kTabShadowHeight = 4;
-    if (client_point.y() < tabstrip_bounds.y() + kTabShadowHeight)
+    tabstrip_shadow_bounds.set_height(kTabShadowHeight);
+    if (tabstrip_shadow_bounds.Contains(client_point))
       return HTCAPTION;
   }
 
diff --git a/chrome/browser/ui/views/frame/glass_browser_frame_view.cc b/chrome/browser/ui/views/frame/glass_browser_frame_view.cc
index f25f4f4..10489a28a 100644
--- a/chrome/browser/ui/views/frame/glass_browser_frame_view.cc
+++ b/chrome/browser/ui/views/frame/glass_browser_frame_view.cc
@@ -387,8 +387,10 @@
 }
 
 void GlassBrowserFrameView::UpdateWindowTitle() {
-  if (ShowCustomTitle() && !frame()->IsFullscreen())
+  if (ShowCustomTitle() && !frame()->IsFullscreen()) {
+    LayoutTitleBar();
     window_title_->SchedulePaint();
+  }
 }
 
 void GlassBrowserFrameView::ResetWindowControls() {
diff --git a/chrome/browser/ui/views/frame/hosted_app_button_container.cc b/chrome/browser/ui/views/frame/hosted_app_button_container.cc
index d0c1e87..5404ca81 100644
--- a/chrome/browser/ui/views/frame/hosted_app_button_container.cc
+++ b/chrome/browser/ui/views/frame/hosted_app_button_container.cc
@@ -17,6 +17,7 @@
 #include "chrome/browser/ui/views/location_bar/content_setting_image_view.h"
 #include "chrome/browser/ui/views/page_action/page_action_icon_container_view.h"
 #include "chrome/browser/ui/views/toolbar/browser_actions_container.h"
+#include "ui/base/hit_test.h"
 #include "ui/compositor/layer_animation_element.h"
 #include "ui/compositor/layer_animation_sequence.h"
 #include "ui/compositor/scoped_layer_animation_settings.h"
@@ -27,6 +28,7 @@
 #include "ui/views/controls/label.h"
 #include "ui/views/layout/box_layout.h"
 #include "ui/views/layout/layout_provider.h"
+#include "ui/views/view_properties.h"
 #include "ui/views/widget/native_widget_aura.h"
 
 namespace {
@@ -181,6 +183,8 @@
     image_view->SetBorder(views::CreateEmptyBorder(
         gfx::Insets(kContentSettingIconInteriorPadding)));
     image_view->disable_animation();
+    image_view->SetProperty(views::kHitTestComponentKey,
+                            static_cast<int>(HTCLIENT));
     content_setting_views_.push_back(image_view.get());
     AddChildView(image_view.release());
   }
@@ -222,8 +226,16 @@
   layout.set_cross_axis_alignment(
       views::BoxLayout::CROSS_AXIS_ALIGNMENT_CENTER);
 
+  content_settings_container_->SetProperty(views::kHitTestComponentKey,
+                                           static_cast<int>(HTCLIENT));
   AddChildView(content_settings_container_);
+
+  page_action_icon_container_view_->SetProperty(views::kHitTestComponentKey,
+                                                static_cast<int>(HTCLIENT));
   AddChildView(page_action_icon_container_view_);
+
+  browser_actions_container_->SetProperty(views::kHitTestComponentKey,
+                                          static_cast<int>(HTCLIENT));
   AddChildView(browser_actions_container_);
   AddChildView(app_menu_button_);
 
diff --git a/chrome/browser/ui/views/frame/hosted_app_menu_button.cc b/chrome/browser/ui/views/frame/hosted_app_menu_button.cc
index 15b8259..3e1f57b 100644
--- a/chrome/browser/ui/views/frame/hosted_app_menu_button.cc
+++ b/chrome/browser/ui/views/frame/hosted_app_menu_button.cc
@@ -13,16 +13,20 @@
 #include "chrome/browser/ui/views/frame/browser_view.h"
 #include "chrome/browser/ui/views/toolbar/app_menu.h"
 #include "chrome/grit/generated_resources.h"
+#include "ui/base/hit_test.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/gfx/paint_vector_icon.h"
 #include "ui/views/border.h"
 #include "ui/views/controls/button/menu_button.h"
+#include "ui/views/view_properties.h"
 
 constexpr int kMenuHighlightFadeDurationMs = 800;
 
 HostedAppMenuButton::HostedAppMenuButton(BrowserView* browser_view)
     : AppMenuButton(this), browser_view_(browser_view) {
+  SetProperty(views::kHitTestComponentKey, static_cast<int>(HTMENU));
+
   SetInkDropMode(InkDropMode::ON);
   // Disable focus ring for consistency with sibling buttons and AppMenuButton.
   SetFocusPainter(nullptr);
diff --git a/chrome/browser/ui/views/frame/opaque_browser_frame_view.cc b/chrome/browser/ui/views/frame/opaque_browser_frame_view.cc
index d1178e1d..501feb7 100644
--- a/chrome/browser/ui/views/frame/opaque_browser_frame_view.cc
+++ b/chrome/browser/ui/views/frame/opaque_browser_frame_view.cc
@@ -284,8 +284,10 @@
 }
 
 void OpaqueBrowserFrameView::UpdateWindowTitle() {
-  if (!frame()->IsFullscreen())
+  if (!frame()->IsFullscreen() && ShouldShowWindowTitle()) {
+    Layout();
     window_title_->SchedulePaint();
+  }
 }
 
 void OpaqueBrowserFrameView::SizeConstraintsChanged() {}
diff --git a/chrome/browser/ui/views/omnibox/omnibox_popup_contents_view.cc b/chrome/browser/ui/views/omnibox/omnibox_popup_contents_view.cc
index 4c60d9b..29070c510 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_popup_contents_view.cc
+++ b/chrome/browser/ui/views/omnibox/omnibox_popup_contents_view.cc
@@ -45,6 +45,10 @@
 #include "ui/views/widget/widget.h"
 #include "ui/views/window/non_client_view.h"
 
+#if defined(USE_AURA)
+#include "ui/wm/core/window_util.h"
+#endif  // defined(USE_AURA)
+
 namespace {
 
 // Cache the shadow images so that potentially expensive shadow drawing isn't
@@ -194,6 +198,12 @@
       animator_->SetTargetBounds(bounds);
     else
       SetBounds(bounds);
+
+#if defined(USE_AURA)
+    // TODO(malaykeshav): Remove this manual snap when we start snapping each
+    // window to its parent window. See https://crbug.com/863268 for more info.
+    wm::SnapWindowToPixelBoundary(GetNativeWindow());
+#endif  // defined(USE_AURA)
   }
 
   void ShowAnimated() {
diff --git a/chrome/browser/ui/views/omnibox/omnibox_popup_contents_view_browsertest.cc b/chrome/browser/ui/views/omnibox/omnibox_popup_contents_view_browsertest.cc
index 96bab85..0d12a623 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_popup_contents_view_browsertest.cc
+++ b/chrome/browser/ui/views/omnibox/omnibox_popup_contents_view_browsertest.cc
@@ -37,7 +37,9 @@
 #include "ui/views/widget/widget.h"
 
 #if defined(USE_AURA)
+#include "ui/aura/window.h"
 #include "ui/native_theme/native_theme_dark_aura.h"
+#include "ui/wm/core/window_properties.h"
 #endif
 
 #if defined(USE_X11)
@@ -170,6 +172,12 @@
 IN_PROC_BROWSER_TEST_P(OmniboxPopupContentsViewTest, PopupAlignment) {
   views::Widget* popup = CreatePopupForTestQuery();
 
+#if defined(USE_AURA)
+  popup_view()->UpdatePopupAppearance();
+  EXPECT_TRUE(
+      popup->GetNativeWindow()->GetProperty(wm::kSnapChildrenToPixelBoundary));
+#endif  // defined(USE_AURA)
+
   if (GetParam() == WIDE) {
     EXPECT_EQ(toolbar()->width(), popup->GetRestoredBounds().width());
   } else {
diff --git a/chrome/browser/ui/webui/settings/chromeos/account_manager_handler.cc b/chrome/browser/ui/webui/settings/chromeos/account_manager_handler.cc
index 9090944..f7c86340 100644
--- a/chrome/browser/ui/webui/settings/chromeos/account_manager_handler.cc
+++ b/chrome/browser/ui/webui/settings/chromeos/account_manager_handler.cc
@@ -157,6 +157,10 @@
 }
 
 void AccountManagerUIHandler::RefreshUI() {
+  if (!IsJavascriptAllowed()) {
+    return;
+  }
+
   FireWebUIListener("accounts-changed");
 }
 
diff --git a/chrome/browser/ui/webui/settings/chromeos/internet_handler.cc b/chrome/browser/ui/webui/settings/chromeos/internet_handler.cc
index 2f8cfda..7a4c8be 100644
--- a/chrome/browser/ui/webui/settings/chromeos/internet_handler.cc
+++ b/chrome/browser/ui/webui/settings/chromeos/internet_handler.cc
@@ -187,16 +187,16 @@
     return;
   }
 
-  if (network->vpn_provider_type() == shill::kProviderThirdPartyVpn) {
+  if (network->GetVpnProviderType() == shill::kProviderThirdPartyVpn) {
     // Request that the third-party VPN provider used by the |network| show a
     // configuration dialog for it.
     VpnServiceFactory::GetForBrowserContext(profile_)
-        ->SendShowConfigureDialogToExtension(network->vpn_provider_id(),
+        ->SendShowConfigureDialogToExtension(network->vpn_provider()->id,
                                              network->name());
     return;
   }
 
-  if (network->vpn_provider_type() == shill::kProviderArcVpn) {
+  if (network->GetVpnProviderType() == shill::kProviderArcVpn) {
     auto* net_instance = ARC_GET_INSTANCE_FOR_METHOD(
         arc::ArcServiceManager::Get()->arc_bridge_service()->net(),
         ConfigureAndroidVpn);
@@ -209,7 +209,7 @@
   }
 
   NET_LOG(ERROR) << "ConfigureThirdPartyVpn: Unsupported VPN type: "
-                 << network->vpn_provider_type() << " For: " << guid;
+                 << network->GetVpnProviderType() << " For: " << guid;
 }
 
 void InternetHandler::RequestArcVpnProviders(const base::ListValue* args) {
diff --git a/chrome/browser/vr/BUILD.gn b/chrome/browser/vr/BUILD.gn
index e0a40bc..d6e233fa 100644
--- a/chrome/browser/vr/BUILD.gn
+++ b/chrome/browser/vr/BUILD.gn
@@ -255,7 +255,6 @@
     "ui_test_input.h",
     "ui_unsupported_mode.h",
     "vr_export.h",
-    "vr_features.h",
     "vr_geometry_util.cc",
     "vr_geometry_util.h",
   ]
@@ -274,15 +273,18 @@
     "//chrome/browser/vr/vector_icons",
     "//chrome/common:constants",
     "//components/omnibox/browser",
+    "//components/rappor/public:public",
     "//components/security_state/core",
     "//components/strings",
     "//components/toolbar",
+    "//components/toolbar:vector_icons",
     "//components/ukm/content",
     "//components/url_formatter",
     "//components/vector_icons",
     "//content/public/browser",
     "//content/public/common",
     "//device/vr",
+    "//device/vr/buildflags:buildflags",
     "//device/vr/public/mojom",
     "//media",
     "//net",
diff --git a/chrome/common/extensions/docs/examples/api/fontSettings/css/chrome_shared.css b/chrome/common/extensions/docs/examples/api/fontSettings/css/chrome_shared.css
index 656b45d..007d6f440 100644
--- a/chrome/common/extensions/docs/examples/api/fontSettings/css/chrome_shared.css
+++ b/chrome/common/extensions/docs/examples/api/fontSettings/css/chrome_shared.css
@@ -74,8 +74,8 @@
 }
 
 html[dir='rtl'] .favicon-cell.weakrtl {
-  -webkit-padding-end: 22px;
-  -webkit-padding-start: 0;
+  padding-inline-end: 22px;
+  padding-inline-start: 0;
 }
 
 /* weakrtl for selection drop downs needs to account for the fact that
diff --git a/chrome/common/extensions/docs/examples/api/fontSettings/css/overlay.css b/chrome/common/extensions/docs/examples/api/fontSettings/css/overlay.css
index 361938221..432ca62 100644
--- a/chrome/common/extensions/docs/examples/api/fontSettings/css/overlay.css
+++ b/chrome/common/extensions/docs/examples/api/fontSettings/css/overlay.css
@@ -94,7 +94,6 @@
 }
 
 .overlay .page h1 {
-  -webkit-padding-end: 24px;
   -webkit-user-select: none;
   color: #333;
   /* 120% of the body's font-size of 84% is 16px. This will keep the relative
@@ -138,8 +137,8 @@
 }
 
 .overlay .page .button-strip > button {
-  -webkit-margin-start: 10px;
   display: block;
+  margin-inline-start: 10px;
 }
 
 /* On OSX 10.7, hidden scrollbars may prevent the user from realizing that the
diff --git a/chrome/common/extensions/docs/examples/api/fontSettings/css/uber_shared.css b/chrome/common/extensions/docs/examples/api/fontSettings/css/uber_shared.css
index 4fc5b0f50..482451b5 100644
--- a/chrome/common/extensions/docs/examples/api/fontSettings/css/uber_shared.css
+++ b/chrome/common/extensions/docs/examples/api/fontSettings/css/uber_shared.css
@@ -3,8 +3,8 @@
  * found in the LICENSE file. */
 
 body.uber-frame {
-  -webkit-margin-start: 155px;
   color: rgb(48, 57, 66);
+  margin-inline-start: 155px;
 }
 
 html[dir='rtl'] body.uber-frame {
@@ -19,7 +19,7 @@
 body.uber-frame #mainview-content .page,
 body.uber-frame .subpage-sheet-container .page,
 body.uber-frame > .page {
-  -webkit-margin-end: 24px;
+  margin-inline-end: 24px;
   min-width: 576px;
   padding-bottom: 20px;
   padding-top: 55px;
@@ -31,7 +31,7 @@
                                             rgba(255, 255, 255, 0.92));
   left: 155px;
   /* <section>s in options currently amount to 638px total, broken up into
-   * 600px max-width + 18px -webkit-padding-start + 20px -webkit-margin-end
+   * 600px max-width + 18px padding-inline-start + 20px margin-inline-end
    * so we mirror this value here so the headers match width and horizontal
    * alignment when scrolling sideways. */
   max-width: 738px;
@@ -78,11 +78,11 @@
 /* Create a border under the h1 (but before anything that gets appended
  * to the end of the header). */
 body.uber-frame header > h1::after {
-  -webkit-margin-end: 20px;
   background-color: #eee;
   content: ' ';
   display: block;
   height: 1px;
+  margin-inline-end: 20px;
   position: relative;
   top: 13px;
 }
@@ -99,10 +99,10 @@
 /* Sections are used in options pages, help page and history page. This defines
  * the section metrics to match the header metrics above. */
 body.uber-frame section {
-  -webkit-padding-start: 18px;
   margin-bottom: 24px;
   margin-top: 8px;
   max-width: 600px;
+  padding-inline-start: 18px;
 }
 
 body.uber-frame section:last-of-type {
@@ -110,7 +110,7 @@
 }
 
 body.uber-frame section > h3 {
-  -webkit-margin-start: -18px;
+  margin-inline-start: -18px;
 }
 
 body.uber-frame section > div:only-of-type {
diff --git a/chrome/common/extensions/docs/examples/api/fontSettings/css/widgets.css b/chrome/common/extensions/docs/examples/api/fontSettings/css/widgets.css
index e03bd8b..dee76357 100644
--- a/chrome/common/extensions/docs/examples/api/fontSettings/css/widgets.css
+++ b/chrome/common/extensions/docs/examples/api/fontSettings/css/widgets.css
@@ -46,19 +46,19 @@
 :-webkit-any(button,
              input[type='button'],
              input[type='submit']):not(.custom-appearance):not(.link-button) {
-  -webkit-padding-end: 10px;
-  -webkit-padding-start: 10px;
+  padding-inline-end: 10px;
+  padding-inline-start: 10px;
 }
 
 select {
   -webkit-appearance: none;
-  -webkit-padding-end: 20px;
-  -webkit-padding-start: 6px;
   /* OVERRIDE */
   background-image: url('../images/select.png'),
       -webkit-linear-gradient(#ededed, #ededed 38%, #dedede);
   background-position: right center;
   background-repeat: no-repeat;
+  padding-inline-end: 20px;
+  padding-inline-start: 6px;
 }
 
 html[dir='rtl'] select {
@@ -292,9 +292,9 @@
 }
 
 :-webkit-any(.checkbox, .radio) label input ~ span {
-  -webkit-margin-start: 0.6em;
   /* Make sure long spans wrap at the same horizontal position they start. */
   display: block;
+  margin-inline-start: 0.6em;
 }
 
 :-webkit-any(.checkbox, .radio) label:hover {
diff --git a/chrome/common/extensions/docs/examples/api/fontSettings/options.html b/chrome/common/extensions/docs/examples/api/fontSettings/options.html
index 1d378671..3e40b67 100644
--- a/chrome/common/extensions/docs/examples/api/fontSettings/options.html
+++ b/chrome/common/extensions/docs/examples/api/fontSettings/options.html
@@ -16,8 +16,8 @@
 <link rel="stylesheet" href="slider.css">
 <style>
 body.uber-frame {
-  -webkit-margin-start: 18px;
-  -webkit-margin-end: 30px;
+  margin-inline-start: 18px;
+  margin-inline-end: 30px;
 }
 
 body.uber-frame section {
@@ -29,8 +29,8 @@
 }
 
 body.uber-frame header {
-  -webkit-padding-start: 18px;
   left: 0;
+  padding-inline-start: 18px;
   right: 0;
 }
 
@@ -65,7 +65,7 @@
 }
 
 .font-settings-div {
-  -webkit-margin-end: 5px;
+  margin-inline-end: 5px;
   width: 180px;
 }
 
@@ -128,13 +128,13 @@
 }
 
 #footer > button {
-  -webkit-padding-start: 9px;
-  -webkit-padding-end: 9px;
+  padding-inline-start: 9px;
+  padding-inline-end: 9px;
 }
 
 #footer > #apply-settings {
-  -webkit-padding-start: 17px;
-  -webkit-padding-end: 17px;
+  padding-inline-start: 17px;
+  padding-inline-end: 17px;
 }
 
 #apply-settings:enabled {
diff --git a/chrome/common/extensions/docs/examples/extensions/plugin_settings/css/plugin_list.css b/chrome/common/extensions/docs/examples/extensions/plugin_settings/css/plugin_list.css
index 9d178e5..acb72a76 100644
--- a/chrome/common/extensions/docs/examples/extensions/plugin_settings/css/plugin_list.css
+++ b/chrome/common/extensions/docs/examples/extensions/plugin_settings/css/plugin_list.css
@@ -1,8 +1,6 @@
-/*
-Copyright (c) 2011 The Chromium Authors. All rights reserved.
-Use of this source code is governed by a BSD-style license that can be
-found in the LICENSE file.
-*/
+/* Copyright (c) 2011 The Chromium Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file. */
 
 body {
   font-family: Helvetica, sans-serif;
@@ -38,7 +36,7 @@
 
 .plugin-description {
   display: inline-block;
-  -webkit-padding-start: 7px;
+  padding-inline-start: 7px;
   width: auto;
   overflow: hidden;
   text-overflow: ellipsis;
@@ -76,8 +74,8 @@
 }
 
 .column-headers {
-  -webkit-margin-start: 17px;
   display: -webkit-box;
+  margin-inline-start: 17px;
 }
 
 .column-headers > div {
diff --git a/chrome/common/extensions/docs/examples/extensions/plugin_settings/css/rule_list.css b/chrome/common/extensions/docs/examples/extensions/plugin_settings/css/rule_list.css
index b67157b..2d6c9c1e 100644
--- a/chrome/common/extensions/docs/examples/extensions/plugin_settings/css/rule_list.css
+++ b/chrome/common/extensions/docs/examples/extensions/plugin_settings/css/rule_list.css
@@ -1,13 +1,11 @@
-/*
-Copyright (c) 2011 The Chromium Authors. All rights reserved.
-Use of this source code is governed by a BSD-style license that can be
-found in the LICENSE file.
-*/
+/* Copyright (c) 2011 The Chromium Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file. */
 
 .rule-pattern {
   -webkit-box-flex: 1;
-  -webkit-margin-end: 10px;
-  -webkit-margin-start: 14px;
+  margin-inline-end: 10px;
+  margin-inline-start: 14px;
 }
 
 .rule-behavior {
diff --git a/chrome/common/extensions/docs/examples/extensions/plugin_settings/domui/css/chrome_shared.css b/chrome/common/extensions/docs/examples/extensions/plugin_settings/domui/css/chrome_shared.css
index fa70aa20..dac22eb 100644
--- a/chrome/common/extensions/docs/examples/extensions/plugin_settings/domui/css/chrome_shared.css
+++ b/chrome/common/extensions/docs/examples/extensions/plugin_settings/domui/css/chrome_shared.css
@@ -1,3 +1,7 @@
+/* Copyright (c) 2011 The Chromium Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file. */
+
 /* Styles common to WebUI pages that share the options pages style */
 body {
   cursor: default;
@@ -13,7 +17,6 @@
 }
 
 #navbar-content-title {
-  -webkit-padding-end: 24px;
   -webkit-user-select: none;
   color: #53637d;
   cursor: pointer;
@@ -21,6 +24,7 @@
   font-weight: normal;
   margin: 0;
   padding-bottom: 14px;
+  padding-inline-end: 24px;
   padding-top: 13px;
   text-align: end;
   text-shadow: white 0 1px 2px;
@@ -40,9 +44,9 @@
 }
 
 #navbar-container {
-  -webkit-border-end: 1px solid #c6c9ce;
   background: -webkit-linear-gradient(rgba(234, 238, 243, 0.2), #eaeef3),
               -webkit-linear-gradient(left, #eaeef3, #eaeef3 97%, #d3d7db);
+  border-inline-end: 1px solid #c6c9ce;
   position: fixed;
   bottom: 0;
   /* We set both left and right for the sake of RTL. */
@@ -78,9 +82,9 @@
   font-size: 105%;
   outline: none;
   padding: 7px 0;
+  padding-inline-end: 24px;
   text-align: end;
   text-shadow: white 0 1px 1px;
-  -webkit-padding-end: 24px;
 }
 
 .navbar-item:focus {
@@ -99,10 +103,10 @@
 
 #mainview {
   -webkit-box-align: stretch;
-  -webkit-padding-start: 216px;
   margin: 0;
   position: absolute;
   left: 0;
+  padding-inline-start: 216px;
   right: 0;
   top: 0;
   bottom: 0;
@@ -110,7 +114,7 @@
 }
 
 html.hide-menu #mainview {
-  -webkit-padding-start: 0;
+  padding-inline-start: 0;
 }
 
 #mainview-content {
@@ -216,8 +220,8 @@
 }
 
 html[dir='rtl'] .favicon-cell.weakrtl {
-  -webkit-padding-end: 22px;
-  -webkit-padding-start: 0;
+  padding-inline-end: 22px;
+  padding-inline-start: 0;
 }
 
 /* weakrtl for selection drop downs needs to account for the fact that
@@ -242,7 +246,6 @@
 }
 
 .page h1 {
-  -webkit-padding-end: 24px;
   -webkit-user-select: none;
   border-bottom: 1px solid #eeeeee;
   color: #53637d;
@@ -250,6 +253,7 @@
   font-weight: normal;
   margin: 0;
   padding-bottom: 4px;
+  padding-inline-end: 24px;
   padding-top: 13px;
   text-shadow: white 0 1px 2px;
 }
diff --git a/chrome/common/extensions/docs/examples/extensions/plugin_settings/domui/css/select.css b/chrome/common/extensions/docs/examples/extensions/plugin_settings/domui/css/select.css
index ba951e5..24de2aaf 100644
--- a/chrome/common/extensions/docs/examples/extensions/plugin_settings/domui/css/select.css
+++ b/chrome/common/extensions/docs/examples/extensions/plugin_settings/domui/css/select.css
@@ -9,8 +9,6 @@
   -webkit-appearance: button;
   -webkit-border-radius: 2px;
   -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
-  -webkit-padding-end: 20px;
-  -webkit-padding-start: 2px;
   -webkit-user-select: none;
   background-image: url("../images/select.png"),
                     -webkit-linear-gradient(#fafafa, #f4f4f4 40%, #e5e5e5);
@@ -22,6 +20,8 @@
   margin: 0;
   overflow: hidden;
   padding-top: 2px;
+  padding-inline-end: 20px;
+  padding-inline-start: 2px;
   padding-bottom: 2px;
   text-overflow: ellipsis;
   white-space: nowrap;
diff --git a/chrome/common/extensions/docs/examples/extensions/plugin_settings/options/css/list.css b/chrome/common/extensions/docs/examples/extensions/plugin_settings/options/css/list.css
index cee1b08..4ff7b90b 100644
--- a/chrome/common/extensions/docs/examples/extensions/plugin_settings/options/css/list.css
+++ b/chrome/common/extensions/docs/examples/extensions/plugin_settings/options/css/list.css
@@ -62,8 +62,8 @@
 list .deletable-item > :first-child {
   -webkit-box-align: center;
   -webkit-box-flex: 1;
-  -webkit-padding-end: 5px;
   display: -webkit-box;
+  padding-inline-end: 5px;
 }
 
 list .close-button {
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 87ee53a..d35b7f9 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -1726,7 +1726,7 @@
         "../browser/ui/ash/launcher/chrome_launcher_controller_test_util.h",
         "../browser/ui/ash/multi_user/test_multi_user_window_manager.cc",
         "../browser/ui/ash/multi_user/test_multi_user_window_manager.h",
-        "../browser/ui/ash/network/networking_config_delegate_chromeos_browsertest.cc",
+        "../browser/ui/ash/network/networking_config_chromeos_browsertest.cc",
         "../browser/ui/ash/shelf_browsertest.cc",
         "../browser/ui/ash/system_tray_client_browsertest.cc",
         "../browser/ui/ash/system_tray_tray_cast_browsertest_media_router_chromeos.cc",
@@ -2922,6 +2922,7 @@
       "//base:base_java",
       "//chrome/android:app_hooks_java",
       "//chrome/android:chrome_java",
+      "//components/favicon/core/test:test_support",
       "//components/gcm_driver/instance_id/android:instance_id_driver_java",
       "//components/gcm_driver/instance_id/android:instance_id_driver_test_support_java",
       "//content/public/android:content_java",
diff --git a/chrome/test/chromedriver/test/run_py_tests.py b/chrome/test/chromedriver/test/run_py_tests.py
index 8e9edfd..7b9416a 100755
--- a/chrome/test/chromedriver/test/run_py_tests.py
+++ b/chrome/test/chromedriver/test/run_py_tests.py
@@ -138,6 +138,8 @@
     'ChromeDriverTest.testGetCurrentWindowHandle',
     'ChromeDriverTest.testStartStop',
     'ChromeDriverTest.testSendCommand*',
+    # https://crbug.com/867511
+    'ChromeDriverTest.testWindowMaximize',
     # LaunchApp is an obsolete API.
     'ChromeExtensionsCapabilityTest.testCanLaunchApp',
     # https://bugs.chromium.org/p/chromedriver/issues/detail?id=2278
diff --git a/chrome/test/data/autofill/dynamic_form_element_invalid.html b/chrome/test/data/autofill/dynamic_form_element_invalid.html
new file mode 100644
index 0000000..dae67e09
--- /dev/null
+++ b/chrome/test/data/autofill/dynamic_form_element_invalid.html
@@ -0,0 +1,60 @@
+<!-- A page that is used to test that a dynamic form fill feature works properly. -->
+<body>
+  <form name="addr1.1" id="form1" action="https://example.com/" method="post">
+    Name: <input type="text" name="firstname" id="firstname" autocomplete="given-name"><br>
+   <input type="text" name="firstname" id="firstname2" autocomplete="given-name" style="display: none"><br>
+    Address: <input type="text" name="address1" id="address1"><br>
+    City: <input type="text" name="city" id="city"><br>
+    <input type="text" name="state_us" id="state_us" style="display: none;" autocomplete="region"><br>
+    Zip: <input name="zip" id="zip"> <br>
+    Country: <select name="country" id="country" onchange="CountryChanged()">
+      <option value="CA">Canada</option>
+      <option value="US">United States</option>
+    </select> <br>
+    Company: <input name="company" id="company"> <br>
+    Email: <input name="email" id="email"> <br>
+    Phone: <input name="phone" id="phone"> <br>
+    <input type="reset" value="Reset">
+    <input type="submit" value="Submit" id="profile_submit">
+  </form>
+</body>
+
+<script>
+
+
+var notify_on_address_input_change = false;
+var address_input_changed = false;
+
+function CountryChanged() {
+  // Reset the value of the address field.
+  var address1 = document.getElementById('address1');
+  address1.value = '';
+  address1.onchange = function() {
+    if (notify_on_address_input_change)
+      window.domAutomationController.send(address1.value != '');
+    else
+      address_input_changed = true;
+  }
+
+  // Change the element that triggered the autofill. Remove it, and make another
+  // field visible. This is to test if the autofill can handle the case where
+  // the clicked on element is no longer valid.
+  var first_name_input = document.getElementById("firstname");
+  first_name_input.parentNode.removeChild(first_name_input);
+
+  var name_later = document.getElementById("firstname2");
+  name_later.removeAttribute('style');
+}
+
+
+function hasRefilled() {
+  var address1 = document.getElementById('address1');
+  if (address1 && address_input_changed) {
+    window.domAutomationController.send(address1.value != '');
+  } else {
+    notify_on_address_input_change = true;
+  }
+}
+
+</script>
+
diff --git a/chrome/test/data/autofill/dynamic_form_element_invalid_noname_form.html b/chrome/test/data/autofill/dynamic_form_element_invalid_noname_form.html
new file mode 100644
index 0000000..e0020c8
--- /dev/null
+++ b/chrome/test/data/autofill/dynamic_form_element_invalid_noname_form.html
@@ -0,0 +1,60 @@
+<!-- A page that is used to test that a dynamic form fill feature works properly. -->
+<body>
+  <form id="form1" action="https://example.com/" method="post">
+    Name: <input type="text" name="firstname" id="firstname" autocomplete="given-name"><br>
+   <input type="text" name="firstname" id="firstname2" autocomplete="given-name" style="display: none"><br>
+    Address: <input type="text" name="address1" id="address1"><br>
+    City: <input type="text" name="city" id="city"><br>
+    <input type="text" name="state_us" id="state_us" style="display: none;" autocomplete="region"><br>
+    Zip: <input name="zip" id="zip"> <br>
+    Country: <select name="country" id="country" onchange="CountryChanged()">
+      <option value="CA">Canada</option>
+      <option value="US">United States</option>
+    </select> <br>
+    Company: <input name="company" id="company"> <br>
+    Email: <input name="email" id="email"> <br>
+    Phone: <input name="phone" id="phone"> <br>
+    <input type="reset" value="Reset">
+    <input type="submit" value="Submit" id="profile_submit">
+  </form>
+</body>
+
+<script>
+
+
+var notify_on_address_input_change = false;
+var address_input_changed = false;
+
+function CountryChanged() {
+  // Reset the value of the address field.
+  var address1 = document.getElementById('address1');
+  address1.value = '';
+  address1.onchange = function() {
+    if (notify_on_address_input_change)
+      window.domAutomationController.send(address1.value != '');
+    else
+      address_input_changed = true;
+  }
+
+  // Change the element that triggered the autofill. Remove it, and make another
+  // field visible. This is to test if the autofill can handle the case where
+  // the clicked on element is no longer valid.
+  var first_name_input = document.getElementById("firstname");
+  first_name_input.parentNode.removeChild(first_name_input);
+
+  var name_later = document.getElementById("firstname2");
+  name_later.removeAttribute('style');
+}
+
+
+function hasRefilled() {
+  var address1 = document.getElementById('address1');
+  if (address1 && address_input_changed) {
+    window.domAutomationController.send(address1.value != '');
+  } else {
+    notify_on_address_input_change = true;
+  }
+}
+
+</script>
+
diff --git a/chrome/test/data/autofill/dynamic_form_element_invalid_unowned.html b/chrome/test/data/autofill/dynamic_form_element_invalid_unowned.html
new file mode 100644
index 0000000..04bf4132
--- /dev/null
+++ b/chrome/test/data/autofill/dynamic_form_element_invalid_unowned.html
@@ -0,0 +1,60 @@
+<!-- A page that is used to test that a dynamic form fill feature works properly. -->
+<body>
+  Name:
+  <input type="text" name="firstname" id="firstname0" autocomplete="given-name" style="display: none"><br>
+  <input type="text" name="firstname" id="firstname" autocomplete="given-name"><br>
+  <input type="text" name="firstname" id="firstname2" autocomplete="given-name" style="display: none"><br>
+  Address: <input type="text" name="address1" id="address1"><br>
+  City: <input type="text" name="city" id="city"><br>
+  <input type="text" name="state_us" id="state_us" style="display: none;" autocomplete="region"><br>
+  Zip: <input name="zip" id="zip"> <br>
+  Country: <select name="country" id="country" onchange="CountryChanged()">
+    <option value="CA">Canada</option>
+    <option value="US">United States</option>
+  </select> <br>
+  Company: <input name="company" id="company"> <br>
+  Email: <input name="email" id="email"> <br>
+  Phone: <input name="phone" id="phone"> <br>
+  <input type="reset" value="Reset">
+  <input type="submit" value="Submit" id="profile_submit">
+</body>
+
+<script>
+
+
+var notify_on_address_input_change = false;
+var address_input_changed = false;
+
+function CountryChanged() {
+  // Reset the value of the address field.
+  var address1 = document.getElementById('address1');
+  address1.value = '';
+  address1.onchange = function() {
+    if (notify_on_address_input_change)
+      window.domAutomationController.send(address1.value != '');
+    else
+      address_input_changed = true;
+  }
+
+  // Change the element that triggered the autofill. Remove it, and make another
+  // field visible. This is to test if the autofill can handle the case where
+  // the clicked on element is no longer valid.
+  var first_name_input = document.getElementById("firstname");
+  first_name_input.parentNode.removeChild(first_name_input);
+
+  var name_later = document.getElementById("firstname2");
+  name_later.removeAttribute('style');
+}
+
+
+function hasRefilled() {
+  var address1 = document.getElementById('address1');
+  if (address1 && address_input_changed) {
+    window.domAutomationController.send(address1.value != '');
+  } else {
+    notify_on_address_input_change = true;
+  }
+}
+
+</script>
+
diff --git a/chrome/test/data/extensions/networking_config_delegate/background.js b/chrome/test/data/extensions/networking_config/background.js
similarity index 100%
rename from chrome/test/data/extensions/networking_config_delegate/background.js
rename to chrome/test/data/extensions/networking_config/background.js
diff --git a/chrome/test/data/extensions/networking_config_delegate/manifest.json b/chrome/test/data/extensions/networking_config/manifest.json
similarity index 74%
rename from chrome/test/data/extensions/networking_config_delegate/manifest.json
rename to chrome/test/data/extensions/networking_config/manifest.json
index 9ff003e..6f5b0dda 100644
--- a/chrome/test/data/extensions/networking_config_delegate/manifest.json
+++ b/chrome/test/data/extensions/networking_config/manifest.json
@@ -1,5 +1,5 @@
 {
-  "name": "NetworkingConfigDelegate test extension",
+  "name": "NetworkingConfig test extension",
   "version": "0.1",
   "manifest_version": 2,
   "background": {
diff --git a/chrome/test/data/notifications/android_test.html b/chrome/test/data/notifications/android_test.html
index bede1c2..bc255054 100644
--- a/chrome/test/data/notifications/android_test.html
+++ b/chrome/test/data/notifications/android_test.html
@@ -39,6 +39,17 @@
         }
         document.title = message;
       }
+
+      // Some tests require a count of how frequently they were invoked.
+      var message_counts = {}
+      function addCountAndSendToTest(message) {
+        if (message in message_counts) {
+          message_counts[message]++;
+        } else {
+          message_counts[message] = 1;
+        }
+        document.title = message + ': ' + message_counts[message];
+      }
     </script>
   </body>
 </html>
diff --git a/chrome/test/data/webui/settings/personalization_options_test.js b/chrome/test/data/webui/settings/personalization_options_test.js
index 1495b4c..845d0332 100644
--- a/chrome/test/data/webui/settings/personalization_options_test.js
+++ b/chrome/test/data/webui/settings/personalization_options_test.js
@@ -89,10 +89,13 @@
         testElement.unifiedConsentEnabled = false;
         Polymer.dom.flush();
         assertEquals(
-            8,
+            7,
             testElement.root.querySelectorAll('settings-toggle-button').length);
         testElement.unifiedConsentEnabled = true;
         Polymer.dom.flush();
+        assertEquals(
+            8,
+            testElement.root.querySelectorAll('settings-toggle-button').length);
       });
     });
   }
diff --git a/chromecast/net/connectivity_checker.cc b/chromecast/net/connectivity_checker.cc
index 5e9679e..74d18b1 100644
--- a/chromecast/net/connectivity_checker.cc
+++ b/chromecast/net/connectivity_checker.cc
@@ -36,8 +36,8 @@
 scoped_refptr<ConnectivityChecker> ConnectivityChecker::Create(
     const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
     net::URLRequestContextGetter* url_request_context_getter) {
-  return base::MakeRefCounted<ConnectivityCheckerImpl>(
-      task_runner, url_request_context_getter);
+  return ConnectivityCheckerImpl::Create(task_runner,
+                                         url_request_context_getter);
 }
 
 }  // namespace chromecast
diff --git a/chromecast/net/connectivity_checker_impl.cc b/chromecast/net/connectivity_checker_impl.cc
index b2acca1..297398f 100644
--- a/chromecast/net/connectivity_checker_impl.cc
+++ b/chromecast/net/connectivity_checker_impl.cc
@@ -56,20 +56,30 @@
 
 }  // namespace
 
+// static
+scoped_refptr<ConnectivityCheckerImpl> ConnectivityCheckerImpl::Create(
+    scoped_refptr<base::SingleThreadTaskRunner> task_runner,
+    net::URLRequestContextGetter* url_request_context_getter) {
+  DCHECK(task_runner);
+
+  auto connectivity_checker =
+      base::WrapRefCounted(new ConnectivityCheckerImpl(task_runner));
+  task_runner->PostTask(
+      FROM_HERE,
+      base::BindOnce(&ConnectivityCheckerImpl::Initialize, connectivity_checker,
+                     base::RetainedRef(url_request_context_getter)));
+  return connectivity_checker;
+}
+
 ConnectivityCheckerImpl::ConnectivityCheckerImpl(
-    const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
-    net::URLRequestContextGetter* url_request_context_getter)
+    scoped_refptr<base::SingleThreadTaskRunner> task_runner)
     : ConnectivityChecker(),
-      task_runner_(task_runner),
+      task_runner_(std::move(task_runner)),
       connected_(false),
       connection_type_(net::NetworkChangeNotifier::CONNECTION_NONE),
       check_errors_(0),
       network_changed_pending_(false) {
   DCHECK(task_runner_.get());
-
-  task_runner->PostTask(
-      FROM_HERE, base::BindOnce(&ConnectivityCheckerImpl::Initialize, this,
-                                base::RetainedRef(url_request_context_getter)));
 }
 
 void ConnectivityCheckerImpl::Initialize(
diff --git a/chromecast/net/connectivity_checker_impl.h b/chromecast/net/connectivity_checker_impl.h
index 0626d459..9b505b91 100644
--- a/chromecast/net/connectivity_checker_impl.h
+++ b/chromecast/net/connectivity_checker_impl.h
@@ -34,8 +34,8 @@
       public net::NetworkChangeNotifier::NetworkChangeObserver {
  public:
   // Connectivity checking and initialization will run on task_runner.
-  explicit ConnectivityCheckerImpl(
-      const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
+  static scoped_refptr<ConnectivityCheckerImpl> Create(
+      scoped_refptr<base::SingleThreadTaskRunner> task_runner,
       net::URLRequestContextGetter* url_request_context_getter);
 
   // ConnectivityChecker implementation:
@@ -43,6 +43,8 @@
   void Check() override;
 
  protected:
+  explicit ConnectivityCheckerImpl(
+      scoped_refptr<base::SingleThreadTaskRunner> task_runner);
   ~ConnectivityCheckerImpl() override;
 
  private:
diff --git a/chromeos/network/auto_connect_handler.cc b/chromeos/network/auto_connect_handler.cc
index 5cb72b3..010e8a6 100644
--- a/chromeos/network/auto_connect_handler.cc
+++ b/chromeos/network/auto_connect_handler.cc
@@ -352,7 +352,6 @@
       continue;
 
     const bool is_managed =
-        !network->profile_path().empty() && !network->guid().empty() &&
         managed_configuration_handler_->FindPolicyByGuidAndProfile(
             network->guid(), network->profile_path(), nullptr /* onc_source */);
     if (is_managed)
@@ -376,7 +375,6 @@
                                                false, false, 0, &networks);
   for (const NetworkState* network : networks) {
     const bool is_managed =
-        !network->profile_path().empty() && !network->guid().empty() &&
         managed_configuration_handler_->FindPolicyByGuidAndProfile(
             network->guid(), network->profile_path(), nullptr /* onc_source */);
     if (is_managed)
diff --git a/chromeos/network/managed_network_configuration_handler_impl.cc b/chromeos/network/managed_network_configuration_handler_impl.cc
index 37d18661..539af08 100644
--- a/chromeos/network/managed_network_configuration_handler_impl.cc
+++ b/chromeos/network/managed_network_configuration_handler_impl.cc
@@ -778,16 +778,19 @@
     const std::string& guid,
     const std::string& profile_path,
     ::onc::ONCSource* onc_source) const {
+  if (profile_path.empty())
+    return nullptr;
+
   const NetworkProfile* profile =
       network_profile_handler_->GetProfileForPath(profile_path);
   if (!profile) {
     NET_LOG_ERROR("Profile path unknown:" + profile_path, guid);
-    return NULL;
+    return nullptr;
   }
 
   const Policies* policies = GetPoliciesForProfile(*profile);
   if (!policies)
-    return NULL;
+    return nullptr;
 
   const base::DictionaryValue* policy =
       GetByGUID(policies->per_network_config, guid);
@@ -816,7 +819,6 @@
 
   // Check if the network is managed. Managed networks are always allowed.
   bool is_managed =
-      !profile_path.empty() &&
       FindPolicyByGuidAndProfile(guid, profile_path, nullptr /* onc_source */);
   if (is_managed)
     return false;
diff --git a/chromeos/network/network_connect.cc b/chromeos/network/network_connect.cc
index 2088575..fa12b2c0 100644
--- a/chromeos/network/network_connect.cc
+++ b/chromeos/network/network_connect.cc
@@ -139,7 +139,7 @@
 
   if (network->type() == shill::kTypeVPN) {
     // Third-party VPNs handle configuration UI themselves.
-    if (network->vpn_provider_type() != shill::kProviderThirdPartyVpn)
+    if (network->GetVpnProviderType() != shill::kProviderThirdPartyVpn)
       delegate_->ShowNetworkConfigure(network_id);
     return;
   }
diff --git a/chromeos/network/network_connection_handler_impl.cc b/chromeos/network/network_connection_handler_impl.cc
index 3218b39..72aa32cd 100644
--- a/chromeos/network/network_connection_handler_impl.cc
+++ b/chromeos/network/network_connection_handler_impl.cc
@@ -461,11 +461,9 @@
   service_properties.GetStringWithoutPathExpansion(shill::kProfileProperty,
                                                    &profile);
   ::onc::ONCSource onc_source = onc::ONC_SOURCE_NONE;
-  const base::DictionaryValue* policy = nullptr;
-  if (!profile.empty()) {
-    policy = managed_configuration_handler_->FindPolicyByGuidAndProfile(
-        guid, profile, &onc_source);
-  }
+  const base::DictionaryValue* policy =
+      managed_configuration_handler_->FindPolicyByGuidAndProfile(guid, profile,
+                                                                 &onc_source);
 
   if (type == shill::kTypeWifi) {
     const base::Value* hex_ssid_value = service_properties.FindKeyOfType(
diff --git a/chromeos/network/network_state.cc b/chromeos/network/network_state.cc
index ea00e84..328707382 100644
--- a/chromeos/network/network_state.cc
+++ b/chromeos/network/network_state.cc
@@ -175,7 +175,7 @@
     }
     return true;
   } else if (key == shill::kProviderProperty) {
-    std::string vpn_provider_type;
+    std::string vpn_provider_type, vpn_provider_id;
     const base::DictionaryValue* dict;
     if (!value.GetAsDictionary(&dict) ||
         !dict->GetStringWithoutPathExpansion(shill::kTypeProperty,
@@ -189,15 +189,12 @@
       // If the network uses a third-party or Arc VPN provider,
       // |shill::kHostProperty| contains the extension ID or Arc package name.
       if (!dict->GetStringWithoutPathExpansion(shill::kHostProperty,
-                                               &vpn_provider_id_)) {
+                                               &vpn_provider_id)) {
         NET_LOG(ERROR) << "Failed to parse " << path() << "." << key;
         return false;
       }
-    } else {
-      vpn_provider_id_.clear();
     }
-
-    vpn_provider_type_ = vpn_provider_type;
+    SetVpnProvider(vpn_provider_id, vpn_provider_type);
     return true;
   } else if (key == shill::kTetheringProperty) {
     return GetStringValue(key, value, &tethering_state_);
@@ -248,17 +245,17 @@
     dictionary->SetKey(shill::kDeviceProperty, base::Value(device_path()));
 
   // VPN properties.
-  if (NetworkTypePattern::VPN().MatchesType(type())) {
+  if (NetworkTypePattern::VPN().MatchesType(type()) && vpn_provider()) {
     // Shill sends VPN provider properties in a nested dictionary. |dictionary|
     // must replicate that nested structure.
     std::unique_ptr<base::DictionaryValue> provider_property(
         new base::DictionaryValue);
-    provider_property->SetKey(shill::kTypeProperty,
-                              base::Value(vpn_provider_type_));
-    if (vpn_provider_type_ == shill::kProviderThirdPartyVpn ||
-        vpn_provider_type_ == shill::kProviderArcVpn) {
+    std::string provider_type = vpn_provider()->type;
+    provider_property->SetKey(shill::kTypeProperty, base::Value(provider_type));
+    if (provider_type == shill::kProviderThirdPartyVpn ||
+        provider_type == shill::kProviderArcVpn) {
       provider_property->SetKey(shill::kHostProperty,
-                                base::Value(vpn_provider_id_));
+                                base::Value(vpn_provider()->id));
     }
     dictionary->SetWithoutPathExpansion(shill::kProviderProperty,
                                         std::move(provider_property));
@@ -336,6 +333,22 @@
   return gurl;
 }
 
+void NetworkState::SetCaptivePortalProvider(const std::string& id,
+                                            const std::string& name) {
+  if (id.empty()) {
+    captive_portal_provider_ = nullptr;
+    return;
+  }
+  if (!captive_portal_provider_)
+    captive_portal_provider_ = std::make_unique<CaptivePortalProviderInfo>();
+  captive_portal_provider_->id = id;
+  captive_portal_provider_->name = name;
+}
+
+std::string NetworkState::GetVpnProviderType() const {
+  return vpn_provider_ ? vpn_provider_->type : std::string();
+}
+
 bool NetworkState::RequiresActivation() const {
   return type() == shill::kTypeCellular &&
          activation_state() != shill::kActivationStateActivated &&
@@ -447,16 +460,6 @@
   guid_ = guid;
 }
 
-bool NetworkState::UpdateName(const base::DictionaryValue& properties) {
-  std::string updated_name =
-      shill_property_util::GetNameFromProperties(path(), properties);
-  if (updated_name != name()) {
-    set_name(updated_name);
-    return true;
-  }
-  return false;
-}
-
 std::string NetworkState::GetErrorState() const {
   if (ErrorIsValid(error()))
     return error();
@@ -500,4 +503,29 @@
   return new_state;
 }
 
+// Private methods.
+
+bool NetworkState::UpdateName(const base::DictionaryValue& properties) {
+  std::string updated_name =
+      shill_property_util::GetNameFromProperties(path(), properties);
+  if (updated_name != name()) {
+    set_name(updated_name);
+    return true;
+  }
+  return false;
+}
+
+void NetworkState::SetVpnProvider(const std::string& id,
+                                  const std::string& type) {
+  // |type| is required but |id| is only set for ThirdParty and Arc VPNs.
+  if (type.empty()) {
+    vpn_provider_ = nullptr;
+    return;
+  }
+  if (!vpn_provider_)
+    vpn_provider_ = std::make_unique<VpnProviderInfo>();
+  vpn_provider_->id = id;
+  vpn_provider_->type = type;
+}
+
 }  // namespace chromeos
diff --git a/chromeos/network/network_state.h b/chromeos/network/network_state.h
index 4aedc83..4c91c35 100644
--- a/chromeos/network/network_state.h
+++ b/chromeos/network/network_state.h
@@ -20,7 +20,7 @@
 namespace base {
 class DictionaryValue;
 class Value;
-}
+}  // namespace base
 
 namespace chromeos {
 
@@ -39,6 +39,20 @@
   explicit NetworkState(const std::string& path);
   ~NetworkState() override;
 
+  struct CaptivePortalProviderInfo {
+    // The id used by chrome to identify the provider (i.e. an extension id).
+    std::string id;
+    // The display name for the captive portal provider (i.e. extension name).
+    std::string name;
+  };
+
+  struct VpnProviderInfo {
+    // The id used by chrome to identify the provider (i.e. an extension id).
+    std::string id;
+    // The VPN type, provided by the VPN provider/extension.
+    std::string type;
+  };
+
   // ManagedState overrides
   // If you change this method, update GetProperties too.
   bool PropertyChanged(const std::string& key,
@@ -81,6 +95,10 @@
   bool connectable() const { return connectable_; }
   void set_connectable(bool connectable) { connectable_ = connectable; }
   bool is_captive_portal() const { return is_captive_portal_; }
+  const CaptivePortalProviderInfo* captive_portal_provider() const {
+    return captive_portal_provider_.get();
+  }
+  void SetCaptivePortalProvider(const std::string& id, const std::string& name);
   int signal_strength() const { return signal_strength_; }
   void set_signal_strength(int signal_strength) {
     signal_strength_ = signal_strength;
@@ -91,9 +109,7 @@
   const std::vector<uint8_t>& raw_ssid() const { return raw_ssid_; }
 
   // Cellular property accessors
-  const std::string& network_technology() const {
-    return network_technology_;
-  }
+  const std::string& network_technology() const { return network_technology_; }
   const std::string& activation_type() const { return activation_type_; }
   const std::string& activation_state() const { return activation_state_; }
   const std::string& roaming() const { return roaming_; }
@@ -102,8 +118,8 @@
   const std::string& tethering_state() const { return tethering_state_; }
 
   // VPN property accessors
-  const std::string& vpn_provider_type() const { return vpn_provider_type_; }
-  const std::string& vpn_provider_id() const { return vpn_provider_id_; }
+  const VpnProviderInfo* vpn_provider() const { return vpn_provider_.get(); }
+  std::string GetVpnProviderType() const;
 
   // Tether accessors and setters.
   int battery_percentage() const { return battery_percentage_; }
@@ -189,6 +205,8 @@
   // Returns true if |name_| changes.
   bool UpdateName(const base::DictionaryValue& properties);
 
+  void SetVpnProvider(const std::string& id, const std::string& type);
+
   // Set to true if the network is a member of Manager.Services.
   bool visible_ = false;
 
@@ -196,7 +214,7 @@
   // Instead use NetworkConfigurationHandler::GetProperties() to asynchronously
   // request properties from Shill.
   std::string security_class_;
-  std::string eap_method_;  // Needed for WiFi EAP networks
+  std::string eap_method_;    // Needed for WiFi EAP networks
   std::string eap_key_mgmt_;  // Needed for identifying Dynamic WEP networks
   std::string device_path_;
   std::string guid_;
@@ -222,6 +240,7 @@
   // Wireless properties, used for icons and Connect logic.
   bool connectable_ = false;
   bool is_captive_portal_ = false;
+  std::unique_ptr<CaptivePortalProviderInfo> captive_portal_provider_;
   int signal_strength_ = 0;
   std::string bssid_;  // For ARC
   int frequency_ = 0;  // For ARC
@@ -236,10 +255,9 @@
   std::string tethering_state_;
 
   // VPN properties, used to construct the display name and to show the correct
-  // configuration dialog.
-  std::string vpn_provider_type_;
-  // Extension ID or Arc package name for extension or Arc provider VPNs.
-  std::string vpn_provider_id_;
+  // configuration dialog. The id is the Extension ID or Arc package name for
+  // extension or Arc provider VPNs.
+  std::unique_ptr<VpnProviderInfo> vpn_provider_;
 
   // Tether properties.
   std::string carrier_;
diff --git a/chromeos/network/network_state_handler.cc b/chromeos/network/network_state_handler.cc
index d97792db..2d071e5 100644
--- a/chromeos/network/network_state_handler.cc
+++ b/chromeos/network/network_state_handler.cc
@@ -27,7 +27,6 @@
 #include "chromeos/network/network_device_handler.h"
 #include "chromeos/network/network_event_log.h"
 #include "chromeos/network/network_handler_callbacks.h"
-#include "chromeos/network/network_state.h"
 #include "chromeos/network/network_state_handler_observer.h"
 #include "chromeos/network/tether_constants.h"
 #include "third_party/cros_system_api/dbus/service_constants.h"
@@ -938,6 +937,38 @@
   shill_property_handler_->SetCheckPortalList(check_portal_list);
 }
 
+void NetworkStateHandler::SetCaptivePortalProviderForHexSsid(
+    const std::string& hex_ssid,
+    const std::string& provider_id,
+    const std::string& provider_name) {
+  NET_LOG(EVENT) << "SetCaptivePortalProviderForHexSsid: " << hex_ssid
+                 << " -> (" << provider_id << ", " << provider_name << ")";
+  // NetworkState hex SSIDs are always uppercase.
+  std::string hex_ssid_uc = hex_ssid;
+  transform(hex_ssid_uc.begin(), hex_ssid_uc.end(), hex_ssid_uc.begin(),
+            toupper);
+  if (provider_id.empty()) {
+    hex_ssid_to_captive_portal_provider_map_.erase(hex_ssid_uc);
+  } else {
+    NetworkState::CaptivePortalProviderInfo provider_info;
+    provider_info.id = provider_id;
+    provider_info.name = provider_name;
+    hex_ssid_to_captive_portal_provider_map_[hex_ssid_uc] =
+        std::move(provider_info);
+  }
+  // When a new entry is added or removed from the map, check all networks
+  // for a matching hex SSID and update the provider info. (This should occur
+  // infrequently). New networks will be updated when added.
+  for (auto& managed : network_list_) {
+    NetworkState* network = managed->AsNetworkState();
+    if (network->GetHexSsid() == hex_ssid_uc) {
+      NET_LOG(EVENT) << "Setting captive portal provider for network: "
+                     << network->guid() << " = " << provider_id;
+      network->SetCaptivePortalProvider(provider_id, provider_name);
+    }
+  }
+}
+
 void NetworkStateHandler::SetWakeOnLanEnabled(bool enabled) {
   NET_LOG_EVENT("SetWakeOnLanEnabled", enabled ? "true" : "false");
   shill_property_handler_->SetWakeOnLanEnabled(enabled);
@@ -1134,7 +1165,10 @@
       network_property_updated = true;
   }
   network_property_updated |= network->InitialPropertiesReceived(properties);
+
   UpdateGuid(network);
+  UpdateCaptivePortalProvider(network);
+
   network_list_sorted_ = false;
 
   // Notify observers of NetworkState changes.
@@ -1472,9 +1506,9 @@
   }
   // Ensure that the NetworkState has a valid GUID.
   std::string guid;
-  SpecifierGuidMap::iterator iter = specifier_guid_map_.find(specifier);
-  if (iter != specifier_guid_map_.end()) {
-    guid = iter->second;
+  SpecifierGuidMap::iterator guid_iter = specifier_guid_map_.find(specifier);
+  if (guid_iter != specifier_guid_map_.end()) {
+    guid = guid_iter->second;
   } else {
     guid = base::GenerateGUID();
     specifier_guid_map_[specifier] = guid;
@@ -1482,6 +1516,19 @@
   network->SetGuid(guid);
 }
 
+void NetworkStateHandler::UpdateCaptivePortalProvider(NetworkState* network) {
+  auto portal_iter =
+      hex_ssid_to_captive_portal_provider_map_.find(network->GetHexSsid());
+  if (portal_iter == hex_ssid_to_captive_portal_provider_map_.end()) {
+    network->SetCaptivePortalProvider("", "");
+    return;
+  }
+  NET_LOG(EVENT) << "Setting captive portal provider for network: "
+                 << network->guid() << " = " << portal_iter->second.id;
+  network->SetCaptivePortalProvider(portal_iter->second.id,
+                                    portal_iter->second.name);
+}
+
 void NetworkStateHandler::EnsureCellularNetwork(
     ManagedStateList* cellular_networks) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
diff --git a/chromeos/network/network_state_handler.h b/chromeos/network/network_state_handler.h
index f236a4a..eb222f1 100644
--- a/chromeos/network/network_state_handler.h
+++ b/chromeos/network/network_state_handler.h
@@ -20,6 +20,7 @@
 #include "chromeos/network/managed_state.h"
 #include "chromeos/network/network_handler.h"
 #include "chromeos/network/network_handler_callbacks.h"
+#include "chromeos/network/network_state.h"
 #include "chromeos/network/network_type_pattern.h"
 #include "chromeos/network/shill_property_handler.h"
 
@@ -314,6 +315,12 @@
   // Sets the list of devices on which portal check is enabled.
   void SetCheckPortalList(const std::string& check_portal_list);
 
+  // Sets a provider id (e.g. extension id) for a hex encoded SSID. If
+  // |provider_id| is empty the entry will be erased.
+  void SetCaptivePortalProviderForHexSsid(const std::string& hex_ssid,
+                                          const std::string& provider_id,
+                                          const std::string& provider_name);
+
   // Sets the Manager.WakeOnLan property. Note: we do not track this state, we
   // only set it.
   void SetWakeOnLanEnabled(bool enabled);
@@ -442,6 +449,10 @@
   // Ensure a valid GUID for NetworkState.
   void UpdateGuid(NetworkState* network);
 
+  // Look for a matching captive portal provider in
+  // |hex_ssid_to_captive_portal_provider_map_|.
+  void UpdateCaptivePortalProvider(NetworkState* network);
+
   // Cellular networks may not have an associated Shill Service (e.g. when the
   // SIM is locked or a mobile network is not available). To simplify the UI,
   // if a Cellular Device exists |cellular_networks| will be modified to contain
@@ -560,6 +571,11 @@
   // NetworkState that is not saved in a profile.
   SpecifierGuidMap specifier_guid_map_;
 
+  // Map of hex SSIDs to captive portal provider info.
+  // Used to set NetworkState::captive_portal_provider_.
+  std::map<std::string, NetworkState::CaptivePortalProviderInfo>
+      hex_ssid_to_captive_portal_provider_map_;
+
   // The state corresponding to the Tether device type. This value is managed by
   // the Tether component.
   TechnologyState tether_technology_state_ =
diff --git a/chromeos/network/network_state_handler_unittest.cc b/chromeos/network/network_state_handler_unittest.cc
index 6b9fa5a..d9f7256 100644
--- a/chromeos/network/network_state_handler_unittest.cc
+++ b/chromeos/network/network_state_handler_unittest.cc
@@ -16,6 +16,7 @@
 #include "base/command_line.h"
 #include "base/macros.h"
 #include "base/run_loop.h"
+#include "base/strings/string_number_conversions.h"
 #include "base/test/scoped_task_environment.h"
 #include "base/values.h"
 #include "chromeos/chromeos_switches.h"
@@ -1832,4 +1833,46 @@
   EXPECT_EQ("/service/cellular1", cellular_networks[0]->path());
 }
 
+TEST_F(NetworkStateHandlerTest, UpdateCaptivePortalProvider) {
+  constexpr char kProviderId[] = "TestProviderId";
+  constexpr char kProviderName[] = "TestProviderName";
+
+  // Verify initial state.
+  const NetworkState* wifi1 = network_state_handler_->GetNetworkState(
+      kShillManagerClientStubDefaultWifi);
+  ASSERT_TRUE(wifi1);
+  const NetworkState::CaptivePortalProviderInfo* info =
+      wifi1->captive_portal_provider();
+  EXPECT_EQ(nullptr, info);
+
+  // Verify that setting a captive portal provider applies to existing networks.
+  std::string hex_ssid = wifi1->GetHexSsid();
+  ASSERT_FALSE(hex_ssid.empty());
+  network_state_handler_->SetCaptivePortalProviderForHexSsid(
+      hex_ssid, kProviderId, kProviderName);
+  base::RunLoop().RunUntilIdle();
+
+  info = wifi1->captive_portal_provider();
+  ASSERT_NE(nullptr, info);
+  EXPECT_EQ(kProviderId, info->id);
+  EXPECT_EQ(kProviderName, info->name);
+
+  // Verify that adding a new network sets its captive portal provider.
+  constexpr char kNewSsid[] = "new_wifi";
+  std::string new_hex_ssid = base::HexEncode(kNewSsid, strlen(kNewSsid));
+  network_state_handler_->SetCaptivePortalProviderForHexSsid(
+      new_hex_ssid, kProviderId, kProviderName);
+  AddService("/service/new_wifi", "new_wifi_guid", kNewSsid, shill::kTypeWifi,
+             shill::kStateOnline);
+  base::RunLoop().RunUntilIdle();
+
+  const NetworkState* new_wifi =
+      network_state_handler_->GetNetworkState("/service/new_wifi");
+  ASSERT_TRUE(new_wifi);
+  info = new_wifi->captive_portal_provider();
+  ASSERT_NE(nullptr, info);
+  EXPECT_EQ(kProviderId, info->id);
+  EXPECT_EQ(kProviderName, info->name);
+}
+
 }  // namespace chromeos
diff --git a/chromeos/network/network_state_unittest.cc b/chromeos/network/network_state_unittest.cc
index 6c991e2..05624f6 100644
--- a/chromeos/network/network_state_unittest.cc
+++ b/chromeos/network/network_state_unittest.cc
@@ -212,8 +212,9 @@
                    base::Value("third-party-vpn-provider-extension-id"));
   EXPECT_TRUE(SetProperty(shill::kProviderProperty, std::move(provider)));
   SignalInitialPropertiesReceived();
-  EXPECT_EQ(network_state_.vpn_provider_type(), shill::kProviderThirdPartyVpn);
-  EXPECT_EQ(network_state_.vpn_provider_id(),
+  ASSERT_TRUE(network_state_.vpn_provider());
+  EXPECT_EQ(network_state_.vpn_provider()->type, shill::kProviderThirdPartyVpn);
+  EXPECT_EQ(network_state_.vpn_provider()->id,
             "third-party-vpn-provider-extension-id");
 }
 
@@ -227,8 +228,9 @@
   provider->SetKey(shill::kHostProperty, base::Value("package.name.foo"));
   EXPECT_TRUE(SetProperty(shill::kProviderProperty, std::move(provider)));
   SignalInitialPropertiesReceived();
-  EXPECT_EQ(network_state_.vpn_provider_type(), shill::kProviderArcVpn);
-  EXPECT_EQ(network_state_.vpn_provider_id(), "package.name.foo");
+  ASSERT_TRUE(network_state_.vpn_provider());
+  EXPECT_EQ(network_state_.vpn_provider()->type, shill::kProviderArcVpn);
+  EXPECT_EQ(network_state_.vpn_provider()->id, "package.name.foo");
 }
 
 TEST_F(NetworkStateTest, Visible) {
diff --git a/components/arc/net/arc_net_host_impl.cc b/components/arc/net/arc_net_host_impl.cc
index c7aa02c..aa708cd 100644
--- a/components/arc/net/arc_net_host_impl.cc
+++ b/components/arc/net/arc_net_host_impl.cc
@@ -390,7 +390,7 @@
   const chromeos::NetworkState* default_network =
       GetShillBackedNetwork(GetStateHandler()->DefaultNetwork());
   if (default_network && default_network->type() == shill::kTypeVPN &&
-      default_network->vpn_provider_type() == shill::kProviderArcVpn) {
+      default_network->GetVpnProviderType() == shill::kProviderArcVpn) {
     VLOG(0) << "Disconnecting stale ARC VPN " << default_network->path();
     GetNetworkConnectionHandler()->DisconnectNetwork(
         default_network->path(), base::Bind(&ArcVpnSuccessCallback),
@@ -793,7 +793,7 @@
         GetShillBackedNetwork(state);
     if (!shill_backed_network)
       continue;
-    if (shill_backed_network->vpn_provider_type() == shill::kProviderArcVpn) {
+    if (shill_backed_network->GetVpnProviderType() == shill::kProviderArcVpn) {
       return shill_backed_network->path();
     }
   }
diff --git a/components/autofill/content/renderer/autofill_agent.cc b/components/autofill/content/renderer/autofill_agent.cc
index f6478f5b..55b8e61 100644
--- a/components/autofill/content/renderer/autofill_agent.cc
+++ b/components/autofill/content/renderer/autofill_agent.cc
@@ -414,18 +414,22 @@
 void AutofillAgent::TriggerRefillIfNeeded(const FormData& form) {
   if (!base::FeatureList::IsEnabled(features::kAutofillDynamicForms))
     return;
+
+  ReplaceElementIfNowInvalid(form);
+
   FormFieldData field;
   FormData updated_form;
   if (form_util::FindFormAndFieldForFormControlElement(element_, &updated_form,
                                                        &field) &&
-      !form.DynamicallySameFormAs(updated_form)) {
+      (!element_.IsAutofilled() || !form.DynamicallySameFormAs(updated_form))) {
     base::TimeTicks forms_seen_timestamp = base::TimeTicks::Now();
     WebLocalFrame* frame = render_frame()->GetWebFrame();
     std::vector<FormData> forms;
     forms.push_back(updated_form);
     // Always communicate to browser process for topmost frame.
-    if (!forms.empty() || !frame->Parent())
+    if (!forms.empty() || !frame->Parent()) {
       GetAutofillDriver()->FormsSeen(forms, forms_seen_timestamp);
+    }
   }
 }
 
@@ -1026,11 +1030,62 @@
   submitted_forms_.clear();
 }
 
+bool AutofillAgent::FindTheUniqueNewVersionOfOldElement(
+    WebVector<WebFormControlElement>& elements,
+    bool& element_found,
+    const WebString& original_element_section,
+    const WebFormControlElement& original_element) {
+  for (const WebFormControlElement& current_element : elements) {
+    if (current_element.IsFocusable() &&
+        original_element.NameForAutofill() ==
+            current_element.NameForAutofill()) {
+      if (!element_found) {
+        element_ = current_element;
+        element_found = true;
+      } else if (current_element.AutofillSection() ==
+                     element_.AutofillSection() ||
+                 (current_element.AutofillSection() !=
+                      original_element_section &&
+                  element_.AutofillSection() != original_element_section)) {
+        // If there are two elements that share the same name with the element_,
+        // and the section can't tell them apart, we can't decide between the
+        // two.
+        element_ = original_element;
+        return false;
+      } else if (current_element.AutofillSection() ==
+                 original_element_section) {
+        // If the current element has the right section, update the element_.
+        element_ = current_element;
+      }
+    }
+  }
+  return true;
+}
+
 void AutofillAgent::ReplaceElementIfNowInvalid(const FormData& original_form) {
   // If the document is invalid, bail out.
   if (element_.GetDocument().IsNull())
     return;
 
+  WebVector<WebFormElement> forms;
+  WebVector<WebFormControlElement> elements;
+
+  if (original_form.name.empty()) {
+    // If the form has no name, check all the forms.
+    bool element_found = false;
+    element_.GetDocument().Forms(forms);
+    for (const WebFormElement& form : forms) {
+      form.GetFormControlElements(elements);
+      // If finding a unique element is impossible, return.
+      if (!FindTheUniqueNewVersionOfOldElement(
+              elements, element_found, element_.AutofillSection(), element_))
+        return;
+    }
+    // If the element is not found, we should still check for unowned elements.
+    if (element_found)
+      return;
+  }
+
   if (!element_.Form().IsNull()) {
     // If |element_|'s parent form has no elements, |element_| is now invalid
     // and should be updated.
@@ -1040,29 +1095,32 @@
       return;
   }
 
-  // Try to find the new version of the form.
   WebFormElement form_element;
-  WebVector<WebFormElement> forms;
-  element_.GetDocument().Forms(forms);
-  for (const WebFormElement& form : forms) {
-    if (original_form.name == form.GetName().Utf16() ||
-        original_form.name == form.GetAttribute("id").Utf16()) {
-      form_element = form;
-      break;
+  if (!original_form.name.empty()) {
+    // Try to find the new version of the form.
+    element_.GetDocument().Forms(forms);
+    for (const WebFormElement& form : forms) {
+      if (original_form.name == form.GetName().Utf16() ||
+          original_form.name == form.GetAttribute("id").Utf16()) {
+        form_element = form;
+        break;
+      }
     }
   }
 
-  WebVector<WebFormControlElement> elements;
   if (form_element.IsNull()) {
     // Could not find the new version of the form, get all the unowned elements.
     std::vector<WebElement> fieldsets;
     elements = form_util::GetUnownedAutofillableFormFieldElements(
         element_.GetDocument().All(), &fieldsets);
-  } else {
-    // Get all the elements of the new version of the form.
-    form_element.GetFormControlElements(elements);
+    bool element_found = false;
+    FindTheUniqueNewVersionOfOldElement(elements, element_found,
+                                        element_.AutofillSection(), element_);
+    return;
   }
-
+  // This is the case for owned fields that belong to the right named form.
+  // Get all the elements of the new version of the form.
+  form_element.GetFormControlElements(elements);
   // Try to find the new version of the last interacted element.
   for (const WebFormControlElement& element : elements) {
     if (element_.NameForAutofill() == element.NameForAutofill()) {
diff --git a/components/autofill/content/renderer/autofill_agent.h b/components/autofill/content/renderer/autofill_agent.h
index ba36f73a..4977eace 100644
--- a/components/autofill/content/renderer/autofill_agent.h
+++ b/components/autofill/content/renderer/autofill_agent.h
@@ -29,6 +29,10 @@
 namespace blink {
 class WebNode;
 class WebView;
+class WebString;
+class WebFormControlElement;
+template <typename T>
+class WebVector;
 }
 
 namespace autofill {
@@ -266,6 +270,15 @@
   // cleared in this method.
   void OnFormNoLongerSubmittable();
 
+  // For no name forms, and unowned elements, try to see if there is a unique
+  // element in the updated form that corresponds to the old |element_|.
+  // Returns false if more than one element matches the |element_|.
+  bool FindTheUniqueNewVersionOfOldElement(
+      blink::WebVector<blink::WebFormControlElement>& elements,
+      bool& element_found,
+      const blink::WebString& original_element_section,
+      const blink::WebFormControlElement& original_element);
+
   // Check whether |element_| was removed or replaced dynamically on the page.
   // If so, looks for the same element in the updated |form| and replaces the
   // |element_| with it if it's found.
diff --git a/components/autofill/core/browser/BUILD.gn b/components/autofill/core/browser/BUILD.gn
index 16621e5..1c4a4555 100644
--- a/components/autofill/core/browser/BUILD.gn
+++ b/components/autofill/core/browser/BUILD.gn
@@ -181,6 +181,8 @@
     "webdata/autofill_table_encryptor.h",
     "webdata/autofill_table_encryptor_factory.cc",
     "webdata/autofill_table_encryptor_factory.h",
+    "webdata/autofill_wallet_metadata_sync_bridge.cc",
+    "webdata/autofill_wallet_metadata_sync_bridge.h",
     "webdata/autofill_wallet_metadata_syncable_service.cc",
     "webdata/autofill_wallet_metadata_syncable_service.h",
     "webdata/autofill_wallet_sync_bridge.cc",
diff --git a/components/autofill/core/browser/autofill_manager.cc b/components/autofill/core/browser/autofill_manager.cc
index f423f18..906ef7e 100644
--- a/components/autofill/core/browser/autofill_manager.cc
+++ b/components/autofill/core/browser/autofill_manager.cc
@@ -1965,7 +1965,12 @@
   DCHECK(itr != filling_contexts_map_.end());
   FillingContext* filling_context = itr->second.get();
 
-  DCHECK(!filling_context->attempted_refill);
+  // The refill attempt can happen from different paths, some of which happen
+  // after waiting for a while. Therefore, although this condition has been
+  // checked prior to calling TriggerRefill, it may not hold, when we get here.
+  if (filling_context->attempted_refill)
+    return;
+
   filling_context->attempted_refill = true;
 
   // Try to find the field from which the original field originated.
diff --git a/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge.cc b/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge.cc
new file mode 100644
index 0000000..f836172c
--- /dev/null
+++ b/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge.cc
@@ -0,0 +1,94 @@
+// 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/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge.h"
+
+#include <utility>
+
+#include "base/logging.h"
+#include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
+#include "components/sync/model_impl/client_tag_based_model_type_processor.h"
+
+namespace autofill {
+
+namespace {
+
+// Address to this variable used as the user data key.
+static int kAutofillWalletMetadataSyncBridgeUserDataKey = 0;
+
+}  // namespace
+
+// static
+void AutofillWalletMetadataSyncBridge::CreateForWebDataServiceAndBackend(
+    const std::string& app_locale,
+    AutofillWebDataBackend* web_data_backend,
+    AutofillWebDataService* web_data_service) {
+  web_data_service->GetDBUserData()->SetUserData(
+      &kAutofillWalletMetadataSyncBridgeUserDataKey,
+      std::make_unique<AutofillWalletMetadataSyncBridge>(
+          std::make_unique<syncer::ClientTagBasedModelTypeProcessor>(
+              syncer::AUTOFILL_WALLET_DATA,
+              /*dump_stack=*/base::RepeatingClosure())));
+}
+
+// static
+syncer::ModelTypeSyncBridge*
+AutofillWalletMetadataSyncBridge::FromWebDataService(
+    AutofillWebDataService* web_data_service) {
+  return static_cast<AutofillWalletMetadataSyncBridge*>(
+      web_data_service->GetDBUserData()->GetUserData(
+          &kAutofillWalletMetadataSyncBridgeUserDataKey));
+}
+
+AutofillWalletMetadataSyncBridge::AutofillWalletMetadataSyncBridge(
+    std::unique_ptr<syncer::ModelTypeChangeProcessor> change_processor)
+    : ModelTypeSyncBridge(std::move(change_processor)) {}
+
+AutofillWalletMetadataSyncBridge::~AutofillWalletMetadataSyncBridge() {}
+
+std::unique_ptr<syncer::MetadataChangeList>
+AutofillWalletMetadataSyncBridge::CreateMetadataChangeList() {
+  NOTIMPLEMENTED();
+  return nullptr;
+}
+
+base::Optional<syncer::ModelError>
+AutofillWalletMetadataSyncBridge::MergeSyncData(
+    std::unique_ptr<syncer::MetadataChangeList> metadata_change_list,
+    syncer::EntityChangeList entity_data) {
+  NOTIMPLEMENTED();
+  return base::nullopt;
+}
+
+base::Optional<syncer::ModelError>
+AutofillWalletMetadataSyncBridge::ApplySyncChanges(
+    std::unique_ptr<syncer::MetadataChangeList> metadata_change_list,
+    syncer::EntityChangeList entity_data) {
+  NOTIMPLEMENTED();
+  return base::nullopt;
+}
+
+void AutofillWalletMetadataSyncBridge::GetData(StorageKeyList storage_keys,
+                                               DataCallback callback) {
+  NOTIMPLEMENTED();
+}
+
+void AutofillWalletMetadataSyncBridge::GetAllDataForDebugging(
+    DataCallback callback) {
+  NOTIMPLEMENTED();
+}
+
+std::string AutofillWalletMetadataSyncBridge::GetClientTag(
+    const syncer::EntityData& entity_data) {
+  NOTIMPLEMENTED();
+  return "";
+}
+
+std::string AutofillWalletMetadataSyncBridge::GetStorageKey(
+    const syncer::EntityData& entity_data) {
+  NOTIMPLEMENTED();
+  return "";
+}
+
+}  // namespace autofill
diff --git a/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge.h b/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge.h
new file mode 100644
index 0000000..ed20fba
--- /dev/null
+++ b/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge.h
@@ -0,0 +1,63 @@
+// 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_AUTOFILL_CORE_BROWSER_WEBDATA_AUTOFILL_WALLET_METADATA_SYNC_BRIDGE_H_
+#define COMPONENTS_AUTOFILL_CORE_BROWSER_WEBDATA_AUTOFILL_WALLET_METADATA_SYNC_BRIDGE_H_
+
+#include <memory>
+#include <string>
+
+#include "base/macros.h"
+#include "base/supports_user_data.h"
+#include "components/sync/model/metadata_change_list.h"
+#include "components/sync/model/model_error.h"
+#include "components/sync/model/model_type_change_processor.h"
+#include "components/sync/model/model_type_sync_bridge.h"
+
+namespace autofill {
+
+class AutofillWebDataBackend;
+class AutofillWebDataService;
+
+// Sync bridge responsible for propagating local changes to the processor and
+// applying remote changes to the local database.
+class AutofillWalletMetadataSyncBridge : public base::SupportsUserData::Data,
+                                         public syncer::ModelTypeSyncBridge {
+ public:
+  // Factory method that hides dealing with change_processor and also stores the
+  // created bridge within |web_data_service|. This method should only be
+  // called on |web_data_service|'s DB thread.
+  static void CreateForWebDataServiceAndBackend(
+      const std::string& app_locale,
+      AutofillWebDataBackend* webdata_backend,
+      AutofillWebDataService* web_data_service);
+
+  static syncer::ModelTypeSyncBridge* FromWebDataService(
+      AutofillWebDataService* web_data_service);
+
+  explicit AutofillWalletMetadataSyncBridge(
+      std::unique_ptr<syncer::ModelTypeChangeProcessor> change_processor);
+  ~AutofillWalletMetadataSyncBridge() override;
+
+  // ModelTypeSyncBridge implementation.
+  std::unique_ptr<syncer::MetadataChangeList> CreateMetadataChangeList()
+      override;
+  base::Optional<syncer::ModelError> MergeSyncData(
+      std::unique_ptr<syncer::MetadataChangeList> metadata_change_list,
+      syncer::EntityChangeList entity_data) override;
+  base::Optional<syncer::ModelError> ApplySyncChanges(
+      std::unique_ptr<syncer::MetadataChangeList> metadata_change_list,
+      syncer::EntityChangeList entity_changes) override;
+  void GetData(StorageKeyList storage_keys, DataCallback callback) override;
+  void GetAllDataForDebugging(DataCallback callback) override;
+  std::string GetClientTag(const syncer::EntityData& entity_data) override;
+  std::string GetStorageKey(const syncer::EntityData& entity_data) override;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(AutofillWalletMetadataSyncBridge);
+};
+
+}  // namespace autofill
+
+#endif  // COMPONENTS_AUTOFILL_CORE_BROWSER_WEBDATA_AUTOFILL_WALLET_METADATA_SYNC_BRIDGE_H_
diff --git a/components/autofill_assistant/OWNERS b/components/autofill_assistant/OWNERS
new file mode 100644
index 0000000..483685a
--- /dev/null
+++ b/components/autofill_assistant/OWNERS
@@ -0,0 +1 @@
+gogerald@chromium.org
\ No newline at end of file
diff --git a/components/autofill_assistant/browser/BUILD.gn b/components/autofill_assistant/browser/BUILD.gn
new file mode 100644
index 0000000..40ac937
--- /dev/null
+++ b/components/autofill_assistant/browser/BUILD.gn
@@ -0,0 +1,35 @@
+# Copyright 2018 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//third_party/protobuf/proto_library.gni")
+
+proto_library("proto") {
+  sources = [
+    "assistant.proto",
+  ]
+}
+
+static_library("browser") {
+  sources = [
+    "assistant_controller.cc",
+    "assistant_controller.h",
+    "assistant_protocol_utils.cc",
+    "assistant_protocol_utils.h",
+    "assistant_script.h",
+    "assistant_script_executor.cc",
+    "assistant_script_executor.h",
+    "assistant_script_executor_delegate.h",
+    "assistant_service.cc",
+    "assistant_service.h",
+  ]
+
+  public_deps = [
+    ":proto",
+    "//base",
+    "//components/version_info",
+    "//content/public/browser",
+    "//google_apis",
+    "//net",
+  ]
+}
diff --git a/components/autofill_assistant/browser/DEPS b/components/autofill_assistant/browser/DEPS
new file mode 100644
index 0000000..66a201ce
--- /dev/null
+++ b/components/autofill_assistant/browser/DEPS
@@ -0,0 +1,7 @@
+include_rules = [
+  "+components/version_info/version_info.h",
+  "+content/public/browser",
+  "+google_apis",
+  "+net",
+  "+services/network/public/cpp",
+]
\ No newline at end of file
diff --git a/components/autofill_assistant/browser/assistant.proto b/components/autofill_assistant/browser/assistant.proto
new file mode 100644
index 0000000..71cac77
--- /dev/null
+++ b/components/autofill_assistant/browser/assistant.proto
@@ -0,0 +1,55 @@
+// 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.
+
+syntax = "proto2";
+
+option optimize_for = LITE_RUNTIME;
+
+package autofill_assistant;
+
+// Context contains client environment details. It's used to filter the
+// scripts that can be surfaced to the user.
+message ClientContextProto {
+  required string chrome_version = 1;
+}
+
+// Get the list of scripts that can potentially be run on a url.
+message SupportsScriptRequestProto {
+  required string url = 1;
+  required ClientContextProto client_context = 2;
+}
+
+// Response of the list of supported scripts.
+message SupportsScriptResponseProto {
+  repeated SupportedScriptProto scripts = 1;
+}
+
+// Supported script.
+message SupportedScriptProto {
+  // This is the internal name of the script.
+  required string path = 1;
+
+  message PresentationProto {
+    // Name to use when suggesting this script to users.
+    optional string name = 1;
+  }
+  optional PresentationProto presentation = 2;
+}
+
+enum PolicyType {
+  UNKNOWN_POLICY = 0;
+  SCRIPT = 1;
+  PAGE = 2;
+  VALIDATION = 3;
+  TRACE = 4;
+}
+
+// Initial request to get a script's actions.
+message InitialScriptActionRequestProto {
+  message QueryProto {
+    required string script_path = 1;
+    optional PolicyType policy = 2;
+  }
+  required QueryProto query = 1;
+}
diff --git a/components/autofill_assistant/browser/assistant_controller.cc b/components/autofill_assistant/browser/assistant_controller.cc
new file mode 100644
index 0000000..0398628
--- /dev/null
+++ b/components/autofill_assistant/browser/assistant_controller.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 "components/autofill_assistant/browser/assistant_controller.h"
+
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/web_contents.h"
+
+namespace autofill_assistant {
+// static
+void AssistantController::CreateAndStartForWebContents(
+    content::WebContents* web_contents) {
+  new AssistantController(web_contents);
+}
+
+AssistantService* AssistantController::GetAssistantService() {
+  return assistant_service_.get();
+}
+
+AssistantController::AssistantController(content::WebContents* web_contents)
+    : content::WebContentsObserver(web_contents),
+      assistant_service_(std::make_unique<AssistantService>(
+          web_contents->GetBrowserContext())) {
+  if (!web_contents->IsLoading()) {
+    GetAssistantScripts();
+  }
+}
+
+AssistantController::~AssistantController() {}
+
+void AssistantController::OnGetAssistantScripts(
+    AssistantService::AssistantScripts scripts) {
+  assistant_scripts_ = std::move(scripts);
+}
+
+void AssistantController::DidFinishLoad(
+    content::RenderFrameHost* render_frame_host,
+    const GURL& validated_url) {
+  // TODO(crbug.com/806868): Find a better time to get and update assistant
+  // scripts.
+  GetAssistantScripts();
+}
+
+void AssistantController::WebContentsDestroyed() {
+  delete this;
+}
+
+void AssistantController::GetAssistantScripts() {
+  assistant_service_->GetAssistantScriptsForUrl(
+      web_contents()->GetLastCommittedURL(),
+      base::BindOnce(&AssistantController::OnGetAssistantScripts,
+                     base::Unretained(this)));
+}
+
+}  // namespace autofill_assistant
\ No newline at end of file
diff --git a/components/autofill_assistant/browser/assistant_controller.h b/components/autofill_assistant/browser/assistant_controller.h
new file mode 100644
index 0000000..fa91345
--- /dev/null
+++ b/components/autofill_assistant/browser/assistant_controller.h
@@ -0,0 +1,49 @@
+// 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_AUTOFILL_ASSISTANT_BROWSER_ASSISTANT_CONTROLLER_H_
+#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_ASSISTANT_CONTROLLER_H_
+
+#include "components/autofill_assistant/browser/assistant_script_executor_delegate.h"
+#include "components/autofill_assistant/browser/assistant_service.h"
+#include "content/public/browser/web_contents_observer.h"
+
+namespace content {
+class RenderFrameHost;
+class WebContents;
+}  // namespace content
+
+namespace autofill_assistant {
+// Autofill assistant controller controls autofill assistant action detection,
+// display, execution and so on. The instance of this object self deletes when
+// the web contents is being destroyed.
+class AssistantController : public AssistantScriptExecutorDelegate,
+                            private content::WebContentsObserver {
+ public:
+  static void CreateAndStartForWebContents(content::WebContents* web_contents);
+
+  // Overrides AssistantScriptExecutorDelegate:
+  AssistantService* GetAssistantService() override;
+
+ private:
+  explicit AssistantController(content::WebContents* web_contents);
+  ~AssistantController() override;
+
+  void GetAssistantScripts();
+  void OnGetAssistantScripts(AssistantService::AssistantScripts scripts);
+
+  // Overrides content::WebContentsObserver:
+  void DidFinishLoad(content::RenderFrameHost* render_frame_host,
+                     const GURL& validated_url) override;
+  void WebContentsDestroyed() override;
+
+  std::unique_ptr<AssistantService> assistant_service_;
+  AssistantService::AssistantScripts assistant_scripts_;
+
+  DISALLOW_COPY_AND_ASSIGN(AssistantController);
+};
+
+}  // namespace autofill_assistant
+
+#endif  // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_ASSISTANT_CONTROLLER_H_
\ No newline at end of file
diff --git a/components/autofill_assistant/browser/assistant_protocol_utils.cc b/components/autofill_assistant/browser/assistant_protocol_utils.cc
new file mode 100644
index 0000000..4b777c3
--- /dev/null
+++ b/components/autofill_assistant/browser/assistant_protocol_utils.cc
@@ -0,0 +1,74 @@
+// 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/autofill_assistant/browser/assistant_protocol_utils.h"
+
+#include "base/logging.h"
+#include "components/autofill_assistant/browser/assistant.pb.h"
+#include "components/version_info/version_info.h"
+#include "url/gurl.h"
+
+namespace autofill_assistant {
+
+// static
+std::string AssistantProtocolUtils::CreateGetScriptsRequest(const GURL& url) {
+  DCHECK(!url.is_empty());
+  ClientContextProto context_proto;
+  context_proto.set_chrome_version(
+      version_info::GetProductNameAndVersionForUserAgent());
+
+  SupportsScriptRequestProto script_proto;
+  script_proto.set_url(url.spec());
+  script_proto.set_allocated_client_context(&context_proto);
+
+  std::string serialized_script_proto;
+  bool success = script_proto.SerializeToString(&serialized_script_proto);
+  DCHECK(success);
+  return serialized_script_proto;
+}
+
+// static
+AssistantProtocolUtils::AssistantScripts
+AssistantProtocolUtils::ParseAssistantScripts(const std::string& response) {
+  DCHECK(!response.empty());
+  AssistantScripts scripts;
+
+  SupportsScriptResponseProto response_proto;
+  if (!response_proto.ParseFromString(response)) {
+    LOG(ERROR) << "Failed to parse getting assistant scripts response.";
+    return scripts;
+  }
+
+  for (const auto& script : response_proto.scripts()) {
+    std::string name = "";
+    if (script.has_presentation() && script.presentation().has_name()) {
+      name = script.presentation().name();
+    }
+    auto assistant_script = std::make_unique<AssistantScript>();
+    assistant_script->name = name;
+    assistant_script->path = script.path();
+    scripts[assistant_script.get()] = std::move(assistant_script);
+  }
+
+  return scripts;
+}
+
+// static
+std::string AssistantProtocolUtils::CreateInitialScriptActionRequest(
+    const std::string& script_path) {
+  InitialScriptActionRequestProto::QueryProto query;
+  query.set_script_path(script_path);
+  query.set_policy(PolicyType::SCRIPT);
+
+  InitialScriptActionRequestProto initial_request_proto;
+  initial_request_proto.set_allocated_query(&query);
+
+  std::string serialized_initial_request_proto;
+  bool success = initial_request_proto.SerializeToString(
+      &serialized_initial_request_proto);
+  DCHECK(success);
+  return serialized_initial_request_proto;
+}
+
+}  // namespace autofill_assistant
diff --git a/components/autofill_assistant/browser/assistant_protocol_utils.h b/components/autofill_assistant/browser/assistant_protocol_utils.h
new file mode 100644
index 0000000..391ab89
--- /dev/null
+++ b/components/autofill_assistant/browser/assistant_protocol_utils.h
@@ -0,0 +1,40 @@
+// 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_AUTOFILL_ASSISTANT_BROWSER_ASSISTANT_PROTOCOL_UTILS_H_
+#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_ASSISTANT_PROTOCOL_UTILS_H_
+
+#include "components/autofill_assistant/browser/assistant_script.h"
+
+#include <map>
+#include <string>
+
+class GURL;
+
+namespace autofill_assistant {
+// Autofill assistant protocol related convenient utils.
+class AssistantProtocolUtils {
+ public:
+  // Create getting autofill assistant scripts request for the given
+  // |url|.
+  static std::string CreateGetScriptsRequest(const GURL& url);
+
+  using AssistantScripts =
+      std::map<AssistantScript*, std::unique_ptr<AssistantScript>>;
+  // Parse assistant scripts from the given |response|, which should not be an
+  // empty string.
+  static AssistantScripts ParseAssistantScripts(const std::string& response);
+
+  // Create initial request to get script actions for the given |script_path|.
+  static std::string CreateInitialScriptActionRequest(
+      const std::string& script_path);
+
+ private:
+  // To avoid instantiate this class by accident.
+  AssistantProtocolUtils() = delete;
+  ~AssistantProtocolUtils() = delete;
+};
+}  // namespace autofill_assistant
+
+#endif  // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_ASSISTANT_PROTOCOL_UTILS_H_
\ No newline at end of file
diff --git a/components/autofill_assistant/browser/assistant_script.h b/components/autofill_assistant/browser/assistant_script.h
new file mode 100644
index 0000000..8bee4ba
--- /dev/null
+++ b/components/autofill_assistant/browser/assistant_script.h
@@ -0,0 +1,20 @@
+// 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_AUTOFILL_ASSISTANT_BROWSER_ASSISTANT_SCRIPT_H_
+#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_ASSISTANT_SCRIPT_H_
+
+#include <string>
+
+namespace autofill_assistant {
+
+// Assistant script represents a sequence of client actions.
+struct AssistantScript {
+  std::string name;
+  std::string path;
+};
+
+}  // namespace autofill_assistant
+
+#endif  // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_ASSISTANT_SCRIPT_H_
\ No newline at end of file
diff --git a/components/autofill_assistant/browser/assistant_script_executor.cc b/components/autofill_assistant/browser/assistant_script_executor.cc
new file mode 100644
index 0000000..b4a57ce
--- /dev/null
+++ b/components/autofill_assistant/browser/assistant_script_executor.cc
@@ -0,0 +1,34 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/autofill_assistant/browser/assistant_script_executor.h"
+
+#include "base/bind.h"
+#include "components/autofill_assistant/browser/assistant_service.h"
+
+namespace autofill_assistant {
+AssistantScriptExecutor::AssistantScriptExecutor(
+    AssistantScript* script,
+    AssistantScriptExecutorDelegate* delegate)
+    : script_(script), delegate_(delegate), weak_ptr_factory_(this) {
+  DCHECK(script_);
+  DCHECK(delegate_);
+}
+AssistantScriptExecutor::~AssistantScriptExecutor() {}
+
+void AssistantScriptExecutor::Run(RunScriptCallback callback) {
+  callback_ = std::move(callback);
+  DCHECK(delegate_->GetAssistantService());
+
+  delegate_->GetAssistantService()->GetAssistantActions(
+      script_->path,
+      base::BindOnce(&AssistantScriptExecutor::onGetAssistantActions,
+                     weak_ptr_factory_.GetWeakPtr()));
+}
+
+void AssistantScriptExecutor::onGetAssistantActions(bool result) {
+  NOTIMPLEMENTED();
+}
+
+}  // namespace autofill_assistant
diff --git a/components/autofill_assistant/browser/assistant_script_executor.h b/components/autofill_assistant/browser/assistant_script_executor.h
new file mode 100644
index 0000000..104545b0
--- /dev/null
+++ b/components/autofill_assistant/browser/assistant_script_executor.h
@@ -0,0 +1,39 @@
+// 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_AUTOFILL_ASSISTANT_BROWSER_ASSISTANT_SCRIPT_EXECUTOR_H_
+#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_ASSISTANT_SCRIPT_EXECUTOR_H_
+
+#include "base/callback.h"
+#include "base/memory/weak_ptr.h"
+#include "components/autofill_assistant/browser/assistant_script.h"
+#include "components/autofill_assistant/browser/assistant_script_executor_delegate.h"
+
+namespace autofill_assistant {
+// Class to execute an assistant script.
+class AssistantScriptExecutor {
+ public:
+  // |script| and |delegate| should outlive this object and should not be
+  // nullptr.
+  AssistantScriptExecutor(AssistantScript* script,
+                          AssistantScriptExecutorDelegate* delegate);
+  ~AssistantScriptExecutor();
+
+  using RunScriptCallback = base::OnceCallback<void(bool)>;
+  void Run(RunScriptCallback callback);
+
+ private:
+  void onGetAssistantActions(bool result);
+
+  AssistantScript* script_;
+  AssistantScriptExecutorDelegate* delegate_;
+
+  RunScriptCallback callback_;
+
+  base::WeakPtrFactory<AssistantScriptExecutor> weak_ptr_factory_;
+  DISALLOW_COPY_AND_ASSIGN(AssistantScriptExecutor);
+};
+}  // namespace autofill_assistant
+
+#endif  // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_ASSISTANT_SCRIPT_EXECUTOR_H_
diff --git a/components/autofill_assistant/browser/assistant_script_executor_delegate.h b/components/autofill_assistant/browser/assistant_script_executor_delegate.h
new file mode 100644
index 0000000..49d1b69
--- /dev/null
+++ b/components/autofill_assistant/browser/assistant_script_executor_delegate.h
@@ -0,0 +1,21 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_ASSISTANT_SCRIPT_EXECUTOR_DELEGATE_H_
+#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_ASSISTANT_SCRIPT_EXECUTOR_DELEGATE_H_
+
+namespace autofill_assistant {
+
+class AssistantService;
+
+class AssistantScriptExecutorDelegate {
+ public:
+  virtual AssistantService* GetAssistantService() = 0;
+
+ protected:
+  virtual ~AssistantScriptExecutorDelegate() {}
+};
+}  // namespace autofill_assistant
+
+#endif  // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_ASSISTANT_SCRIPT_EXECUTOR_DELEGATE_H_
diff --git a/components/autofill_assistant/browser/assistant_service.cc b/components/autofill_assistant/browser/assistant_service.cc
new file mode 100644
index 0000000..8e65f21
--- /dev/null
+++ b/components/autofill_assistant/browser/assistant_service.cc
@@ -0,0 +1,166 @@
+// 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/autofill_assistant/browser/assistant_service.h"
+
+#include "base/strings/strcat.h"
+#include "components/autofill_assistant/browser/assistant_protocol_utils.h"
+#include "content/public/browser/browser_context.h"
+#include "content/public/browser/storage_partition.h"
+#include "google_apis/google_api_keys.h"
+#include "net/base/load_flags.h"
+#include "net/http/http_status_code.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
+#include "url/url_canon_stdstring.h"
+
+namespace {
+// TODO(crbug.com/806868): Provide correct server and endpoint.
+const char* const kAutofillAssistantServer = "";
+const char* const kScriptEndpoint = "";
+const char* const kActionEndpoint = "";
+
+net::NetworkTrafficAnnotationTag traffic_annotation =
+    net::DefineNetworkTrafficAnnotation("autofill_assistant_service", R"(
+        semantics {
+          sender: "Autofill Assistant"
+          description:
+            "Chromium posts requests to autofill assistant server to get
+            assistant scripts for a URL."
+          trigger:
+            "A user opens a URL that could be assisted by autofill
+            assistant server."
+          data: "None."
+          destination: GOOGLE_OWNED_SERVICE
+        }
+        policy {
+          cookies_allowed: NO
+          setting:
+            "This feature can be disabled in settings."
+          policy_exception_justification: "Not implemented."
+        })");
+}  // namespace
+
+namespace autofill_assistant {
+
+AssistantService::AssistantService(content::BrowserContext* context)
+    : context_(context) {
+  std::string api_key = google_apis::GetAPIKey();
+
+  url::StringPieceReplacements<std::string> script_replacements;
+  script_replacements.SetPathStr(kScriptEndpoint);
+  script_replacements.SetQueryStr(api_key);
+  assistant_script_server_url_ =
+      GURL(kAutofillAssistantServer).ReplaceComponents(script_replacements);
+
+  url::StringPieceReplacements<std::string> action_replacements;
+  action_replacements.SetPathStr(kActionEndpoint);
+  action_replacements.SetQueryStr(api_key);
+  assistant_script_action_server_url_ =
+      GURL(kAutofillAssistantServer).ReplaceComponents(action_replacements);
+}
+
+AssistantService::~AssistantService() {}
+
+void AssistantService::GetAssistantScriptsForUrl(
+    const GURL& url,
+    GetAssistantScriptsForUrlCallback callback) {
+  DCHECK(url.is_valid());
+
+  std::unique_ptr<AssistantLoader> assistant_loader =
+      std::make_unique<AssistantLoader>();
+  assistant_loader->scripts_callback = std::move(callback);
+  assistant_loader->loader =
+      CreateAndStartLoader(assistant_script_server_url_,
+                           AssistantProtocolUtils::CreateGetScriptsRequest(url),
+                           assistant_loader.get());
+  assistant_loaders_[assistant_loader.get()] = std::move(assistant_loader);
+}
+
+void AssistantService::GetAssistantActions(
+    const std::string& script_path,
+    GetAssistantActionsCallback callback) {
+  DCHECK(!script_path.empty());
+
+  std::unique_ptr<AssistantLoader> assistant_loader =
+      std::make_unique<AssistantLoader>();
+  assistant_loader->actions_callback = std::move(callback);
+  assistant_loader->loader = CreateAndStartLoader(
+      assistant_script_action_server_url_,
+      AssistantProtocolUtils::CreateInitialScriptActionRequest(script_path),
+      assistant_loader.get());
+  assistant_loaders_[assistant_loader.get()] = std::move(assistant_loader);
+}
+
+AssistantService::AssistantLoader::AssistantLoader() {}
+AssistantService::AssistantLoader::~AssistantLoader() {}
+
+std::unique_ptr<network::SimpleURLLoader>
+AssistantService::CreateAndStartLoader(const GURL& server_url,
+                                       const std::string& request,
+                                       AssistantLoader* loader) {
+  auto resource_request = std::make_unique<network::ResourceRequest>();
+  resource_request->url = server_url;
+  resource_request->method = "POST";
+  resource_request->fetch_redirect_mode =
+      network::mojom::FetchRedirectMode::kError;
+  resource_request->load_flags =
+      net::LOAD_DO_NOT_SEND_COOKIES | net::LOAD_DO_NOT_SAVE_COOKIES;
+  std::unique_ptr<network::SimpleURLLoader> simple_loader =
+      network::SimpleURLLoader::Create(std::move(resource_request),
+                                       traffic_annotation);
+  simple_loader->AttachStringForUpload(request, "application/x-protobuffer");
+  simple_loader->DownloadToStringOfUnboundedSizeUntilCrashAndDie(
+      content::BrowserContext::GetDefaultStoragePartition(context_)
+          ->GetURLLoaderFactoryForBrowserProcess()
+          .get(),
+      base::BindOnce(&AssistantService::OnURLLoaderComplete,
+                     base::Unretained(this), loader));
+  return simple_loader;
+}
+
+void AssistantService::OnURLLoaderComplete(
+    AssistantLoader* loader,
+    std::unique_ptr<std::string> response_body) {
+  auto loader_it = assistant_loaders_.find(loader);
+  DCHECK(loader_it != assistant_loaders_.end());
+  std::unique_ptr<AssistantLoader> assistant_loader =
+      std::move(loader_it->second);
+  assistant_loaders_.erase(loader_it);
+  DCHECK(assistant_loader);
+
+  int response_code = 0;
+  if (assistant_loader->loader->ResponseInfo() &&
+      assistant_loader->loader->ResponseInfo()->headers) {
+    response_code =
+        assistant_loader->loader->ResponseInfo()->headers->response_code();
+  }
+  if (assistant_loader->loader->NetError() != net::OK || response_code != 200) {
+    LOG(ERROR) << "Communicating with autofill assistant server error NetError="
+               << assistant_loader->loader->NetError()
+               << " response_code=" << response_code;
+
+    DCHECK(assistant_loader->scripts_callback ||
+           assistant_loader->actions_callback);
+    if (assistant_loader->scripts_callback)
+      std::move(assistant_loader->scripts_callback).Run(AssistantScripts());
+    else if (assistant_loader->actions_callback)
+      std::move(assistant_loader->actions_callback).Run(false);
+    return;
+  }
+
+  std::string response_body_str;
+  if (response_body)
+    response_body_str = std::move(*response_body);
+  DCHECK(assistant_loader->scripts_callback ||
+         assistant_loader->actions_callback);
+  if (assistant_loader->scripts_callback) {
+    std::move(assistant_loader->scripts_callback)
+        .Run(AssistantProtocolUtils::ParseAssistantScripts(response_body_str));
+  } else if (assistant_loader->actions_callback) {
+    // TODO(crbug.com/806868): Parse assistant actions.
+    std::move(assistant_loader->actions_callback).Run(false);
+  }
+}
+
+}  // namespace autofill_assistant
diff --git a/components/autofill_assistant/browser/assistant_service.h b/components/autofill_assistant/browser/assistant_service.h
new file mode 100644
index 0000000..637cbb6
--- /dev/null
+++ b/components/autofill_assistant/browser/assistant_service.h
@@ -0,0 +1,72 @@
+// 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_AUTOFILL_ASSISTANT_BROWSER_ASSISTANT_SERVICE_H_
+#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_ASSISTANT_SERVICE_H_
+
+#include <map>
+#include <memory>
+
+#include "base/callback.h"
+#include "components/autofill_assistant/browser/assistant_script.h"
+#include "services/network/public/cpp/simple_url_loader.h"
+#include "url/gurl.h"
+
+namespace content {
+class BrowserContext;
+}
+
+namespace autofill_assistant {
+// Autofill assistant service to communicate with the server to get scripts and
+// client actions.
+class AssistantService {
+ public:
+  AssistantService(content::BrowserContext* context);
+  ~AssistantService();
+
+  // Get assistant scripts for a given |url|, which should be a valid URL.
+  using AssistantScripts =
+      std::map<AssistantScript*, std::unique_ptr<AssistantScript>>;
+  using GetAssistantScriptsForUrlCallback =
+      base::OnceCallback<void(AssistantScripts)>;
+  void GetAssistantScriptsForUrl(const GURL& url,
+                                 GetAssistantScriptsForUrlCallback callback);
+
+  // Get assistant actions.
+  using GetAssistantActionsCallback = base::OnceCallback<void(bool)>;
+  void GetAssistantActions(const std::string& script_path,
+                           GetAssistantActionsCallback callback);
+
+ private:
+  // Struct to store assistant scripts and actions request.
+  struct AssistantLoader {
+    AssistantLoader();
+    ~AssistantLoader();
+
+    // One of the |scripts_callback| and |actions_callback| must be nullptr;
+    GetAssistantScriptsForUrlCallback scripts_callback;
+    GetAssistantActionsCallback actions_callback;
+    std::unique_ptr<network::SimpleURLLoader> loader;
+  };
+  std::unique_ptr<network::SimpleURLLoader> CreateAndStartLoader(
+      const GURL& server_url,
+      const std::string& request,
+      AssistantLoader* loader);
+  void OnURLLoaderComplete(AssistantLoader* loader,
+                           std::unique_ptr<std::string> response_body);
+
+  content::BrowserContext* context_;
+  GURL assistant_script_server_url_;
+  GURL assistant_script_action_server_url_;
+
+  // Destroying this object will cancel ongoing requests.
+  std::map<AssistantLoader*, std::unique_ptr<AssistantLoader>>
+      assistant_loaders_;
+
+  DISALLOW_COPY_AND_ASSIGN(AssistantService);
+};
+
+}  // namespace autofill_assistant
+
+#endif  // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_ASSISTANT_SERVICE_H_
diff --git a/components/browser_sync/profile_sync_components_factory_impl.cc b/components/browser_sync/profile_sync_components_factory_impl.cc
index 713f268..3f87705 100644
--- a/components/browser_sync/profile_sync_components_factory_impl.cc
+++ b/components/browser_sync/profile_sync_components_factory_impl.cc
@@ -14,6 +14,7 @@
 #include "components/autofill/core/browser/webdata/autocomplete_sync_bridge.h"
 #include "components/autofill/core/browser/webdata/autofill_profile_data_type_controller.h"
 #include "components/autofill/core/browser/webdata/autofill_profile_sync_bridge.h"
+#include "components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge.h"
 #include "components/autofill/core/browser/webdata/autofill_wallet_sync_bridge.h"
 #include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
 #include "components/autofill/core/browser/webdata/web_data_model_type_controller.h"
@@ -69,7 +70,7 @@
   // TODO(jkrcal): Deal with the (probably rare) race condition when we call
   // bridges' FromWebDataService() before calling
   // CreateForWebDataServiceAndBackend() in WebDataServiceWrapper. This TODO
-  // also applies to the second function below and to analogous code in
+  // also applies to all analogous functions below and to analogous code in
   // SyncClient::GetControllerDelegateForModelType().
   return autofill::AutocompleteSyncBridge::FromWebDataService(service)
       ->change_processor()
@@ -84,6 +85,22 @@
       ->GetControllerDelegateOnUIThread();
 }
 
+base::WeakPtr<syncer::ModelTypeControllerDelegate>
+AutofillWalletDelegateFromDataService(
+    autofill::AutofillWebDataService* service) {
+  return autofill::AutofillWalletSyncBridge::FromWebDataService(service)
+      ->change_processor()
+      ->GetControllerDelegateOnUIThread();
+}
+
+base::WeakPtr<syncer::ModelTypeControllerDelegate>
+AutofillWalletMetadataDelegateFromDataService(
+    autofill::AutofillWebDataService* service) {
+  return autofill::AutofillWalletMetadataSyncBridge::FromWebDataService(service)
+      ->change_processor()
+      ->GetControllerDelegateOnUIThread();
+}
+
 }  // namespace
 
 ProfileSyncComponentsFactoryImpl::ProfileSyncComponentsFactoryImpl(
@@ -157,7 +174,7 @@
             std::make_unique<autofill::WebDataModelTypeController>(
                 syncer::AUTOFILL_WALLET_DATA, sync_client_, db_thread_,
                 web_data_service_,
-                base::BindRepeating(&AutofillProfileDelegateFromDataService)));
+                base::BindRepeating(&AutofillWalletDelegateFromDataService)));
       } else {
         controllers.push_back(
             std::make_unique<AutofillWalletDataTypeController>(
@@ -170,9 +187,20 @@
     // is syncing and metadata sync is not explicitly disabled.
     if (!wallet_disabled &&
         !disabled_types.Has(syncer::AUTOFILL_WALLET_METADATA)) {
-      controllers.push_back(std::make_unique<AutofillWalletDataTypeController>(
-          syncer::AUTOFILL_WALLET_METADATA, db_thread_, error_callback,
-          sync_client_, web_data_service_));
+      if (base::FeatureList::IsEnabled(
+              switches::kSyncUSSAutofillWalletMetadata)) {
+        controllers.push_back(
+            std::make_unique<autofill::WebDataModelTypeController>(
+                syncer::AUTOFILL_WALLET_METADATA, sync_client_, db_thread_,
+                web_data_service_,
+                base::BindRepeating(
+                    &AutofillWalletMetadataDelegateFromDataService)));
+      } else {
+        controllers.push_back(
+            std::make_unique<AutofillWalletDataTypeController>(
+                syncer::AUTOFILL_WALLET_METADATA, db_thread_, error_callback,
+                sync_client_, web_data_service_));
+      }
     }
   }
 
diff --git a/components/crash/android/BUILD.gn b/components/crash/android/BUILD.gn
index 425e96dc..97b8d2b4 100644
--- a/components/crash/android/BUILD.gn
+++ b/components/crash/android/BUILD.gn
@@ -5,7 +5,8 @@
 import("//build/config/android/rules.gni")
 
 _jni_sources =
-    [ "java/src/org/chromium/components/crash/browser/CrashDumpManager.java" ]
+    [ "java/src/org/chromium/components/crash/browser/ChildProcessCrashObserver.java",
+      "java/src/org/chromium/components/crash/browser/CrashDumpManager.java" ]
 
 generate_jni("jni_headers") {
   sources = _jni_sources
diff --git a/components/crash/android/java/src/org/chromium/components/crash/browser/ChildProcessCrashObserver.java b/components/crash/android/java/src/org/chromium/components/crash/browser/ChildProcessCrashObserver.java
new file mode 100644
index 0000000..a9f6a23
--- /dev/null
+++ b/components/crash/android/java/src/org/chromium/components/crash/browser/ChildProcessCrashObserver.java
@@ -0,0 +1,59 @@
+// 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.components.crash.browser;
+
+import org.chromium.base.Log;
+import org.chromium.base.ThreadUtils;
+import org.chromium.base.annotations.CalledByNative;
+
+/**
+ * A Java-side bridge for notifying an observer when a child process has crashed.
+ *
+ * Crashpad writes a minidump for a child process in the time between the child receives a crash
+ * signal and when it exits. After the child process exits, Crashpad should have completed writing
+ * a minidump to its CrashReportDatabase and this class's childCrashed() is called, executing any
+ * registered callback.
+ *
+ * It is expected that the callback will be used to handle the newly created dump by, e.g. attaching
+ * a logcat and scheduling it for upload.
+ */
+public class ChildProcessCrashObserver {
+    private static final String TAG = "ChildCrashObserver";
+
+    /**
+     * An interface for registering a callback to be executed when a child process crashes.
+     */
+    public interface ChildCrashedCallback { public void childCrashed(int pid); }
+
+    /**
+     * The globally registered callback for responding to child process crashes, or null if no
+     * callback has been registered yet.
+     */
+    private static ChildCrashedCallback sCallback;
+
+    /**
+     * Registers a callback for responding to child process crashes. May be called at most once, and
+     * only on the UI thread.
+     *
+     * @param callback The callback to trigger when a child process has exited due to a crash.
+     */
+    public static void registerCrashCallback(ChildCrashedCallback callback) {
+        ThreadUtils.assertOnUiThread();
+        assert sCallback == null;
+        sCallback = callback;
+    }
+
+    /**
+     * Notifies any registered observer that a child process has exited due to an apparent crash.
+     */
+    @CalledByNative
+    public static void childCrashed(int pid) {
+        if (sCallback == null) {
+            Log.w(TAG, "Ignoring crash observed before a callback was registered...");
+            return;
+        }
+        sCallback.childCrashed(pid);
+    }
+}
diff --git a/components/crash/content/browser/crash_dump_manager_android_unittest.cc b/components/crash/content/browser/crash_dump_manager_android_unittest.cc
index 83fd396..d378372 100644
--- a/components/crash/content/browser/crash_dump_manager_android_unittest.cc
+++ b/components/crash/content/browser/crash_dump_manager_android_unittest.cc
@@ -129,34 +129,6 @@
                                 base::Unretained(test_harness_)));
 }
 
-TEST_F(CrashDumpManagerTest, NoDumpCreated) {
-  base::HistogramTester histogram_tester;
-  CrashDumpManager* manager = CrashDumpManager::GetInstance();
-
-  CrashMetricsReporterObserver observer;
-  crash_reporter::CrashMetricsReporter::GetInstance()->AddObserver(&observer);
-
-  crash_reporter::ChildExitObserver::TerminationInfo termination_info;
-  termination_info.process_host_id = 1;
-  termination_info.pid = base::kNullProcessHandle;
-  termination_info.process_type = content::PROCESS_TYPE_RENDERER;
-  termination_info.app_state =
-      base::android::APPLICATION_STATE_HAS_RUNNING_ACTIVITIES;
-  termination_info.normal_termination = false;
-  termination_info.binding_state = base::android::ChildBindingState::STRONG;
-  termination_info.was_killed_intentionally_by_browser = false;
-  termination_info.was_oom_protected_status = true;
-  base::PostTaskWithTraits(
-      FROM_HERE, {base::MayBlock(), base::TaskPriority::BACKGROUND},
-      base::BindOnce(&CrashDumpManager::ProcessMinidumpFileFromChild,
-                     base::Unretained(manager), base::FilePath(),
-                     termination_info));
-  observer.WaitForProcessed();
-
-  histogram_tester.ExpectTotalCount("Tab.RendererDetailedExitStatus", 0);
-  EXPECT_EQ(0, dumps_uploaded_);
-}
-
 TEST_F(CrashDumpManagerTest, NonOomCrash) {
   base::HistogramTester histogram_tester;
 
diff --git a/components/crash/content/browser/crash_metrics_reporter_android.cc b/components/crash/content/browser/crash_metrics_reporter_android.cc
index 3c2babb..8b8e741 100644
--- a/components/crash/content/browser/crash_metrics_reporter_android.cc
+++ b/components/crash/content/browser/crash_metrics_reporter_android.cc
@@ -112,10 +112,9 @@
     const ChildExitObserver::TerminationInfo& info,
     breakpad::CrashDumpManager::CrashDumpStatus status) {
   ReportedCrashTypeSet reported_counts;
-  if (status == breakpad::CrashDumpManager::CrashDumpStatus::kMissingDump) {
-    NotifyObservers(info.process_host_id, reported_counts);
+  // Avoid duplicating processing for the same process.
+  if (status == breakpad::CrashDumpManager::CrashDumpStatus::kMissingDump)
     return;
-  }
 
   bool has_valid_dump = false;
   switch (status) {
diff --git a/components/cronet/android/java/src/org/chromium/net/urlconnection/MessageLoop.java b/components/cronet/android/java/src/org/chromium/net/urlconnection/MessageLoop.java
index 9e1f79f..d624417 100644
--- a/components/cronet/android/java/src/org/chromium/net/urlconnection/MessageLoop.java
+++ b/components/cronet/android/java/src/org/chromium/net/urlconnection/MessageLoop.java
@@ -27,6 +27,12 @@
     // this might cause the loop to terminate immediately if there is a quit
     // task enqueued.
     private boolean mLoopFailed = false;
+    // The exception that caused mLoopFailed to be set to true. Will be
+    // rethrown if loop() is called again. If mLoopFailed is set then
+    // exactly one of mPriorInterruptedIOException and mPriorRuntimeException
+    // will be set.
+    private InterruptedIOException mPriorInterruptedIOException;
+    private RuntimeException mPriorRuntimeException;
 
     // Used when assertions are enabled to enforce single-threaded use.
     private static final long INVALID_THREAD_ID = -1;
@@ -96,8 +102,11 @@
         long startNano = System.nanoTime();
         long timeoutNano = TimeUnit.NANOSECONDS.convert(timeoutMilli, TimeUnit.MILLISECONDS);
         if (mLoopFailed) {
-            throw new IllegalStateException(
-                    "Cannot run loop as an exception has occurred previously.");
+            if (mPriorInterruptedIOException != null) {
+                throw mPriorInterruptedIOException;
+            } else {
+                throw mPriorRuntimeException;
+            }
         }
         if (mLoopRunning) {
             throw new IllegalStateException(
@@ -111,9 +120,15 @@
                 } else {
                     take(true, timeoutNano - System.nanoTime() + startNano).run();
                 }
-            } catch (InterruptedIOException | RuntimeException e) {
+            } catch (InterruptedIOException e) {
                 mLoopRunning = false;
                 mLoopFailed = true;
+                mPriorInterruptedIOException = e;
+                throw e;
+            } catch (RuntimeException e) {
+                mLoopRunning = false;
+                mLoopFailed = true;
+                mPriorRuntimeException = e;
                 throw e;
             }
         }
diff --git a/components/cronet/android/test/javatests/src/org/chromium/net/urlconnection/CronetHttpURLConnectionTest.java b/components/cronet/android/test/javatests/src/org/chromium/net/urlconnection/CronetHttpURLConnectionTest.java
index d5d98e2..597ba9e 100644
--- a/components/cronet/android/test/javatests/src/org/chromium/net/urlconnection/CronetHttpURLConnectionTest.java
+++ b/components/cronet/android/test/javatests/src/org/chromium/net/urlconnection/CronetHttpURLConnectionTest.java
@@ -38,6 +38,7 @@
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.InputStream;
+import java.io.InterruptedIOException;
 import java.io.OutputStream;
 import java.lang.reflect.Method;
 import java.net.HttpURLConnection;
@@ -1402,4 +1403,70 @@
         urlConnection.disconnect();
         assertTrue(CronetTestUtil.nativeGetTaggedBytes(tag) > priorBytes);
     }
+
+    @Test
+    @SmallTest
+    @Feature({"Cronet"})
+    @CompareDefaultWithCronet
+    public void testIOExceptionErrorRethrown() throws Exception {
+        // URL that should fail to connect.
+        URL url = new URL("http://localhost");
+        HttpURLConnection connection = (HttpURLConnection) url.openConnection();
+        // This should not throw, even though internally it may encounter an exception.
+        connection.getHeaderField("blah");
+        try {
+            // This should throw an IOException.
+            connection.getResponseCode();
+            fail();
+        } catch (IOException e) {
+            // Expected
+        }
+        connection.disconnect();
+    }
+
+    @Test
+    @SmallTest
+    @Feature({"Cronet"})
+    @CompareDefaultWithCronet
+    public void testIOExceptionInterruptRethrown() throws Exception {
+        // Older system impls don't reliably respond to interrupt.
+        if (mTestRule.testingSystemHttpURLConnection()
+                && Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
+            return;
+        }
+        ServerSocket hangingServer = new ServerSocket(0);
+        URL url = new URL("http://localhost:" + hangingServer.getLocalPort());
+        final HttpURLConnection connection = (HttpURLConnection) url.openConnection();
+        // connect() is non-blocking.
+        connection.connect();
+        FutureTask<IOException> task = new FutureTask<IOException>(new Callable<IOException>() {
+            @Override
+            public IOException call() {
+                // This should not throw, even though internally it may encounter an exception.
+                connection.getHeaderField("blah");
+                try {
+                    // This should throw an InterruptedIOException.
+                    connection.getResponseCode();
+                } catch (InterruptedIOException e) {
+                    // Expected
+                    return e;
+                } catch (IOException e) {
+                    return null;
+                }
+                return null;
+            }
+        });
+        Thread t = new Thread(task);
+        t.start();
+        Socket s = hangingServer.accept();
+        hangingServer.close();
+        // This will trigger an InterruptException in getHeaderField() and getResponseCode().
+        // getHeaderField() should not re-throw it.  getResponseCode() should re-throw it as an
+        // InterruptedIOException.
+        t.interrupt();
+        // Make sure an IOException is thrown.
+        assertNotNull(task.get());
+        s.close();
+        connection.disconnect();
+    }
 }
diff --git a/components/cronet/android/test/javatests/src/org/chromium/net/urlconnection/MessageLoopTest.java b/components/cronet/android/test/javatests/src/org/chromium/net/urlconnection/MessageLoopTest.java
index 8d1938b..0678fe8a 100644
--- a/components/cronet/android/test/javatests/src/org/chromium/net/urlconnection/MessageLoopTest.java
+++ b/components/cronet/android/test/javatests/src/org/chromium/net/urlconnection/MessageLoopTest.java
@@ -19,6 +19,7 @@
 import org.chromium.net.CronetTestRule;
 
 import java.io.IOException;
+import java.io.InterruptedIOException;
 import java.net.SocketTimeoutException;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
@@ -78,7 +79,7 @@
                     loop.loop();
                     fail();
                 } catch (Exception e) {
-                    if (!(e instanceof IllegalStateException)) {
+                    if (!(e instanceof InterruptedIOException)) {
                         fail();
                     }
                 }
@@ -127,7 +128,7 @@
                     loop.loop();
                     fail();
                 } catch (Exception e) {
-                    if (!(e instanceof IllegalStateException)) {
+                    if (!(e instanceof NullPointerException)) {
                         fail();
                     }
                 }
diff --git a/components/history_strings.grdp b/components/history_strings.grdp
index a46b1cd8..463ebd9 100644
--- a/components/history_strings.grdp
+++ b/components/history_strings.grdp
@@ -51,7 +51,7 @@
     No search results found
   </message>
   <if expr="not use_titlecase">
-  <message name="IDS_HISTORY_OPEN_CLEAR_BROWSING_DATA_DIALOG" desc="Title of the button that will open the clear browsing data dialog.">
+  <message name="IDS_HISTORY_OPEN_CLEAR_BROWSING_DATA_DIALOG" desc="Title of the button that will open the clear browsing data dialog [Length: 16em].">
     Clear browsing data...
   </message>
   </if>
diff --git a/components/invalidation/impl/per_user_topic_registration_manager_unittest.cc b/components/invalidation/impl/per_user_topic_registration_manager_unittest.cc
index 15cd48d..265c1d76 100644
--- a/components/invalidation/impl/per_user_topic_registration_manager_unittest.cc
+++ b/components/invalidation/impl/per_user_topic_registration_manager_unittest.cc
@@ -137,7 +137,7 @@
 
   std::string response_body = R"(
     {
-      "private_topic_name": "test-pr"
+      "privateTopicName": "test-pr"
     }
   )";
 
diff --git a/components/invalidation/impl/per_user_topic_registration_request.cc b/components/invalidation/impl/per_user_topic_registration_request.cc
index a9eef18..353818a 100644
--- a/components/invalidation/impl/per_user_topic_registration_request.cc
+++ b/components/invalidation/impl/per_user_topic_registration_request.cc
@@ -17,7 +17,7 @@
 
 namespace {
 
-const char kPrivateTopicNameKey[] = "private_topic_name";
+const char kPrivateTopicNameKey[] = "privateTopicName";
 
 base::Value* GetPrivateTopicName(base::Value* value) {
   if (!value || !value->is_dict()) {
diff --git a/components/invalidation/impl/per_user_topic_registration_request_unittest.cc b/components/invalidation/impl/per_user_topic_registration_request_unittest.cc
index 03b3316a..6c452fb 100644
--- a/components/invalidation/impl/per_user_topic_registration_request_unittest.cc
+++ b/components/invalidation/impl/per_user_topic_registration_request_unittest.cc
@@ -124,7 +124,7 @@
           .Build();
   std::string response_body = R"(
     {
-      "private_topic_name": "test-pr"
+      "privateTopicName": "test-pr"
     }
   )";
 
@@ -166,7 +166,7 @@
           .Build();
   std::string response_body = R"(
     {
-      "private_topic_name": "test-pr"
+      "privateTopicName": "test-pr"
     }
   )";
 
diff --git a/components/safe_browsing/browser/threat_details.cc b/components/safe_browsing/browser/threat_details.cc
index eeda739..5a5dee7 100644
--- a/components/safe_browsing/browser/threat_details.cc
+++ b/components/safe_browsing/browser/threat_details.cc
@@ -271,7 +271,7 @@
 // don't leak it.
 class ThreatDetailsFactoryImpl : public ThreatDetailsFactory {
  public:
-  ThreatDetails* CreateThreatDetails(
+  scoped_refptr<ThreatDetails> CreateThreatDetails(
       BaseUIManager* ui_manager,
       WebContents* web_contents,
       const security_interstitials::UnsafeResource& unsafe_resource,
@@ -280,10 +280,12 @@
       ReferrerChainProvider* referrer_chain_provider,
       bool trim_to_ad_tags,
       ThreatDetailsDoneCallback done_callback) override {
-    return new ThreatDetails(ui_manager, web_contents, unsafe_resource,
-                             url_loader_factory, history_service,
-                             referrer_chain_provider, trim_to_ad_tags,
-                             done_callback);
+    auto threat_details = base::WrapRefCounted(new ThreatDetails(
+        ui_manager, web_contents, unsafe_resource, url_loader_factory,
+        history_service, referrer_chain_provider, trim_to_ad_tags,
+        done_callback));
+    threat_details->StartCollection();
+    return threat_details;
   }
 
  private:
@@ -299,7 +301,7 @@
 
 // Create a ThreatDetails for the given tab.
 /* static */
-ThreatDetails* ThreatDetails::NewThreatDetails(
+scoped_refptr<ThreatDetails> ThreatDetails::NewThreatDetails(
     BaseUIManager* ui_manager,
     WebContents* web_contents,
     const UnsafeResource& resource,
@@ -344,7 +346,6 @@
   redirects_collector_ = new ThreatDetailsRedirectsCollector(
       history_service ? history_service->AsWeakPtr()
                       : base::WeakPtr<history::HistoryService>());
-  StartCollection();
 }
 
 // TODO(lpz): Consider making this constructor delegate to the parameterized one
diff --git a/components/safe_browsing/browser/threat_details.h b/components/safe_browsing/browser/threat_details.h
index acea93c2..61db996 100644
--- a/components/safe_browsing/browser/threat_details.h
+++ b/components/safe_browsing/browser/threat_details.h
@@ -73,7 +73,7 @@
   typedef security_interstitials::UnsafeResource UnsafeResource;
 
   // Constructs a new ThreatDetails instance, using the factory.
-  static ThreatDetails* NewThreatDetails(
+  static scoped_refptr<ThreatDetails> NewThreatDetails(
       BaseUIManager* ui_manager,
       content::WebContents* web_contents,
       const UnsafeResource& resource,
@@ -107,6 +107,7 @@
  protected:
   friend class ThreatDetailsFactoryImpl;
   friend class TestThreatDetailsFactory;
+  friend class ThreatDetailsTest;
 
   ThreatDetails(
       BaseUIManager* ui_manager,
@@ -133,12 +134,12 @@
   // Used to get a pointer to the HTTP cache.
   scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_;
 
- private:
-  friend class base::RefCounted<ThreatDetails>;
-
   // Starts the collection of the report.
   void StartCollection();
 
+ private:
+  friend class base::RefCounted<ThreatDetails>;
+
   // Whether the url is "public" so we can add it to the report.
   bool IsReportableUrl(const GURL& url) const;
 
@@ -286,7 +287,7 @@
  public:
   virtual ~ThreatDetailsFactory() {}
 
-  virtual ThreatDetails* CreateThreatDetails(
+  virtual scoped_refptr<ThreatDetails> CreateThreatDetails(
       BaseUIManager* ui_manager,
       content::WebContents* web_contents,
       const security_interstitials::UnsafeResource& unsafe_resource,
diff --git a/components/safe_browsing/triggers/trigger_manager_unittest.cc b/components/safe_browsing/triggers/trigger_manager_unittest.cc
index f3f5a725..dc4017c8 100644
--- a/components/safe_browsing/triggers/trigger_manager_unittest.cc
+++ b/components/safe_browsing/triggers/trigger_manager_unittest.cc
@@ -40,7 +40,7 @@
  public:
   ~MockThreatDetailsFactory() override {}
 
-  ThreatDetails* CreateThreatDetails(
+  scoped_refptr<ThreatDetails> CreateThreatDetails(
       BaseUIManager* ui_manager,
       content::WebContents* web_contents,
       const security_interstitials::UnsafeResource& unsafe_resource,
@@ -49,8 +49,7 @@
       ReferrerChainProvider* referrer_chain_provider,
       bool trim_to_ad_tags,
       ThreatDetailsDoneCallback done_callback) override {
-    MockThreatDetails* threat_details = new MockThreatDetails();
-    return threat_details;
+    return base::MakeRefCounted<MockThreatDetails>();
   }
 };
 
diff --git a/components/sync/driver/sync_driver_switches.cc b/components/sync/driver/sync_driver_switches.cc
index 697cd0f..3e7e59f 100644
--- a/components/sync/driver/sync_driver_switches.cc
+++ b/components/sync/driver/sync_driver_switches.cc
@@ -78,4 +78,8 @@
 const base::Feature kSyncUSSAutofillWalletData{
     "SyncUSSAutofillWalletData", base::FEATURE_DISABLED_BY_DEFAULT};
 
+// Enable USS implementation of autofill wallet metadata datatype.
+const base::Feature kSyncUSSAutofillWalletMetadata{
+    "SyncUSSAutofillWalletMetadata", base::FEATURE_DISABLED_BY_DEFAULT};
+
 }  // namespace switches
diff --git a/components/sync/driver/sync_driver_switches.h b/components/sync/driver/sync_driver_switches.h
index b01df2b2..93a6d36 100644
--- a/components/sync/driver/sync_driver_switches.h
+++ b/components/sync/driver/sync_driver_switches.h
@@ -30,6 +30,7 @@
 extern const base::Feature kSyncUSSSessions;
 extern const base::Feature kSyncUSSAutofillProfile;
 extern const base::Feature kSyncUSSAutofillWalletData;
+extern const base::Feature kSyncUSSAutofillWalletMetadata;
 
 }  // namespace switches
 
diff --git a/components/viz/common/gpu/context_cache_controller.cc b/components/viz/common/gpu/context_cache_controller.cc
index c3a48f5..d49abb7 100644
--- a/components/viz/common/gpu/context_cache_controller.cc
+++ b/components/viz/common/gpu/context_cache_controller.cc
@@ -159,11 +159,8 @@
     return;
   }
 
-  if (gr_context_) {
-    // Avoid the more complete GrContext::freeGpuResources, as that evicts
-    // harder to re-generate Skia caches.
-    gr_context_->purgeUnlockedResources(false /* scratchResourcesOnly */);
-  }
+  if (gr_context_)
+    gr_context_->freeGpuResources();
 
   // Toggle SetAggressivelyFreeResources to drop command buffer data.
   context_support_->SetAggressivelyFreeResources(true);
diff --git a/components/webdata_services/web_data_service_wrapper.cc b/components/webdata_services/web_data_service_wrapper.cc
index 0287a89..b663e2e5 100644
--- a/components/webdata_services/web_data_service_wrapper.cc
+++ b/components/webdata_services/web_data_service_wrapper.cc
@@ -17,6 +17,7 @@
 #include "components/autofill/core/browser/webdata/autofill_profile_sync_bridge.h"
 #include "components/autofill/core/browser/webdata/autofill_profile_syncable_service.h"
 #include "components/autofill/core/browser/webdata/autofill_table.h"
+#include "components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge.h"
 #include "components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service.h"
 #include "components/autofill/core/browser/webdata/autofill_wallet_sync_bridge.h"
 #include "components/autofill/core/browser/webdata/autofill_wallet_syncable_service.h"
@@ -95,9 +96,15 @@
         ->InjectStartSyncFlare(sync_flare);
   }
 
-  autofill::AutofillWalletMetadataSyncableService::
-      CreateForWebDataServiceAndBackend(autofill_web_data.get(),
-                                        autofill_backend, app_locale);
+  if (base::FeatureList::IsEnabled(switches::kSyncUSSAutofillWalletMetadata)) {
+    autofill::AutofillWalletMetadataSyncBridge::
+        CreateForWebDataServiceAndBackend(app_locale, autofill_backend,
+                                          autofill_web_data.get());
+  } else {
+    autofill::AutofillWalletMetadataSyncableService::
+        CreateForWebDataServiceAndBackend(autofill_web_data.get(),
+                                          autofill_backend, app_locale);
+  }
 }
 
 }  // namespace
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn
index 4b67636b..43e712c 100644
--- a/content/browser/BUILD.gn
+++ b/content/browser/BUILD.gn
@@ -444,6 +444,8 @@
     "background_fetch/storage/get_initialization_data_task.h",
     "background_fetch/storage/get_metadata_task.cc",
     "background_fetch/storage/get_metadata_task.h",
+    "background_fetch/storage/get_registration_task.cc",
+    "background_fetch/storage/get_registration_task.h",
     "background_fetch/storage/get_settled_fetches_task.cc",
     "background_fetch/storage/get_settled_fetches_task.h",
     "background_fetch/storage/image_helpers.cc",
diff --git a/content/browser/background_fetch/background_fetch_context.cc b/content/browser/background_fetch/background_fetch_context.cc
index 4aaa80c..cc2c5f0 100644
--- a/content/browser/background_fetch/background_fetch_context.cc
+++ b/content/browser/background_fetch/background_fetch_context.cc
@@ -73,11 +73,9 @@
   }
 
   for (auto& data : initialization_data) {
-    CreateController(data.registration_id, data.options, data.icon,
-                     data.ui_title, data.num_completed_requests,
-                     data.num_requests, data.active_fetch_guids,
-                     std::make_unique<BackgroundFetchRegistration>(
-                         std::move(data.registration)));
+    CreateController(data.registration_id, data.registration, data.options,
+                     data.icon, data.ui_title, data.num_completed_requests,
+                     data.num_requests, data.active_fetch_guids);
   }
 }
 
@@ -105,7 +103,7 @@
 void BackgroundFetchContext::DidGetRegistration(
     blink::mojom::BackgroundFetchService::GetRegistrationCallback callback,
     blink::mojom::BackgroundFetchError error,
-    std::unique_ptr<BackgroundFetchRegistration> registration) {
+    const BackgroundFetchRegistration& registration) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
 
   if (error != blink::mojom::BackgroundFetchError::NONE) {
@@ -114,13 +112,15 @@
     return;
   }
 
-  DCHECK(registration);
+  BackgroundFetchRegistration updated_registration(registration);
+
   // The data manager only has the number of bytes from completed downloads, so
   // augment this with the number of downloaded bytes from in-progress jobs.
-  DCHECK(job_controllers_.count(registration->unique_id));
-  registration->downloaded +=
-      job_controllers_[registration->unique_id]->GetInProgressDownloadedBytes();
-  std::move(callback).Run(error, *registration.get());
+  DCHECK(job_controllers_.count(registration.unique_id));
+  updated_registration.downloaded +=
+      job_controllers_[registration.unique_id]->GetInProgressDownloadedBytes();
+
+  std::move(callback).Run(error, updated_registration);
 }
 
 void BackgroundFetchContext::StartFetch(
@@ -141,8 +141,7 @@
   data_manager_->CreateRegistration(
       registration_id, requests, options, icon,
       base::BindOnce(&BackgroundFetchContext::DidCreateRegistration,
-                     weak_factory_.GetWeakPtr(), registration_id, options, icon,
-                     requests.size()));
+                     weak_factory_.GetWeakPtr(), registration_id));
 }
 
 void BackgroundFetchContext::GetIconDisplaySize(
@@ -154,35 +153,25 @@
 
 void BackgroundFetchContext::DidCreateRegistration(
     const BackgroundFetchRegistrationId& registration_id,
-    const BackgroundFetchOptions& options,
-    const SkBitmap& icon,
-    size_t num_requests,
     blink::mojom::BackgroundFetchError error,
-    std::unique_ptr<BackgroundFetchRegistration> registration) {
+    const BackgroundFetchRegistration& registration) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
 
   background_fetch::RecordRegistrationCreatedError(error);
-  if (error != blink::mojom::BackgroundFetchError::NONE) {
-    DCHECK(fetch_callbacks_.count(registration_id));
-    std::move(fetch_callbacks_[registration_id])
-        .Run(error, base::nullopt /* BackgroundFetchRegistration */);
-    fetch_callbacks_.erase(registration_id);
+
+  auto iter = fetch_callbacks_.find(registration_id);
+
+  // The fetch might have been abandoned already if the Service Worker was
+  // unregistered or corrupted while registration was in progress.
+  if (iter == fetch_callbacks_.end())
     return;
-  }
 
-  if (hang_registration_creation_for_testing_) {
-    // Hang here, to allow time for testing races. For instance, this helps us
-    // test the behavior when a service worker gets unregistered before the
-    // controller can be created.
-    return;
-  }
+  if (error == blink::mojom::BackgroundFetchError::NONE)
+    std::move(iter->second).Run(error, registration);
+  else
+    std::move(iter->second).Run(error, base::nullopt /* registration */);
 
-  DCHECK(registration);
-
-  // Create the BackgroundFetchJobController to do the actual fetching.
-  CreateController(registration_id, options, icon, options.title,
-                   0u /* num_completed_requests */, num_requests,
-                   {} /* outstanding_guids */, std::move(registration));
+  fetch_callbacks_.erase(registration_id);
 }
 
 void BackgroundFetchContext::AddRegistrationObserver(
@@ -250,6 +239,29 @@
   }
 }
 
+void BackgroundFetchContext::OnRegistrationCreated(
+    const BackgroundFetchRegistrationId& registration_id,
+    const BackgroundFetchRegistration& registration,
+    const BackgroundFetchOptions& options,
+    const SkBitmap& icon,
+    int num_requests) {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+  if (hang_registration_creation_for_testing_) {
+    // Hang here, to allow time for testing races. For instance, this helps us
+    // test the behavior when a service worker gets unregistered before the
+    // controller can be created.
+    return;
+  }
+
+  // TODO(peter): When this moves to the BackgroundFetchScheduler, only create
+  // a controller when the background fetch can actually be started.
+
+  CreateController(registration_id, registration, options, icon, options.title,
+                   0u /* num_completed_requests */, num_requests,
+                   {} /* outstanding_guids */);
+}
+
 void BackgroundFetchContext::OnUpdatedUI(
     const BackgroundFetchRegistrationId& registration_id,
     const std::string& title) {
@@ -274,18 +286,18 @@
 
 void BackgroundFetchContext::CreateController(
     const BackgroundFetchRegistrationId& registration_id,
+    const BackgroundFetchRegistration& registration,
     const BackgroundFetchOptions& options,
     const SkBitmap& icon,
     const std::string& ui_title,
     size_t num_completed_requests,
     size_t num_requests,
-    const std::vector<std::string>& outstanding_guids,
-    std::unique_ptr<BackgroundFetchRegistration> registration) {
+    const std::vector<std::string>& outstanding_guids) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
 
   auto controller = std::make_unique<BackgroundFetchJobController>(
-      &delegate_proxy_, registration_id, options, icon,
-      registration->downloaded, scheduler_.get(),
+      &delegate_proxy_, registration_id, options, icon, registration.downloaded,
+      scheduler_.get(),
       // Safe because JobControllers are destroyed before RegistrationNotifier.
       base::BindRepeating(&BackgroundFetchRegistrationNotifier::Notify,
                           base::Unretained(registration_notifier_.get())),
@@ -297,13 +309,6 @@
                                       outstanding_guids, ui_title);
   scheduler_->AddJobController(controller.get());
   job_controllers_.emplace(registration_id.unique_id(), std::move(controller));
-
-  auto fetch_callback_iter = fetch_callbacks_.find(registration_id);
-  if (fetch_callback_iter != fetch_callbacks_.end()) {
-    std::move(fetch_callback_iter->second)
-        .Run(blink::mojom::BackgroundFetchError::NONE, *registration);
-    fetch_callbacks_.erase(fetch_callback_iter);
-  }
 }
 
 void BackgroundFetchContext::Abort(
diff --git a/content/browser/background_fetch/background_fetch_context.h b/content/browser/background_fetch/background_fetch_context.h
index a6b05e1..f2ec5e3 100644
--- a/content/browser/background_fetch/background_fetch_context.h
+++ b/content/browser/background_fetch/background_fetch_context.h
@@ -114,6 +114,12 @@
       blink::mojom::BackgroundFetchService::UpdateUICallback callback);
 
   // BackgroundFetchDataManagerObserver implementation.
+  void OnRegistrationCreated(
+      const BackgroundFetchRegistrationId& registration_id,
+      const BackgroundFetchRegistration& registration,
+      const BackgroundFetchOptions& options,
+      const SkBitmap& icon,
+      int num_requests) override;
   void OnUpdatedUI(const BackgroundFetchRegistrationId& registration_id,
                    const std::string& title) override;
   void OnServiceWorkerDatabaseCorrupted(
@@ -125,6 +131,8 @@
   void OnStorageWiped() override;
 
  private:
+  FRIEND_TEST_ALL_PREFIXES(BackgroundFetchServiceTest,
+                           JobsInitializedOnBrowserRestart);
   friend class BackgroundFetchServiceTest;
   friend class BackgroundFetchJobControllerTest;
   friend class base::DeleteHelper<BackgroundFetchContext>;
@@ -138,31 +146,27 @@
 
   // Creates a new Job Controller for the given |registration_id| and |options|,
   // which will start fetching the files that are part of the registration.
-  void CreateController(
-      const BackgroundFetchRegistrationId& registration_id,
-      const BackgroundFetchOptions& options,
-      const SkBitmap& icon,
-      const std::string& ui_title,
-      size_t num_completed_requests,
-      size_t num_requests,
-      const std::vector<std::string>& outstanding_guids,
-      std::unique_ptr<BackgroundFetchRegistration> registration);
+  void CreateController(const BackgroundFetchRegistrationId& registration_id,
+                        const BackgroundFetchRegistration& registration,
+                        const BackgroundFetchOptions& options,
+                        const SkBitmap& icon,
+                        const std::string& ui_title,
+                        size_t num_completed_requests,
+                        size_t num_requests,
+                        const std::vector<std::string>& outstanding_guids);
 
   // Called when an existing registration has been retrieved from the data
   // manager. If the registration does not exist then |registration| is nullptr.
   void DidGetRegistration(
       blink::mojom::BackgroundFetchService::GetRegistrationCallback callback,
       blink::mojom::BackgroundFetchError error,
-      std::unique_ptr<BackgroundFetchRegistration> registration);
+      const BackgroundFetchRegistration& registration);
 
   // Called when a new registration has been created by the data manager.
   void DidCreateRegistration(
       const BackgroundFetchRegistrationId& registration_id,
-      const BackgroundFetchOptions& options,
-      const SkBitmap& icon,
-      size_t num_requests,
       blink::mojom::BackgroundFetchError error,
-      std::unique_ptr<BackgroundFetchRegistration> registration);
+      const BackgroundFetchRegistration& registration);
 
   // Called by a JobController when it finishes processing. Also used to
   // implement |Abort|.
diff --git a/content/browser/background_fetch/background_fetch_data_manager.cc b/content/browser/background_fetch/background_fetch_data_manager.cc
index 97fa8390..b2b3d9e4 100644
--- a/content/browser/background_fetch/background_fetch_data_manager.cc
+++ b/content/browser/background_fetch/background_fetch_data_manager.cc
@@ -18,6 +18,7 @@
 #include "content/browser/background_fetch/storage/delete_registration_task.h"
 #include "content/browser/background_fetch/storage/get_developer_ids_task.h"
 #include "content/browser/background_fetch/storage/get_metadata_task.h"
+#include "content/browser/background_fetch/storage/get_registration_task.h"
 #include "content/browser/background_fetch/storage/get_settled_fetches_task.h"
 #include "content/browser/background_fetch/storage/mark_registration_for_deletion_task.h"
 #include "content/browser/background_fetch/storage/mark_request_complete_task.h"
@@ -32,34 +33,6 @@
 
 namespace content {
 
-namespace {
-
-// Helper function to convert a BackgroundFetchRegistration proto into a
-// BackgroundFetchRegistration struct, and call the appropriate callback.
-void GetRegistrationFromMetadata(
-    BackgroundFetchDataManager::GetRegistrationCallback callback,
-    blink::mojom::BackgroundFetchError error,
-    std::unique_ptr<proto::BackgroundFetchMetadata> metadata_proto) {
-  if (!metadata_proto) {
-    std::move(callback).Run(error, nullptr);
-    return;
-  }
-
-  const auto& registration_proto = metadata_proto->registration();
-  auto registration = std::make_unique<BackgroundFetchRegistration>();
-  registration->developer_id = registration_proto.developer_id();
-  registration->unique_id = registration_proto.unique_id();
-  // TODO(crbug.com/774054): Uploads are not yet supported.
-  registration->upload_total = registration_proto.upload_total();
-  registration->uploaded = registration_proto.uploaded();
-  registration->download_total = registration_proto.download_total();
-  registration->downloaded = registration_proto.downloaded();
-
-  std::move(callback).Run(error, std::move(registration));
-}
-
-}  // namespace
-
 BackgroundFetchDataManager::BackgroundFetchDataManager(
     BrowserContext* browser_context,
     scoped_refptr<ServiceWorkerContextWrapper> service_worker_context,
@@ -125,23 +98,8 @@
     GetRegistrationCallback callback) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
 
-  auto registration_callback =
-      base::BindOnce(&GetRegistrationFromMetadata, std::move(callback));
   AddDatabaseTask(std::make_unique<background_fetch::CreateMetadataTask>(
-      this, registration_id, requests, options, icon,
-      std::move(registration_callback)));
-}
-
-void BackgroundFetchDataManager::GetMetadata(
-    int64_t service_worker_registration_id,
-    const url::Origin& origin,
-    const std::string& developer_id,
-    GetMetadataCallback callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
-
-  AddDatabaseTask(std::make_unique<background_fetch::GetMetadataTask>(
-      this, service_worker_registration_id, origin, developer_id,
-      std::move(callback)));
+      this, registration_id, requests, options, icon, std::move(callback)));
 }
 
 void BackgroundFetchDataManager::GetRegistration(
@@ -151,10 +109,9 @@
     GetRegistrationCallback callback) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
 
-  auto registration_callback =
-      base::BindOnce(&GetRegistrationFromMetadata, std::move(callback));
-  GetMetadata(service_worker_registration_id, origin, developer_id,
-              std::move(registration_callback));
+  AddDatabaseTask(std::make_unique<background_fetch::GetRegistrationTask>(
+      this, service_worker_registration_id, origin, developer_id,
+      std::move(callback)));
 }
 
 void BackgroundFetchDataManager::UpdateRegistrationUI(
@@ -174,31 +131,29 @@
 
   auto start_next_request = base::BindOnce(
       &BackgroundFetchDataManager::AddStartNextPendingRequestTask,
-      weak_ptr_factory_.GetWeakPtr(),
-      registration_id.service_worker_registration_id(), std::move(callback));
+      weak_ptr_factory_.GetWeakPtr(), registration_id, std::move(callback));
 
   // Get the associated metadata, and add a StartNextPendingRequestTask.
-  GetMetadata(registration_id.service_worker_registration_id(),
-              registration_id.origin(), registration_id.developer_id(),
-              std::move(start_next_request));
+  AddDatabaseTask(std::make_unique<background_fetch::GetRegistrationTask>(
+      this, registration_id.service_worker_registration_id(),
+      registration_id.origin(), registration_id.developer_id(),
+      std::move(start_next_request)));
 }
 
 void BackgroundFetchDataManager::AddStartNextPendingRequestTask(
-    int64_t service_worker_registration_id,
+    const BackgroundFetchRegistrationId& registration_id,
     NextRequestCallback callback,
     blink::mojom::BackgroundFetchError error,
-    std::unique_ptr<proto::BackgroundFetchMetadata> metadata) {
-  if (!metadata) {
+    const BackgroundFetchRegistration& registration) {
+  if (error != blink::mojom::BackgroundFetchError::NONE) {
     // Stop giving out requests as registration aborted (or otherwise finished).
     std::move(callback).Run(nullptr /* request */);
     return;
   }
-  DCHECK_EQ(error, blink::mojom::BackgroundFetchError::NONE);
 
   AddDatabaseTask(
       std::make_unique<background_fetch::StartNextPendingRequestTask>(
-          this, service_worker_registration_id, std::move(metadata),
-          std::move(callback)));
+          this, registration_id, registration, std::move(callback)));
 }
 
 void BackgroundFetchDataManager::MarkRequestAsComplete(
diff --git a/content/browser/background_fetch/background_fetch_data_manager.h b/content/browser/background_fetch/background_fetch_data_manager.h
index fd6d233d..6dd5b81 100644
--- a/content/browser/background_fetch/background_fetch_data_manager.h
+++ b/content/browser/background_fetch/background_fetch_data_manager.h
@@ -66,12 +66,9 @@
       bool /* background_fetch_succeeded */,
       std::vector<BackgroundFetchSettledFetch>,
       std::vector<std::unique_ptr<storage::BlobDataHandle>>)>;
-  using GetMetadataCallback =
-      base::OnceCallback<void(blink::mojom::BackgroundFetchError,
-                              std::unique_ptr<proto::BackgroundFetchMetadata>)>;
   using GetRegistrationCallback =
       base::OnceCallback<void(blink::mojom::BackgroundFetchError,
-                              std::unique_ptr<BackgroundFetchRegistration>)>;
+                              const BackgroundFetchRegistration&)>;
   using NextRequestCallback =
       base::OnceCallback<void(scoped_refptr<BackgroundFetchRequestInfo>)>;
   using NumRequestsCallback = base::OnceCallback<void(size_t)>;
@@ -105,12 +102,6 @@
       const SkBitmap& icon,
       GetRegistrationCallback callback);
 
-  // Get the BackgroundFetchMetadata.
-  void GetMetadata(int64_t service_worker_registration_id,
-                   const url::Origin& origin,
-                   const std::string& developer_id,
-                   GetMetadataCallback callback);
-
   // Get the BackgroundFetchRegistration.
   void GetRegistration(int64_t service_worker_registration_id,
                        const url::Origin& origin,
@@ -196,10 +187,10 @@
   }
 
   void AddStartNextPendingRequestTask(
-      int64_t service_worker_registration_id,
+      const BackgroundFetchRegistrationId& registration_id,
       NextRequestCallback callback,
       blink::mojom::BackgroundFetchError error,
-      std::unique_ptr<proto::BackgroundFetchMetadata> metadata);
+      const BackgroundFetchRegistration& registration);
 
   void AddDatabaseTask(std::unique_ptr<background_fetch::DatabaseTask> task);
 
diff --git a/content/browser/background_fetch/background_fetch_data_manager_observer.h b/content/browser/background_fetch/background_fetch_data_manager_observer.h
index 12981a8..1436f40b 100644
--- a/content/browser/background_fetch/background_fetch_data_manager_observer.h
+++ b/content/browser/background_fetch/background_fetch_data_manager_observer.h
@@ -5,8 +5,14 @@
 #ifndef CONTENT_BROWSER_BACKGROUND_FETCH_BACKGROUND_FETCH_DATA_MANAGER_OBSERVER_H_
 #define CONTENT_BROWSER_BACKGROUND_FETCH_BACKGROUND_FETCH_DATA_MANAGER_OBSERVER_H_
 
+#include <memory>
+
+class SkBitmap;
+
 namespace content {
 
+struct BackgroundFetchOptions;
+struct BackgroundFetchRegistration;
 class BackgroundFetchRegistrationId;
 
 // Observer interface for objects that would like to be notified about changes
@@ -14,6 +20,14 @@
 // will be invoked on the IO thread.
 class BackgroundFetchDataManagerObserver {
  public:
+  // Called when the Background Fetch |registration| has been created.
+  virtual void OnRegistrationCreated(
+      const BackgroundFetchRegistrationId& registration_id,
+      const BackgroundFetchRegistration& registration,
+      const BackgroundFetchOptions& options,
+      const SkBitmap& icon,
+      int num_requests) = 0;
+
   // Called when the |title| for the Background Fetch |registration_id| has been
   // updated in the data store.
   virtual void OnUpdatedUI(const BackgroundFetchRegistrationId& registration_id,
diff --git a/content/browser/background_fetch/background_fetch_data_manager_unittest.cc b/content/browser/background_fetch/background_fetch_data_manager_unittest.cc
index ced59107..9ac1b3e 100644
--- a/content/browser/background_fetch/background_fetch_data_manager_unittest.cc
+++ b/content/browser/background_fetch/background_fetch_data_manager_unittest.cc
@@ -38,6 +38,7 @@
 namespace {
 
 using background_fetch::BackgroundFetchInitializationData;
+using ::testing::_;
 using ::testing::UnorderedElementsAre;
 using ::testing::IsEmpty;
 
@@ -63,16 +64,15 @@
   std::move(quit_closure).Run();
 }
 
-void DidCreateRegistration(
-    base::Closure quit_closure,
-    blink::mojom::BackgroundFetchError* out_error,
-    blink::mojom::BackgroundFetchError error,
-    std::unique_ptr<BackgroundFetchRegistration> registration) {
+void DidCreateRegistration(base::OnceClosure quit_closure,
+                           blink::mojom::BackgroundFetchError* out_error,
+                           blink::mojom::BackgroundFetchError error,
+                           const BackgroundFetchRegistration& registration) {
   *out_error = error;
   std::move(quit_closure).Run();
 }
 
-void DidGetError(base::Closure quit_closure,
+void DidGetError(base::OnceClosure quit_closure,
                  blink::mojom::BackgroundFetchError* out_error,
                  blink::mojom::BackgroundFetchError error) {
   *out_error = error;
@@ -207,14 +207,14 @@
     run_loop.Run();
   }
 
-  std::unique_ptr<BackgroundFetchRegistration> GetRegistration(
+  BackgroundFetchRegistration GetRegistration(
       int64_t service_worker_registration_id,
       const url::Origin& origin,
       const std::string developer_id,
       blink::mojom::BackgroundFetchError* out_error) {
     DCHECK(out_error);
 
-    std::unique_ptr<BackgroundFetchRegistration> registration;
+    BackgroundFetchRegistration registration;
     base::RunLoop run_loop;
     background_fetch_data_manager_->GetRegistration(
         service_worker_registration_id, origin, developer_id,
@@ -228,18 +228,16 @@
 
   std::unique_ptr<proto::BackgroundFetchMetadata> GetMetadata(
       int64_t service_worker_registration_id,
-      const url::Origin& origin,
-      const std::string developer_id,
-      blink::mojom::BackgroundFetchError* out_error) {
-    DCHECK(out_error);
-
+      const std::string& unique_id) {
     std::unique_ptr<proto::BackgroundFetchMetadata> metadata;
+
     base::RunLoop run_loop;
-    background_fetch_data_manager_->GetMetadata(
-        service_worker_registration_id, origin, developer_id,
+    embedded_worker_test_helper()->context_wrapper()->GetRegistrationUserData(
+        service_worker_registration_id,
+        {background_fetch::RegistrationKey(unique_id)},
         base::BindOnce(&BackgroundFetchDataManagerTest::DidGetMetadata,
                        base::Unretained(this), run_loop.QuitClosure(),
-                       out_error, &metadata));
+                       &metadata));
     run_loop.Run();
 
     return metadata;
@@ -464,6 +462,12 @@
   }
 
   // BackgroundFetchDataManagerObserver mocks:
+  MOCK_METHOD5(OnRegistrationCreated,
+               void(const BackgroundFetchRegistrationId& registration_id,
+                    const BackgroundFetchRegistration& registration,
+                    const BackgroundFetchOptions& options,
+                    const SkBitmap& icon,
+                    int num_requests));
   MOCK_METHOD2(OnUpdatedUI,
                void(const BackgroundFetchRegistrationId& registration,
                     const std::string& title));
@@ -471,32 +475,29 @@
                void(int64_t service_worker_registration_id));
 
  protected:
-  void DidGetRegistration(
-      base::Closure quit_closure,
-      blink::mojom::BackgroundFetchError* out_error,
-      std::unique_ptr<BackgroundFetchRegistration>* out_registration,
-      blink::mojom::BackgroundFetchError error,
-      std::unique_ptr<BackgroundFetchRegistration> registration) {
-    if (error == blink::mojom::BackgroundFetchError::NONE) {
-      DCHECK(registration);
-    }
+  void DidGetRegistration(base::OnceClosure quit_closure,
+                          blink::mojom::BackgroundFetchError* out_error,
+                          BackgroundFetchRegistration* out_registration,
+                          blink::mojom::BackgroundFetchError error,
+                          const BackgroundFetchRegistration& registration) {
     *out_error = error;
-    *out_registration = std::move(registration);
+    *out_registration = registration;
 
     std::move(quit_closure).Run();
   }
 
   void DidGetMetadata(
       base::OnceClosure quit_closure,
-      blink::mojom::BackgroundFetchError* out_error,
       std::unique_ptr<proto::BackgroundFetchMetadata>* out_metadata,
-      blink::mojom::BackgroundFetchError error,
-      std::unique_ptr<proto::BackgroundFetchMetadata> metadata) {
-    if (error == blink::mojom::BackgroundFetchError::NONE) {
-      DCHECK(metadata);
+      const std::vector<std::string>& data,
+      blink::ServiceWorkerStatusCode status) {
+    if (status == blink::ServiceWorkerStatusCode::kOk) {
+      DCHECK_EQ(data.size(), 1u);
+
+      auto metadata = std::make_unique<proto::BackgroundFetchMetadata>();
+      if (metadata->ParseFromString(data[0]))
+        *out_metadata = std::move(metadata);
     }
-    *out_error = error;
-    *out_metadata = std::move(metadata);
 
     std::move(quit_closure).Run();
   }
@@ -596,8 +597,12 @@
   EXPECT_EQ(error, blink::mojom::BackgroundFetchError::INVALID_ID);
 
   // Creating the initial registration should succeed.
-  CreateRegistration(registration_id1, requests, options, SkBitmap(), &error);
-  EXPECT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
+  {
+    EXPECT_CALL(*this, OnRegistrationCreated(registration_id1, _, _, _, _));
+
+    CreateRegistration(registration_id1, requests, options, SkBitmap(), &error);
+    ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
+  }
 
   // Different |unique_id|, since this is a new Background Fetch registration,
   // even though it shares the same |developer_id|.
@@ -621,8 +626,12 @@
   // And now registering the second registration should work fine, since there
   // is no longer an *active* registration with the same |developer_id|, even
   // though the initial registration has not yet been deleted.
-  CreateRegistration(registration_id2, requests, options, SkBitmap(), &error);
-  EXPECT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
+  {
+    EXPECT_CALL(*this, OnRegistrationCreated(registration_id2, _, _, _, _));
+
+    CreateRegistration(registration_id2, requests, options, SkBitmap(), &error);
+    ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
+  }
 }
 
 TEST_F(BackgroundFetchDataManagerTest, GetDeveloperIds) {
@@ -641,8 +650,12 @@
   // Create a single registration.
   BackgroundFetchRegistrationId registration_id1(
       sw_id, origin(), kExampleDeveloperId, kExampleUniqueId);
-  CreateRegistration(registration_id1, requests, options, SkBitmap(), &error);
-  EXPECT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
+  {
+    EXPECT_CALL(*this, OnRegistrationCreated(registration_id1, _, _, _, _));
+
+    CreateRegistration(registration_id1, requests, options, SkBitmap(), &error);
+    ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
+  }
 
   // Verify that the developer ID can be found.
   developer_ids = GetDeveloperIds(sw_id, origin(), &error);
@@ -659,9 +672,12 @@
   // Create another registration.
   BackgroundFetchRegistrationId registration_id2(
       sw_id, origin(), kAlternativeDeveloperId, kAlternativeUniqueId);
-  CreateRegistration(registration_id2, requests, options, SkBitmap(), &error);
-  EXPECT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
+  {
+    EXPECT_CALL(*this, OnRegistrationCreated(registration_id2, _, _, _, _));
 
+    CreateRegistration(registration_id2, requests, options, SkBitmap(), &error);
+    ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
+  }
   // Verify that both developer IDs can be found.
   developer_ids = GetDeveloperIds(sw_id, origin(), &error);
   EXPECT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
@@ -688,31 +704,34 @@
   blink::mojom::BackgroundFetchError error;
 
   // Create a single registration.
-  CreateRegistration(registration_id, requests, options, SkBitmap(), &error);
-  EXPECT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
+  {
+    EXPECT_CALL(*this, OnRegistrationCreated(registration_id, _, _, _, _));
+
+    CreateRegistration(registration_id, requests, options, SkBitmap(), &error);
+    ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
+  }
 
   // Verify that the registration can be retrieved.
   auto registration =
       GetRegistration(sw_id, origin(), kExampleDeveloperId, &error);
   ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
-  ASSERT_TRUE(registration);
-  EXPECT_EQ(kExampleUniqueId, registration->unique_id);
-  EXPECT_EQ(kExampleDeveloperId, registration->developer_id);
+
+  EXPECT_EQ(kExampleUniqueId, registration.unique_id);
+  EXPECT_EQ(kExampleDeveloperId, registration.developer_id);
 
   // Verify that retrieving using the wrong developer id doesn't work.
   registration =
       GetRegistration(sw_id, origin(), kAlternativeDeveloperId, &error);
   ASSERT_EQ(error, blink::mojom::BackgroundFetchError::INVALID_ID);
-  ASSERT_FALSE(registration);
 
   RestartDataManagerFromPersistentStorage();
 
   // After a restart, GetRegistration should still find the registration.
   registration = GetRegistration(sw_id, origin(), kExampleDeveloperId, &error);
   ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
-  ASSERT_TRUE(registration);
-  EXPECT_EQ(kExampleUniqueId, registration->unique_id);
-  EXPECT_EQ(kExampleDeveloperId, registration->developer_id);
+
+  EXPECT_EQ(kExampleUniqueId, registration.unique_id);
+  EXPECT_EQ(kExampleDeveloperId, registration.developer_id);
 }
 
 TEST_F(BackgroundFetchDataManagerTest, GetMetadata) {
@@ -727,27 +746,23 @@
   blink::mojom::BackgroundFetchError error;
 
   // Create a single registration.
-  CreateRegistration(registration_id, requests, options, SkBitmap(), &error);
-  EXPECT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
+  {
+    EXPECT_CALL(*this, OnRegistrationCreated(registration_id, _, _, _, _));
 
+    CreateRegistration(registration_id, requests, options, SkBitmap(), &error);
+    ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
+  }
   // Verify that the metadata can be retrieved.
-  auto metadata = GetMetadata(sw_id, origin(), kExampleDeveloperId, &error);
-  ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
+  auto metadata = GetMetadata(sw_id, kExampleUniqueId);
   ASSERT_TRUE(metadata);
   EXPECT_EQ(metadata->origin(), origin().Serialize());
   EXPECT_NE(metadata->creation_microseconds_since_unix_epoch(), 0);
   EXPECT_EQ(metadata->num_fetches(), static_cast<int>(requests.size()));
 
-  // Verify that retrieving using the wrong developer id doesn't work.
-  metadata = GetMetadata(sw_id, origin(), kAlternativeDeveloperId, &error);
-  ASSERT_EQ(error, blink::mojom::BackgroundFetchError::INVALID_ID);
-  ASSERT_FALSE(metadata);
-
   RestartDataManagerFromPersistentStorage();
 
   // After a restart, GetMetadata should still find the registration.
-  metadata = GetMetadata(sw_id, origin(), kExampleDeveloperId, &error);
-  ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
+  metadata = GetMetadata(sw_id, kExampleUniqueId);
   ASSERT_TRUE(metadata);
   EXPECT_EQ(metadata->origin(), origin().Serialize());
   EXPECT_NE(metadata->creation_microseconds_since_unix_epoch(), 0);
@@ -770,12 +785,15 @@
   icon.eraseColor(SK_ColorGREEN);
 
   // Create a single registration.
-  CreateRegistration(registration_id, requests, options, icon, &error);
-  EXPECT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
+  {
+    EXPECT_CALL(*this, OnRegistrationCreated(registration_id, _, _, _, _));
+
+    CreateRegistration(registration_id, requests, options, icon, &error);
+    ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
+  }
 
   // Verify that the metadata can be retrieved.
-  auto metadata = GetMetadata(sw_id, origin(), kExampleDeveloperId, &error);
-  ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
+  auto metadata = GetMetadata(sw_id, kExampleUniqueId);
   ASSERT_TRUE(metadata);
   EXPECT_EQ(metadata->origin(), origin().Serialize());
   EXPECT_NE(metadata->creation_microseconds_since_unix_epoch(), 0);
@@ -799,8 +817,12 @@
   EXPECT_TRUE(GetUIOptions(sw_id).title().empty());
 
   // Create a single registration.
-  CreateRegistration(registration_id, requests, options, SkBitmap(), &error);
-  EXPECT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
+  {
+    EXPECT_CALL(*this, OnRegistrationCreated(registration_id, _, _, _, _));
+
+    CreateRegistration(registration_id, requests, options, SkBitmap(), &error);
+    ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
+  }
 
   // Verify that the title can be retrieved.
   ASSERT_EQ(GetUIOptions(sw_id).title(), kInitialTitle);
@@ -830,8 +852,12 @@
   BackgroundFetchOptions options;
   blink::mojom::BackgroundFetchError error;
 
-  CreateRegistration(registration_id1, requests, options, SkBitmap(), &error);
-  EXPECT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
+  {
+    EXPECT_CALL(*this, OnRegistrationCreated(registration_id1, _, _, _, _));
+
+    CreateRegistration(registration_id1, requests, options, SkBitmap(), &error);
+    ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
+  }
 
   RestartDataManagerFromPersistentStorage();
 
@@ -844,15 +870,15 @@
   // |service_worker_registration_id| should yield an error, even after
   // restarting.
   CreateRegistration(registration_id2, requests, options, SkBitmap(), &error);
-  EXPECT_EQ(error, blink::mojom::BackgroundFetchError::DUPLICATED_DEVELOPER_ID);
+  ASSERT_EQ(error, blink::mojom::BackgroundFetchError::DUPLICATED_DEVELOPER_ID);
 
   // Verify that the registration can be retrieved before deletion.
   auto registration =
       GetRegistration(sw_id, origin(), kExampleDeveloperId, &error);
   ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
-  ASSERT_TRUE(registration);
-  EXPECT_EQ(kExampleUniqueId, registration->unique_id);
-  EXPECT_EQ(kExampleDeveloperId, registration->developer_id);
+
+  EXPECT_EQ(kExampleUniqueId, registration.unique_id);
+  EXPECT_EQ(kExampleDeveloperId, registration.developer_id);
 
   // Deactivating the registration should succeed.
   MarkRegistrationForDeletion(registration_id1, &error);
@@ -861,7 +887,6 @@
   // Verify that the registration cannot be retrieved after deletion
   registration = GetRegistration(sw_id, origin(), kExampleDeveloperId, &error);
   ASSERT_EQ(error, blink::mojom::BackgroundFetchError::INVALID_ID);
-  ASSERT_FALSE(registration);
 
   RestartDataManagerFromPersistentStorage();
 
@@ -869,14 +894,17 @@
   // a restart.
   registration = GetRegistration(sw_id, origin(), kExampleDeveloperId, &error);
   ASSERT_EQ(error, blink::mojom::BackgroundFetchError::INVALID_ID);
-  ASSERT_FALSE(registration);
 
   // And now registering the second registration should work fine, even after
   // restarting, since there is no longer an *active* registration with the same
   // |developer_id|, even though the initial registration has not yet been
   // deleted.
-  CreateRegistration(registration_id2, requests, options, SkBitmap(), &error);
-  EXPECT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
+  {
+    EXPECT_CALL(*this, OnRegistrationCreated(registration_id2, _, _, _, _));
+
+    CreateRegistration(registration_id2, requests, options, SkBitmap(), &error);
+    ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
+  }
 
   RestartDataManagerFromPersistentStorage();
 
@@ -907,8 +935,13 @@
   BackgroundFetchOptions options;
   blink::mojom::BackgroundFetchError error;
 
-  CreateRegistration(registration_id, requests, options, SkBitmap(), &error);
-  EXPECT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
+  {
+    EXPECT_CALL(*this, OnRegistrationCreated(registration_id, _, _, _, _));
+
+    CreateRegistration(registration_id, requests, options, SkBitmap(), &error);
+    ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
+  }
+
   EXPECT_EQ(
       GetRequestStats(sw_id),
       (ResponseStateStats{2 /* pending_requests */, 0 /* active_requests */,
@@ -970,13 +1003,17 @@
 
   BackgroundFetchOptions options;
   blink::mojom::BackgroundFetchError error;
-  CreateRegistration(registration_id, requests, options, SkBitmap(), &error);
-  EXPECT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
+  {
+    EXPECT_CALL(*this, OnRegistrationCreated(registration_id, _, _, _, _));
+
+    CreateRegistration(registration_id, requests, options, SkBitmap(), &error);
+    ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
+  }
 
   auto registration =
       GetRegistration(sw_id, origin(), kExampleDeveloperId, &error);
   ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
-  EXPECT_EQ(registration->download_total, 0u);
+  EXPECT_EQ(registration.download_total, 0u);
 
   scoped_refptr<BackgroundFetchRequestInfo> request_info;
   PopNextRequest(registration_id, &request_info);
@@ -986,7 +1023,7 @@
 
   registration = GetRegistration(sw_id, origin(), kExampleDeveloperId, &error);
   ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
-  EXPECT_EQ(registration->download_total, kResponseFileSize);
+  EXPECT_EQ(registration.download_total, kResponseFileSize);
 
   PopNextRequest(registration_id, &request_info);
   AnnotateRequestInfoWithFakeDownloadManagerData(request_info.get(),
@@ -995,7 +1032,7 @@
 
   registration = GetRegistration(sw_id, origin(), kExampleDeveloperId, &error);
   ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
-  EXPECT_EQ(registration->download_total, 2 * kResponseFileSize);
+  EXPECT_EQ(registration.download_total, 2 * kResponseFileSize);
 
   PopNextRequest(registration_id, &request_info);
   AnnotateRequestInfoWithFakeDownloadManagerData(request_info.get(),
@@ -1005,7 +1042,7 @@
   registration = GetRegistration(sw_id, origin(), kExampleDeveloperId, &error);
   ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
   // |download_total| is unchanged.
-  EXPECT_EQ(registration->download_total, 2 * kResponseFileSize);
+  EXPECT_EQ(registration.download_total, 2 * kResponseFileSize);
 }
 
 TEST_F(BackgroundFetchDataManagerTest, WriteToCache) {
@@ -1018,9 +1055,12 @@
 
   BackgroundFetchOptions options;
   blink::mojom::BackgroundFetchError error;
+  {
+    EXPECT_CALL(*this, OnRegistrationCreated(registration_id, _, _, _, _));
 
-  CreateRegistration(registration_id, requests, options, SkBitmap(), &error);
-  EXPECT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
+    CreateRegistration(registration_id, requests, options, SkBitmap(), &error);
+    ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
+  }
 
   scoped_refptr<BackgroundFetchRequestInfo> request_info;
   PopNextRequest(registration_id, &request_info);
@@ -1062,9 +1102,12 @@
 
   BackgroundFetchOptions options;
   blink::mojom::BackgroundFetchError error;
+  {
+    EXPECT_CALL(*this, OnRegistrationCreated(registration_id, _, _, _, _));
 
-  CreateRegistration(registration_id, {request}, options, SkBitmap(), &error);
-  EXPECT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
+    CreateRegistration(registration_id, {request}, options, SkBitmap(), &error);
+    ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
+  }
 
   scoped_refptr<BackgroundFetchRequestInfo> request_info;
   PopNextRequest(registration_id, &request_info);
@@ -1095,8 +1138,13 @@
   BackgroundFetchRegistrationId registration_id(
       sw_id, origin(), kExampleDeveloperId, kExampleUniqueId);
 
-  CreateRegistration(registration_id, requests, options, SkBitmap(), &error);
-  ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
+  {
+    EXPECT_CALL(*this, OnRegistrationCreated(registration_id, _, _, _, _));
+
+    CreateRegistration(registration_id, requests, options, SkBitmap(), &error);
+    ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
+  }
+
   EXPECT_EQ(
       GetRequestStats(sw_id),
       (ResponseStateStats{2 /* pending_requests */, 0 /* active_requests */,
@@ -1147,8 +1195,12 @@
 
   BackgroundFetchOptions options;
   blink::mojom::BackgroundFetchError error;
-  CreateRegistration(registration_id, requests, options, SkBitmap(), &error);
-  EXPECT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
+  {
+    EXPECT_CALL(*this, OnRegistrationCreated(registration_id, _, _, _, _));
+
+    CreateRegistration(registration_id, requests, options, SkBitmap(), &error);
+    ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
+  }
 
   bool succeeded = false;
   std::vector<BackgroundFetchSettledFetch> settled_fetches;
@@ -1215,8 +1267,12 @@
   BackgroundFetchRegistrationId registration_id(
       sw_id, origin(), kExampleDeveloperId, kExampleUniqueId);
 
-  CreateRegistration(registration_id, requests, options, SkBitmap(), &error);
-  ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
+  {
+    EXPECT_CALL(*this, OnRegistrationCreated(registration_id, _, _, _, _));
+
+    CreateRegistration(registration_id, requests, options, SkBitmap(), &error);
+    ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
+  }
 
   for (size_t i = 0; i < requests.size(); i++) {
     SCOPED_TRACE(i);
@@ -1255,8 +1311,12 @@
   BackgroundFetchRegistrationId registration_id(
       sw_id, origin(), kExampleDeveloperId, kExampleUniqueId);
 
-  CreateRegistration(registration_id, requests, options, SkBitmap(), &error);
-  ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
+  {
+    EXPECT_CALL(*this, OnRegistrationCreated(registration_id, _, _, _, _));
+
+    CreateRegistration(registration_id, requests, options, SkBitmap(), &error);
+    ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
+  }
 
   for (size_t i = 0; i < requests.size() - 1; i++) {
     SCOPED_TRACE(i);
@@ -1300,8 +1360,12 @@
   EXPECT_EQ(0u,
             GetRegistrationUserDataByKeyPrefix(sw_id, kUserDataPrefix).size());
   // Create a registration.
-  CreateRegistration(registration_id, requests, options, SkBitmap(), &error);
-  ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
+  {
+    EXPECT_CALL(*this, OnRegistrationCreated(registration_id, _, _, _, _));
+
+    CreateRegistration(registration_id, requests, options, SkBitmap(), &error);
+    ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
+  }
 
   // We expect as many pending entries as there are requests.
   EXPECT_EQ(requests.size(),
@@ -1364,8 +1428,14 @@
   SkBitmap icon;
   icon.allocN32Pixels(42, 42);
   icon.eraseColor(SK_ColorGREEN);
-  CreateRegistration(registration_id, requests, options, icon, &error);
-  ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
+
+  {
+    EXPECT_CALL(*this, OnRegistrationCreated(registration_id, _, _, _, _));
+
+    CreateRegistration(registration_id, requests, options, icon, &error);
+    ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
+  }
+
   {
     std::vector<BackgroundFetchInitializationData> data =
         GetInitializationData();
@@ -1413,8 +1483,13 @@
   // Create another registration.
   BackgroundFetchRegistrationId registration_id2(
       sw_id, origin(), kAlternativeDeveloperId, kAlternativeUniqueId);
-  CreateRegistration(registration_id2, requests, options, SkBitmap(), &error);
-  EXPECT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
+  {
+    EXPECT_CALL(*this, OnRegistrationCreated(registration_id2, _, _, _, _));
+
+    CreateRegistration(registration_id2, requests, options, SkBitmap(), &error);
+    ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
+  }
+
   {
     std::vector<BackgroundFetchInitializationData> data =
         GetInitializationData();
@@ -1435,11 +1510,15 @@
 
   std::vector<blink::mojom::BackgroundFetchError> errors(5);
 
+  // We expect a single successful registration to be created.
+  EXPECT_CALL(*this, OnRegistrationCreated(_, _, _, _, _));
+
   const int num_parallel_creates = 5;
 
   base::RunLoop run_loop;
   base::RepeatingClosure quit_once_all_finished_closure =
       base::BarrierClosure(num_parallel_creates, run_loop.QuitClosure());
+
   for (int i = 0; i < num_parallel_creates; i++) {
     // New |unique_id| per iteration, since each is a distinct registration.
     BackgroundFetchRegistrationId registration_id(
diff --git a/content/browser/background_fetch/background_fetch_service_unittest.cc b/content/browser/background_fetch/background_fetch_service_unittest.cc
index 36f5702..9a73efb 100644
--- a/content/browser/background_fetch/background_fetch_service_unittest.cc
+++ b/content/browser/background_fetch/background_fetch_service_unittest.cc
@@ -290,9 +290,12 @@
     base::RunLoop().RunUntilIdle();
   }
 
+ protected:
+  scoped_refptr<BackgroundFetchContext> context_;
+
  private:
   void DidGetRegistration(
-      base::Closure quit_closure,
+      base::OnceClosure quit_closure,
       blink::mojom::BackgroundFetchError* out_error,
       BackgroundFetchRegistration* out_registration,
       blink::mojom::BackgroundFetchError error,
@@ -305,15 +308,14 @@
     std::move(quit_closure).Run();
   }
 
-  void DidStartFetch(
-      base::Closure quit_closure,
-      blink::mojom::BackgroundFetchError error,
-      std::unique_ptr<BackgroundFetchRegistration> registration) {
+  void DidStartFetch(base::OnceClosure quit_closure,
+                     blink::mojom::BackgroundFetchError error,
+                     const BackgroundFetchRegistration& registration) {
     ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
     std::move(quit_closure).Run();
   }
 
-  void DidGetError(base::Closure quit_closure,
+  void DidGetError(base::OnceClosure quit_closure,
                    blink::mojom::BackgroundFetchError* out_error,
                    blink::mojom::BackgroundFetchError error) {
     *out_error = error;
@@ -321,7 +323,7 @@
     std::move(quit_closure).Run();
   }
 
-  void DidGetDeveloperIds(base::Closure quit_closure,
+  void DidGetDeveloperIds(base::OnceClosure quit_closure,
                           blink::mojom::BackgroundFetchError* out_error,
                           std::vector<std::string>* out_developer_ids,
                           blink::mojom::BackgroundFetchError error,
@@ -332,7 +334,6 @@
     std::move(quit_closure).Run();
   }
 
-  scoped_refptr<BackgroundFetchContext> context_;
   std::unique_ptr<BackgroundFetchServiceImpl> service_;
 
   DISALLOW_COPY_AND_ASSIGN(BackgroundFetchServiceTest);
@@ -1095,9 +1096,15 @@
           .Build()));
   BackgroundFetchOptions options;
 
-  // Only register the Fetch.
-  StartFetch(service_worker_registration_id, kExampleDeveloperId, requests,
-             options, SkBitmap());
+  // Only register the Fetch. In order to appropriately simulate a browser
+  // restart, we do not want the fetch to start yet.
+  {
+    base::AutoReset<bool> hang_registration_creation_for_testing(
+        &context_->hang_registration_creation_for_testing_, true);
+
+    StartFetch(service_worker_registration_id, kExampleDeveloperId, requests,
+               options, SkBitmap());
+  }
 
   // Simulate browser restart by re-creating |context_| and |service_|.
   SetUp();
diff --git a/content/browser/background_fetch/storage/create_metadata_task.cc b/content/browser/background_fetch/storage/create_metadata_task.cc
index a57d8e6..cab3c9e 100644
--- a/content/browser/background_fetch/storage/create_metadata_task.cc
+++ b/content/browser/background_fetch/storage/create_metadata_task.cc
@@ -8,6 +8,8 @@
 
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
+#include "content/browser/background_fetch/background_fetch_data_manager.h"
+#include "content/browser/background_fetch/background_fetch_data_manager_observer.h"
 #include "content/browser/background_fetch/storage/database_helpers.h"
 #include "content/browser/background_fetch/storage/image_helpers.h"
 #include "content/browser/service_worker/service_worker_context_wrapper.h"
@@ -191,9 +193,20 @@
 
 void CreateMetadataTask::FinishWithError(
     blink::mojom::BackgroundFetchError error) {
-  if (error != blink::mojom::BackgroundFetchError::NONE)
-    metadata_proto_.reset();
-  std::move(callback_).Run(error, std::move(metadata_proto_));
+  BackgroundFetchRegistration registration;
+
+  if (error == blink::mojom::BackgroundFetchError::NONE) {
+    DCHECK(metadata_proto_);
+
+    registration = ToBackgroundFetchRegistration(*metadata_proto_);
+
+    for (auto& observer : data_manager()->observers()) {
+      observer.OnRegistrationCreated(registration_id_, registration, options_,
+                                     icon_, requests_.size());
+    }
+  }
+
+  std::move(callback_).Run(error, registration);
   Finished();  // Destroys |this|.
 }
 
diff --git a/content/browser/background_fetch/storage/create_metadata_task.h b/content/browser/background_fetch/storage/create_metadata_task.h
index b57d953..11bdea37 100644
--- a/content/browser/background_fetch/storage/create_metadata_task.h
+++ b/content/browser/background_fetch/storage/create_metadata_task.h
@@ -17,6 +17,8 @@
 
 namespace content {
 
+struct BackgroundFetchRegistration;
+
 namespace background_fetch {
 
 // Creates Background Fetch metadata entries in the database.
@@ -24,7 +26,7 @@
  public:
   using CreateMetadataCallback =
       base::OnceCallback<void(blink::mojom::BackgroundFetchError,
-                              std::unique_ptr<proto::BackgroundFetchMetadata>)>;
+                              const BackgroundFetchRegistration&)>;
 
   CreateMetadataTask(DatabaseTaskHost* host,
                      const BackgroundFetchRegistrationId& registration_id,
diff --git a/content/browser/background_fetch/storage/database_helpers.cc b/content/browser/background_fetch/storage/database_helpers.cc
index 44152e8..7079357 100644
--- a/content/browser/background_fetch/storage/database_helpers.cc
+++ b/content/browser/background_fetch/storage/database_helpers.cc
@@ -5,6 +5,7 @@
 #include "content/browser/background_fetch/storage/database_helpers.h"
 
 #include "base/strings/string_number_conversions.h"
+#include "content/browser/background_fetch/background_fetch.pb.h"
 
 namespace content {
 
@@ -87,6 +88,21 @@
   return DatabaseStatus::kFailed;
 }
 
+BackgroundFetchRegistration ToBackgroundFetchRegistration(
+    const proto::BackgroundFetchMetadata& metadata_proto) {
+  const auto& registration_proto = metadata_proto.registration();
+
+  BackgroundFetchRegistration registration;
+  registration.developer_id = registration_proto.developer_id();
+  registration.unique_id = registration_proto.unique_id();
+  registration.upload_total = registration_proto.upload_total();
+  registration.uploaded = registration_proto.uploaded();
+  registration.download_total = registration_proto.download_total();
+  registration.downloaded = registration_proto.downloaded();
+
+  return registration;
+}
+
 }  // namespace background_fetch
 
 }  // namespace content
diff --git a/content/browser/background_fetch/storage/database_helpers.h b/content/browser/background_fetch/storage/database_helpers.h
index 459a558..215fb56 100644
--- a/content/browser/background_fetch/storage/database_helpers.h
+++ b/content/browser/background_fetch/storage/database_helpers.h
@@ -7,11 +7,17 @@
 
 #include <string>
 
+#include "content/common/background_fetch/background_fetch_types.h"
+#include "content/common/content_export.h"
 #include "content/common/service_worker/service_worker_types.h"
 #include "third_party/blink/public/common/service_worker/service_worker_status_code.h"
 
 namespace content {
 
+namespace proto {
+class BackgroundFetchMetadata;
+}
+
 namespace background_fetch {
 
 // The database schema is content/browser/background_fetch/storage/README.md.
@@ -32,7 +38,7 @@
 // Database Keys.
 std::string ActiveRegistrationUniqueIdKey(const std::string& developer_id);
 
-std::string RegistrationKey(const std::string& unique_id);
+CONTENT_EXPORT std::string RegistrationKey(const std::string& unique_id);
 
 std::string UIOptionsKey(const std::string& unique_id);
 
@@ -54,6 +60,10 @@
 
 DatabaseStatus ToDatabaseStatus(blink::ServiceWorkerStatusCode status);
 
+// Converts the |metadata_proto| to a BackgroundFetchRegistration object.
+BackgroundFetchRegistration ToBackgroundFetchRegistration(
+    const proto::BackgroundFetchMetadata& metadata_proto);
+
 }  // namespace background_fetch
 
 }  // namespace content
diff --git a/content/browser/background_fetch/storage/get_registration_task.cc b/content/browser/background_fetch/storage/get_registration_task.cc
new file mode 100644
index 0000000..e8cbc868
--- /dev/null
+++ b/content/browser/background_fetch/storage/get_registration_task.cc
@@ -0,0 +1,59 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/background_fetch/storage/get_registration_task.h"
+
+#include "content/browser/background_fetch/background_fetch.pb.h"
+#include "content/browser/background_fetch/storage/database_helpers.h"
+#include "content/browser/background_fetch/storage/get_metadata_task.h"
+
+namespace content {
+
+namespace background_fetch {
+
+GetRegistrationTask::GetRegistrationTask(DatabaseTaskHost* host,
+                                         int64_t service_worker_registration_id,
+                                         const url::Origin& origin,
+                                         const std::string& developer_id,
+                                         GetRegistrationCallback callback)
+    : DatabaseTask(host),
+      service_worker_registration_id_(service_worker_registration_id),
+      origin_(origin),
+      developer_id_(developer_id),
+      callback_(std::move(callback)),
+      weak_factory_(this) {}
+
+GetRegistrationTask::~GetRegistrationTask() = default;
+
+void GetRegistrationTask::Start() {
+  AddSubTask(std::make_unique<GetMetadataTask>(
+      this, service_worker_registration_id_, origin_, developer_id_,
+      base::BindOnce(&GetRegistrationTask::DidGetMetadata,
+                     weak_factory_.GetWeakPtr())));
+}
+
+void GetRegistrationTask::DidGetMetadata(
+    blink::mojom::BackgroundFetchError error,
+    std::unique_ptr<proto::BackgroundFetchMetadata> metadata_proto) {
+  metadata_proto_ = std::move(metadata_proto);
+  FinishWithError(error);
+}
+
+void GetRegistrationTask::FinishWithError(
+    blink::mojom::BackgroundFetchError error) {
+  BackgroundFetchRegistration registration;
+
+  if (error == blink::mojom::BackgroundFetchError::NONE) {
+    DCHECK(metadata_proto_);
+
+    registration = ToBackgroundFetchRegistration(*metadata_proto_);
+  }
+
+  std::move(callback_).Run(error, registration);
+  Finished();  // Destroys |this|.
+}
+
+}  // namespace background_fetch
+
+}  // namespace content
diff --git a/content/browser/background_fetch/storage/get_registration_task.h b/content/browser/background_fetch/storage/get_registration_task.h
new file mode 100644
index 0000000..1178529
--- /dev/null
+++ b/content/browser/background_fetch/storage/get_registration_task.h
@@ -0,0 +1,66 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_BACKGROUND_FETCH_STORAGE_GET_REGISTRATION_TASK_H_
+#define CONTENT_BROWSER_BACKGROUND_FETCH_STORAGE_GET_REGISTRATION_TASK_H_
+
+#include <memory>
+#include <string>
+
+#include "base/callback_forward.h"
+#include "content/browser/background_fetch/storage/database_task.h"
+#include "third_party/blink/public/common/service_worker/service_worker_status_code.h"
+#include "url/origin.h"
+
+namespace content {
+
+namespace proto {
+class BackgroundFetchMetadata;
+}
+
+namespace background_fetch {
+
+// Gets an active Background Fetch metadata entry from the database.
+class GetRegistrationTask : public DatabaseTask {
+ public:
+  using GetRegistrationCallback =
+      base::OnceCallback<void(blink::mojom::BackgroundFetchError,
+                              const BackgroundFetchRegistration&)>;
+
+  GetRegistrationTask(DatabaseTaskHost* host,
+                      int64_t service_worker_registration_id,
+                      const url::Origin& origin,
+                      const std::string& developer_id,
+                      GetRegistrationCallback callback);
+
+  ~GetRegistrationTask() override;
+
+  // DatabaseTask implementation:
+  void Start() override;
+
+ private:
+  void DidGetMetadata(
+      blink::mojom::BackgroundFetchError error,
+      std::unique_ptr<proto::BackgroundFetchMetadata> metadata_proto);
+
+  void FinishWithError(blink::mojom::BackgroundFetchError error) override;
+
+  int64_t service_worker_registration_id_;
+  url::Origin origin_;
+  std::string developer_id_;
+
+  GetRegistrationCallback callback_;
+
+  std::unique_ptr<proto::BackgroundFetchMetadata> metadata_proto_;
+
+  base::WeakPtrFactory<GetRegistrationTask> weak_factory_;  // Keep as last.
+
+  DISALLOW_COPY_AND_ASSIGN(GetRegistrationTask);
+};
+
+}  // namespace background_fetch
+
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_BACKGROUND_FETCH_STORAGE_GET_REGISTRATION_TASK_H_
diff --git a/content/browser/background_fetch/storage/start_next_pending_request_task.cc b/content/browser/background_fetch/storage/start_next_pending_request_task.cc
index 1cc5c79..d0ae4e3 100644
--- a/content/browser/background_fetch/storage/start_next_pending_request_task.cc
+++ b/content/browser/background_fetch/storage/start_next_pending_request_task.cc
@@ -15,15 +15,15 @@
 
 StartNextPendingRequestTask::StartNextPendingRequestTask(
     DatabaseTaskHost* host,
-    int64_t service_worker_registration_id,
-    std::unique_ptr<proto::BackgroundFetchMetadata> metadata,
+    const BackgroundFetchRegistrationId& registration_id,
+    const BackgroundFetchRegistration& registration,
     NextRequestCallback callback)
     : DatabaseTask(host),
-      service_worker_registration_id_(service_worker_registration_id),
-      metadata_(std::move(metadata)),
+      registration_id_(registration_id),
+      registration_(registration),
       callback_(std::move(callback)),
       weak_factory_(this) {
-  DCHECK(metadata_);
+  DCHECK(!registration_id_.is_null());
 }
 
 StartNextPendingRequestTask::~StartNextPendingRequestTask() = default;
@@ -34,8 +34,8 @@
 
 void StartNextPendingRequestTask::GetPendingRequests() {
   service_worker_context()->GetRegistrationUserDataByKeyPrefix(
-      service_worker_registration_id_,
-      PendingRequestKeyPrefix(metadata_->registration().unique_id()),
+      registration_id_.service_worker_registration_id(),
+      PendingRequestKeyPrefix(registration_.unique_id),
       base::BindOnce(&StartNextPendingRequestTask::DidGetPendingRequests,
                      weak_factory_.GetWeakPtr()));
 }
@@ -59,7 +59,7 @@
 
   if (!pending_request_.ParseFromString(data.front())) {
     // Service Worker database has been corrupted. Abandon fetches.
-    AbandonFetches(service_worker_registration_id_);
+    AbandonFetches(registration_id_.service_worker_registration_id());
     FinishWithError(blink::mojom::BackgroundFetchError::STORAGE_ERROR);
     return;
   }
@@ -67,7 +67,7 @@
   // Make sure there isn't already an Active Request.
   // This might happen if the browser is killed in-between writes.
   service_worker_context()->GetRegistrationUserData(
-      service_worker_registration_id_,
+      registration_id_.service_worker_registration_id(),
       {ActiveRequestKey(pending_request_.unique_id(),
                         pending_request_.request_index())},
       base::BindOnce(&StartNextPendingRequestTask::DidFindActiveRequest,
@@ -88,7 +88,7 @@
       // We already stored the active request.
       if (!active_request_.ParseFromString(data.front())) {
         // Service worker database has been corrupted. Abandon fetches.
-        AbandonFetches(service_worker_registration_id_);
+        AbandonFetches(registration_id_.service_worker_registration_id());
         FinishWithError(blink::mojom::BackgroundFetchError::STORAGE_ERROR);
         return;
       }
@@ -109,7 +109,8 @@
       pending_request_.release_serialized_request());
 
   service_worker_context()->StoreRegistrationUserData(
-      service_worker_registration_id_, GURL(metadata_->origin()),
+      registration_id_.service_worker_registration_id(),
+      registration_id_.origin().GetURL(),
       {{ActiveRequestKey(active_request_.unique_id(),
                          active_request_.request_index()),
         active_request_.SerializeAsString()}},
@@ -143,7 +144,7 @@
 
   // Delete the pending request.
   service_worker_context()->ClearRegistrationUserData(
-      service_worker_registration_id_,
+      registration_id_.service_worker_registration_id(),
       {PendingRequestKey(pending_request_.unique_id(),
                          pending_request_.request_index())},
       base::BindOnce(&StartNextPendingRequestTask::DidDeletePendingRequest,
diff --git a/content/browser/background_fetch/storage/start_next_pending_request_task.h b/content/browser/background_fetch/storage/start_next_pending_request_task.h
index 89ae0fb..fcef4e4 100644
--- a/content/browser/background_fetch/storage/start_next_pending_request_task.h
+++ b/content/browser/background_fetch/storage/start_next_pending_request_task.h
@@ -9,6 +9,7 @@
 #include "content/browser/background_fetch/background_fetch.pb.h"
 #include "content/browser/background_fetch/background_fetch_request_info.h"
 #include "content/browser/background_fetch/storage/database_task.h"
+#include "content/common/background_fetch/background_fetch_types.h"
 #include "third_party/blink/public/common/service_worker/service_worker_status_code.h"
 
 namespace content {
@@ -24,8 +25,8 @@
 
   StartNextPendingRequestTask(
       DatabaseTaskHost* host,
-      int64_t service_worker_registration_id,
-      std::unique_ptr<proto::BackgroundFetchMetadata> metadata,
+      const BackgroundFetchRegistrationId& registration_id,
+      const BackgroundFetchRegistration& registration,
       NextRequestCallback callback);
 
   ~StartNextPendingRequestTask() override;
@@ -52,8 +53,8 @@
 
   void FinishWithError(blink::mojom::BackgroundFetchError error) override;
 
-  int64_t service_worker_registration_id_;
-  std::unique_ptr<proto::BackgroundFetchMetadata> metadata_;
+  BackgroundFetchRegistrationId registration_id_;
+  BackgroundFetchRegistration registration_;
   NextRequestCallback callback_;
 
   // protos don't support move semantics, so these class members will be used
diff --git a/content/browser/renderer_host/browser_compositor_view_mac.h b/content/browser/renderer_host/browser_compositor_view_mac.h
index 46be85e..254be13 100644
--- a/content/browser/renderer_host/browser_compositor_view_mac.h
+++ b/content/browser/renderer_host/browser_compositor_view_mac.h
@@ -148,7 +148,7 @@
 
   bool ForceNewSurfaceForTesting();
 
-  ui::Compositor* GetCompositorForTesting() const;
+  ui::Compositor* GetCompositor() const;
 
  private:
   // ui::LayerObserver implementation:
diff --git a/content/browser/renderer_host/browser_compositor_view_mac.mm b/content/browser/renderer_host/browser_compositor_view_mac.mm
index 9bb2156..5bf4dbf4 100644
--- a/content/browser/renderer_host/browser_compositor_view_mac.mm
+++ b/content/browser/renderer_host/browser_compositor_view_mac.mm
@@ -487,7 +487,9 @@
   SetParentUiLayer(nullptr);
 }
 
-ui::Compositor* BrowserCompositorMac::GetCompositorForTesting() const {
+ui::Compositor* BrowserCompositorMac::GetCompositor() const {
+  if (parent_ui_layer_)
+    return parent_ui_layer_->GetCompositor();
   if (recyclable_compositor_)
     return recyclable_compositor_->compositor();
   return nullptr;
diff --git a/content/browser/renderer_host/input/fling_scheduler_mac.mm b/content/browser/renderer_host/input/fling_scheduler_mac.mm
index f2ac740b..83959b3e 100644
--- a/content/browser/renderer_host/input/fling_scheduler_mac.mm
+++ b/content/browser/renderer_host/input/fling_scheduler_mac.mm
@@ -21,14 +21,10 @@
   // RWHV_child_frame doesn't have DelegatedFrameHost with ui::Compositor.
   if (host_->GetView()->IsRenderWidgetHostViewChildFrame())
     return nullptr;
-
-  // TODO(sahel): Uncomment this once Viz is ready on Mac.
-  // https://crbug.com/833985
-  /* RenderWidgetHostViewMac* view =
+  RenderWidgetHostViewMac* view =
       static_cast<RenderWidgetHostViewMac*>(host_->GetView());
   if (view->BrowserCompositor())
-    return view->BrowserCompositor()->Compositor();
-  } */
+    return view->BrowserCompositor()->GetCompositor();
 
   return nullptr;
 }
diff --git a/content/browser/renderer_host/render_widget_host_impl.cc b/content/browser/renderer_host/render_widget_host_impl.cc
index 5e77b36..3454038 100644
--- a/content/browser/renderer_host/render_widget_host_impl.cc
+++ b/content/browser/renderer_host/render_widget_host_impl.cc
@@ -2830,14 +2830,22 @@
       return;
   }
 
+  // Consider any bitmaps registered with the old CompositorFrameSink as gone,
+  // they will be re-registered on the newly requested CompositorFrameSink if
+  // they are meant to be used still. https://crbug.com/862584.
+  for (const auto& id : owned_bitmaps_)
+    shared_bitmap_manager_->ChildDeletedSharedBitmap(id);
+  owned_bitmaps_.clear();
+
   if (compositor_frame_sink_binding_.is_bound())
     compositor_frame_sink_binding_.Close();
   compositor_frame_sink_binding_.Bind(
       std::move(compositor_frame_sink_request),
       BrowserMainLoop::GetInstance()->GetResizeTaskRunner());
-  if (view_)
+  if (view_) {
     view_->DidCreateNewRendererCompositorFrameSink(
         compositor_frame_sink_client.get());
+  }
   renderer_compositor_frame_sink_ = std::move(compositor_frame_sink_client);
 }
 
diff --git a/content/browser/renderer_host/render_widget_host_view_aura.cc b/content/browser/renderer_host/render_widget_host_view_aura.cc
index 0916857..0eec5c7 100644
--- a/content/browser/renderer_host/render_widget_host_view_aura.cc
+++ b/content/browser/renderer_host/render_widget_host_view_aura.cc
@@ -2339,11 +2339,14 @@
     GetInputMethod()->OnTextInputTypeChanged(this);
 
   const TextInputState* state = text_input_manager_->GetTextInputState();
-  if (state && state->show_ime_if_needed &&
-      state->type != ui::TEXT_INPUT_TYPE_NONE &&
-      state->mode != ui::TEXT_INPUT_MODE_NONE &&
-      GetInputMethod()->GetTextInputClient() == this) {
-    GetInputMethod()->ShowVirtualKeyboardIfEnabled();
+  if (state && state->type != ui::TEXT_INPUT_TYPE_NONE &&
+      state->mode != ui::TEXT_INPUT_MODE_NONE) {
+    if (state->show_ime_if_needed &&
+        GetInputMethod()->GetTextInputClient() == this)
+      GetInputMethod()->ShowVirtualKeyboardIfEnabled();
+    // Ensure that accessibility events are fired when the selection location
+    // moves from UI back to content.
+    text_input_manager->NotifySelectionBoundsChanged(updated_view);
   }
 
   if (auto* render_widget_host = updated_view->host()) {
diff --git a/content/browser/renderer_host/render_widget_host_view_event_handler.cc b/content/browser/renderer_host/render_widget_host_view_event_handler.cc
index 0f9d0a1c..940d9c1 100644
--- a/content/browser/renderer_host/render_widget_host_view_event_handler.cc
+++ b/content/browser/renderer_host/render_widget_host_view_event_handler.cc
@@ -751,73 +751,75 @@
         ProcessMouseWheelEvent(mouse_wheel_event, *event->latency());
       }
     }
-    return;
-  }
-
-  gfx::Point center(gfx::Rect(window_->bounds().size()).CenterPoint());
-
-  // If we receive non client mouse messages while we are in the locked state
-  // it probably means that the mouse left the borders of our window and
-  // needs to be moved back to the center.
-  if (event->flags() & ui::EF_IS_NON_CLIENT) {
-    // TODO(jonross): ideally this would not be done for mus (crbug.com/621412)
-    MoveCursorToCenter();
-    return;
-  }
-
-  blink::WebMouseEvent mouse_event =
-      ui::MakeWebMouseEvent(*event, base::Bind(&GetScreenLocationFromEvent));
-
-  bool is_move_to_center_event =
-      (event->type() == ui::ET_MOUSE_MOVED ||
-       event->type() == ui::ET_MOUSE_DRAGGED) &&
-      mouse_event.PositionInWidget().x == center.x() &&
-      mouse_event.PositionInWidget().y == center.y();
-
-  // For fractional scale factors, the conversion from pixels to dip and
-  // vice versa could result in off by 1 or 2 errors which hurts us because
-  // we want to avoid sending the artificial move to center event to the
-  // renderer. Sending the move to center to the renderer cause the cursor
-  // to bounce around the center of the screen leading to the lock operation
-  // not working correctly.
-  // Workaround is to treat a mouse move or drag event off by at most 2 px
-  // from the center as a move to center event.
-  if (synthetic_move_sent_ &&
-      IsFractionalScaleFactor(host_view_->current_device_scale_factor())) {
-    if (event->type() == ui::ET_MOUSE_MOVED ||
-        event->type() == ui::ET_MOUSE_DRAGGED) {
-      if ((std::abs(mouse_event.PositionInWidget().x - center.x()) <= 2) &&
-          (std::abs(mouse_event.PositionInWidget().y - center.y()) <= 2)) {
-        is_move_to_center_event = true;
-      }
-    }
-  }
-
-  ModifyEventMovementAndCoords(*event, &mouse_event);
-
-  bool should_not_forward = is_move_to_center_event && synthetic_move_sent_;
-  if (should_not_forward) {
-    synthetic_move_sent_ = false;
   } else {
-    // Check if the mouse has reached the border and needs to be centered.
-    if (ShouldMoveToCenter())
+    gfx::Point center(gfx::Rect(window_->bounds().size()).CenterPoint());
+
+    // If we receive non client mouse messages while we are in the locked state
+    // it probably means that the mouse left the borders of our window and
+    // needs to be moved back to the center.
+    if (event->flags() & ui::EF_IS_NON_CLIENT) {
+      // TODO(jonross): ideally this would not be done for mus
+      // (crbug.com/621412)
       MoveCursorToCenter();
-    bool is_selection_popup = NeedsInputGrab(popup_child_host_view_);
-    // Forward event to renderer.
-    if (CanRendererHandleEvent(event, mouse_locked_, is_selection_popup) &&
-        !(event->flags() & ui::EF_FROM_TOUCH)) {
-      if (ShouldRouteEvent(event)) {
-        host_->delegate()->GetInputEventRouter()->RouteMouseEvent(
-            host_view_, &mouse_event, *event->latency());
-      } else {
-        ProcessMouseEvent(mouse_event, *event->latency());
+      return;
+    }
+
+    blink::WebMouseEvent mouse_event =
+        ui::MakeWebMouseEvent(*event, base::Bind(&GetScreenLocationFromEvent));
+
+    bool is_move_to_center_event =
+        (event->type() == ui::ET_MOUSE_MOVED ||
+         event->type() == ui::ET_MOUSE_DRAGGED) &&
+        mouse_event.PositionInWidget().x == center.x() &&
+        mouse_event.PositionInWidget().y == center.y();
+
+    // For fractional scale factors, the conversion from pixels to dip and
+    // vice versa could result in off by 1 or 2 errors which hurts us because
+    // we want to avoid sending the artificial move to center event to the
+    // renderer. Sending the move to center to the renderer cause the cursor
+    // to bounce around the center of the screen leading to the lock operation
+    // not working correctly.
+    // Workaround is to treat a mouse move or drag event off by at most 2 px
+    // from the center as a move to center event.
+    if (synthetic_move_sent_ &&
+        IsFractionalScaleFactor(host_view_->current_device_scale_factor())) {
+      if (event->type() == ui::ET_MOUSE_MOVED ||
+          event->type() == ui::ET_MOUSE_DRAGGED) {
+        if ((std::abs(mouse_event.PositionInWidget().x - center.x()) <= 2) &&
+            (std::abs(mouse_event.PositionInWidget().y - center.y()) <= 2)) {
+          is_move_to_center_event = true;
+        }
       }
-      // Ensure that we get keyboard focus on mouse down as a plugin window
-      // may have grabbed keyboard focus.
-      if (event->type() == ui::ET_MOUSE_PRESSED)
-        SetKeyboardFocus();
+    }
+
+    ModifyEventMovementAndCoords(*event, &mouse_event);
+
+    bool should_not_forward = is_move_to_center_event && synthetic_move_sent_;
+    if (should_not_forward) {
+      synthetic_move_sent_ = false;
+    } else {
+      // Check if the mouse has reached the border and needs to be centered.
+      if (ShouldMoveToCenter())
+        MoveCursorToCenter();
+      bool is_selection_popup = NeedsInputGrab(popup_child_host_view_);
+      // Forward event to renderer.
+      if (CanRendererHandleEvent(event, mouse_locked_, is_selection_popup) &&
+          !(event->flags() & ui::EF_FROM_TOUCH)) {
+        if (ShouldRouteEvent(event)) {
+          host_->delegate()->GetInputEventRouter()->RouteMouseEvent(
+              host_view_, &mouse_event, *event->latency());
+        } else {
+          ProcessMouseEvent(mouse_event, *event->latency());
+        }
+        // Ensure that we get keyboard focus on mouse down as a plugin window
+        // may have grabbed keyboard focus.
+        if (event->type() == ui::ET_MOUSE_PRESSED)
+          SetKeyboardFocus();
+      }
     }
   }
+  if (!ShouldGenerateAppCommand(event))
+    event->SetHandled();
 }
 
 void RenderWidgetHostViewEventHandler::ModifyEventMovementAndCoords(
diff --git a/content/browser/renderer_host/render_widget_host_view_mac_unittest.mm b/content/browser/renderer_host/render_widget_host_view_mac_unittest.mm
index 4fceb1a..a97ff3eb 100644
--- a/content/browser/renderer_host/render_widget_host_view_mac_unittest.mm
+++ b/content/browser/renderer_host/render_widget_host_view_mac_unittest.mm
@@ -1837,11 +1837,11 @@
 
 TEST_F(RenderWidgetHostViewMacTest, ClearCompositorFrame) {
   BrowserCompositorMac* browser_compositor = rwhv_mac_->BrowserCompositor();
-  ui::Compositor* ui_compositor = browser_compositor->GetCompositorForTesting();
+  ui::Compositor* ui_compositor = browser_compositor->GetCompositor();
   EXPECT_NE(ui_compositor, nullptr);
   EXPECT_TRUE(ui_compositor->IsLocked());
   rwhv_mac_->ClearCompositorFrame();
-  EXPECT_EQ(browser_compositor->GetCompositorForTesting(), ui_compositor);
+  EXPECT_EQ(browser_compositor->GetCompositor(), ui_compositor);
   EXPECT_FALSE(ui_compositor->IsLocked());
 }
 
diff --git a/content/browser/renderer_host/text_input_manager.cc b/content/browser/renderer_host/text_input_manager.cc
index 24f32e72..ce3a5ff8 100644
--- a/content/browser/renderer_host/text_input_manager.cc
+++ b/content/browser/renderer_host/text_input_manager.cc
@@ -209,6 +209,11 @@
   selection_region_map_[view].first_selection_rect.set_size(
       params.anchor_rect.size());
 
+  NotifySelectionBoundsChanged(view);
+}
+
+void TextInputManager::NotifySelectionBoundsChanged(
+    RenderWidgetHostViewBase* view) {
   for (auto& observer : observer_list_)
     observer.OnSelectionBoundsChanged(this, view);
 }
diff --git a/content/browser/renderer_host/text_input_manager.h b/content/browser/renderer_host/text_input_manager.h
index 8e4ecfe..d145a992 100644
--- a/content/browser/renderer_host/text_input_manager.h
+++ b/content/browser/renderer_host/text_input_manager.h
@@ -184,6 +184,10 @@
   void SelectionBoundsChanged(RenderWidgetHostViewBase* view,
                               const ViewHostMsg_SelectionBounds_Params& params);
 
+  // Notify observers that the selection bounds have been updated. This is also
+  // called when a view with a selection is reactivated.
+  void NotifySelectionBoundsChanged(RenderWidgetHostViewBase* view);
+
   // Called when the composition range and/or character bounds have changed.
   void ImeCompositionRangeChanged(
       RenderWidgetHostViewBase* view,
diff --git a/content/browser/service_worker/service_worker_consts.cc b/content/browser/service_worker/service_worker_consts.cc
index 0a6663f..b149396 100644
--- a/content/browser/service_worker/service_worker_consts.cc
+++ b/content/browser/service_worker/service_worker_consts.cc
@@ -46,6 +46,9 @@
 const char ServiceWorkerConsts::kShutdownErrorMessage[] =
     "The Service Worker system has shutdown.";
 
+const char ServiceWorkerConsts::kUpdateTimeoutErrorMesage[] =
+    "Service worker self-update limit exceeded.";
+
 const char ServiceWorkerConsts::kUserDeniedPermissionMessage[] =
     "The user denied permission to use Service Worker.";
 
diff --git a/content/browser/service_worker/service_worker_consts.h b/content/browser/service_worker/service_worker_consts.h
index d119a47..1eab9d5 100644
--- a/content/browser/service_worker/service_worker_consts.h
+++ b/content/browser/service_worker/service_worker_consts.h
@@ -21,6 +21,7 @@
   static const char kNoDocumentURLErrorMessage[];
   static const char kSetNavigationPreloadHeaderErrorPrefix[];
   static const char kShutdownErrorMessage[];
+  static const char kUpdateTimeoutErrorMesage[];
   static const char kUserDeniedPermissionMessage[];
 };
 
diff --git a/content/browser/service_worker/service_worker_object_host.cc b/content/browser/service_worker/service_worker_object_host.cc
index 49b03786..cd4f6ea5 100644
--- a/content/browser/service_worker/service_worker_object_host.cc
+++ b/content/browser/service_worker/service_worker_object_host.cc
@@ -19,7 +19,7 @@
 namespace {
 
 using StatusCallback = base::OnceCallback<void(blink::ServiceWorkerStatusCode)>;
-using SetExtendableMessageEventSourceCallback =
+using PrepareExtendableMessageEventCallback =
     base::OnceCallback<bool(mojom::ExtendableMessageEventPtr*)>;
 
 void DispatchExtendableMessageEventAfterStartWorker(
@@ -28,7 +28,7 @@
     const url::Origin& source_origin,
     const base::Optional<base::TimeDelta>& timeout,
     StatusCallback callback,
-    SetExtendableMessageEventSourceCallback set_source_callback,
+    PrepareExtendableMessageEventCallback prepare_callback,
     blink::ServiceWorkerStatusCode start_worker_status) {
   if (start_worker_status != blink::ServiceWorkerStatusCode::kOk) {
     std::move(callback).Run(start_worker_status);
@@ -38,7 +38,7 @@
   mojom::ExtendableMessageEventPtr event = mojom::ExtendableMessageEvent::New();
   event->message = std::move(message);
   event->source_origin = source_origin;
-  if (!std::move(set_source_callback).Run(&event)) {
+  if (!std::move(prepare_callback).Run(&event)) {
     std::move(callback).Run(blink::ServiceWorkerStatusCode::kErrorFailed);
     return;
   }
@@ -62,7 +62,7 @@
     const url::Origin& source_origin,
     const base::Optional<base::TimeDelta>& timeout,
     StatusCallback callback,
-    SetExtendableMessageEventSourceCallback set_source_callback) {
+    PrepareExtendableMessageEventCallback prepare_callback) {
   // If not enough time is left to actually process the event don't even
   // bother starting the worker and sending the event.
   if (timeout && *timeout < base::TimeDelta::FromMilliseconds(100)) {
@@ -74,27 +74,42 @@
       ServiceWorkerMetrics::EventType::MESSAGE,
       base::BindOnce(&DispatchExtendableMessageEventAfterStartWorker, worker,
                      std::move(message), source_origin, timeout,
-                     std::move(callback), std::move(set_source_callback)));
+                     std::move(callback), std::move(prepare_callback)));
 }
 
-bool SetSourceClientInfo(
+bool PrepareExtendableMessageEventFromClient(
+    base::WeakPtr<ServiceWorkerContextCore> context,
+    int64_t registration_id,
     blink::mojom::ServiceWorkerClientInfoPtr source_client_info,
     mojom::ExtendableMessageEventPtr* event) {
+  if (!context) {
+    return false;
+  }
   DCHECK(source_client_info && !source_client_info->client_uuid.empty());
   (*event)->source_info_for_client = std::move(source_client_info);
   // Hide the client url if the client has a unique origin.
   if ((*event)->source_origin.unique())
     (*event)->source_info_for_client->url = GURL();
+
+  // Reset |registration->self_update_delay| iff postMessage is coming from a
+  // client, to prevent workers from postMessage to another version to reset
+  // the delay (https://crbug.com/805496).
+  ServiceWorkerRegistration* registration =
+      context->GetLiveRegistration(registration_id);
+  DCHECK(registration) << "running workers should have a live registration";
+  registration->set_self_update_delay(base::TimeDelta());
+
   return true;
 }
 
 // The output |event| must be sent over Mojo immediately after this function
 // returns. See ServiceWorkerObjectHost::CreateCompleteObjectInfoToSend() for
 // details.
-bool SetSourceServiceWorkerInfo(scoped_refptr<ServiceWorkerVersion> worker,
-                                base::WeakPtr<ServiceWorkerProviderHost>
-                                    source_service_worker_provider_host,
-                                mojom::ExtendableMessageEventPtr* event) {
+bool PrepareExtendableMessageEventFromServiceWorker(
+    scoped_refptr<ServiceWorkerVersion> worker,
+    base::WeakPtr<ServiceWorkerProviderHost>
+        source_service_worker_provider_host,
+    mojom::ExtendableMessageEventPtr* event) {
   // The service worker execution context may have been destroyed by the time we
   // get here.
   if (!source_service_worker_provider_host)
@@ -121,11 +136,16 @@
 }
 
 void DispatchExtendableMessageEventFromClient(
+    base::WeakPtr<ServiceWorkerContextCore> context,
     scoped_refptr<ServiceWorkerVersion> worker,
     blink::TransferableMessage message,
     const url::Origin& source_origin,
     StatusCallback callback,
     blink::mojom::ServiceWorkerClientInfoPtr source_client_info) {
+  if (!context) {
+    std::move(callback).Run(blink::ServiceWorkerStatusCode::kErrorAbort);
+    return;
+  }
   // |source_client_info| may be null if a client sent the message but its
   // info could not be retrieved.
   if (!source_client_info) {
@@ -136,7 +156,8 @@
   StartWorkerToDispatchExtendableMessageEvent(
       worker, std::move(message), source_origin, base::nullopt /* timeout */,
       std::move(callback),
-      base::BindOnce(&SetSourceClientInfo, std::move(source_client_info)));
+      base::BindOnce(&PrepareExtendableMessageEventFromClient, context,
+                     worker->registration_id(), std::move(source_client_info)));
 }
 
 void DispatchExtendableMessageEventFromServiceWorker(
@@ -156,7 +177,7 @@
             source_service_worker_provider_host->provider_type());
   StartWorkerToDispatchExtendableMessageEvent(
       worker, std::move(message), source_origin, timeout, std::move(callback),
-      base::BindOnce(&SetSourceServiceWorkerInfo, worker,
+      base::BindOnce(&PrepareExtendableMessageEventFromServiceWorker, worker,
                      source_service_worker_provider_host));
 }
 
@@ -261,8 +282,8 @@
     case blink::mojom::ServiceWorkerProviderType::kForWindow:
       service_worker_client_utils::GetClient(
           provider_host_,
-          base::BindOnce(&DispatchExtendableMessageEventFromClient, version_,
-                         std::move(message), provider_origin_,
+          base::BindOnce(&DispatchExtendableMessageEventFromClient, context_,
+                         version_, std::move(message), provider_origin_,
                          std::move(callback)));
       return;
     case blink::mojom::ServiceWorkerProviderType::kForServiceWorker: {
diff --git a/content/browser/service_worker/service_worker_registration.h b/content/browser/service_worker/service_worker_registration.h
index e579f31c..2b9d3a29 100644
--- a/content/browser/service_worker/service_worker_registration.h
+++ b/content/browser/service_worker/service_worker_registration.h
@@ -15,6 +15,7 @@
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/single_thread_task_runner.h"
+#include "base/time/time.h"
 #include "content/browser/service_worker/service_worker_version.h"
 #include "content/common/content_export.h"
 #include "content/common/service_worker/service_worker_types.h"
@@ -162,6 +163,13 @@
   base::Time last_update_check() const { return last_update_check_; }
   void set_last_update_check(base::Time last) { last_update_check_ = last; }
 
+  // The delay for self-updating service workers, to prevent them from running
+  // forever (see https://crbug.com/805496).
+  base::TimeDelta self_update_delay() const { return self_update_delay_; }
+  void set_self_update_delay(const base::TimeDelta& delay) {
+    self_update_delay_ = delay;
+  }
+
   // Unsets the version and deletes its resources. Also deletes this
   // registration from storage if there is no longer a stored version.
   void DeleteVersion(const scoped_refptr<ServiceWorkerVersion>& version);
@@ -227,6 +235,7 @@
   bool should_activate_when_ready_;
   blink::mojom::NavigationPreloadState navigation_preload_state_;
   base::Time last_update_check_;
+  base::TimeDelta self_update_delay_;
   int64_t resources_total_size_bytes_;
 
   // This registration is the primary owner of these versions.
diff --git a/content/browser/service_worker/service_worker_registration_object_host.cc b/content/browser/service_worker/service_worker_registration_object_host.cc
index 4e758bf3..5466cd6 100644
--- a/content/browser/service_worker/service_worker_registration_object_host.cc
+++ b/content/browser/service_worker/service_worker_registration_object_host.cc
@@ -4,11 +4,13 @@
 
 #include "content/browser/service_worker/service_worker_registration_object_host.h"
 
+#include "base/time/time.h"
 #include "content/browser/service_worker/service_worker_consts.h"
 #include "content/browser/service_worker/service_worker_context_core.h"
 #include "content/browser/service_worker/service_worker_object_host.h"
 #include "content/browser/service_worker/service_worker_provider_host.h"
 #include "content/common/service_worker/service_worker_utils.h"
+#include "content/public/browser/browser_thread.h"
 #include "net/http/http_util.h"
 #include "third_party/blink/public/mojom/service_worker/service_worker_registration.mojom.h"
 
@@ -16,6 +18,9 @@
 
 namespace {
 
+constexpr base::TimeDelta kSelfUpdateDelay = base::TimeDelta::FromSeconds(30);
+constexpr base::TimeDelta kMaxSelfUpdateDelay = base::TimeDelta::FromMinutes(3);
+
 // Returns an object info to send over Mojo. The info must be sent immediately.
 // See ServiceWorkerObjectHost::CreateCompleteObjectInfoToSend() for details.
 blink::mojom::ServiceWorkerObjectInfoPtr CreateCompleteObjectInfoToSend(
@@ -28,6 +33,45 @@
   return service_worker_object_host->CreateCompleteObjectInfoToSend();
 }
 
+void ExecuteUpdate(base::WeakPtr<ServiceWorkerContextCore> context,
+                   int64_t registration_id,
+                   bool force_bypass_cache,
+                   bool skip_script_comparison,
+                   ServiceWorkerContextCore::UpdateCallback callback,
+                   blink::ServiceWorkerStatusCode status) {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+  if (status != blink::ServiceWorkerStatusCode::kOk) {
+    // The delay was already very long and update() is rejected immediately.
+    DCHECK_EQ(blink::ServiceWorkerStatusCode::kErrorTimeout, status);
+    std::move(callback).Run(blink::ServiceWorkerStatusCode::kErrorTimeout,
+                            ServiceWorkerConsts::kUpdateTimeoutErrorMesage,
+                            registration_id);
+    return;
+  }
+
+  if (!context) {
+    std::move(callback).Run(blink::ServiceWorkerStatusCode::kErrorAbort,
+                            ServiceWorkerConsts::kShutdownErrorMessage,
+                            registration_id);
+    return;
+  }
+
+  ServiceWorkerRegistration* registration =
+      context->GetLiveRegistration(registration_id);
+  if (!registration) {
+    // The service worker is no longer running, so update() won't be rejected.
+    // We still run the callback so the caller knows.
+    std::move(callback).Run(blink::ServiceWorkerStatusCode::kErrorTimeout,
+                            ServiceWorkerConsts::kUpdateTimeoutErrorMesage,
+                            registration_id);
+    return;
+  }
+
+  context->UpdateServiceWorker(registration, force_bypass_cache,
+                               skip_script_comparison, std::move(callback));
+}
+
 }  // anonymous namespace
 
 ServiceWorkerRegistrationObjectHost::ServiceWorkerRegistrationObjectHost(
@@ -116,14 +160,58 @@
     return;
   }
 
-  context_->UpdateServiceWorker(
-      registration_.get(), false /* force_bypass_cache */,
-      false /* skip_script_comparison */,
-      base::AdaptCallbackForRepeating(
+  DelayUpdate(
+      provider_host_->provider_type(), registration_.get(),
+      provider_host_->running_hosted_version(),
+      base::BindOnce(
+          &ExecuteUpdate, context_, registration_->id(),
+          false /* force_bypass_cache */, false /* skip_script_comparison */,
           base::BindOnce(&ServiceWorkerRegistrationObjectHost::UpdateComplete,
                          weak_ptr_factory_.GetWeakPtr(), std::move(callback))));
 }
 
+void ServiceWorkerRegistrationObjectHost::DelayUpdate(
+    blink::mojom::ServiceWorkerProviderType provider_type,
+    ServiceWorkerRegistration* registration,
+    ServiceWorkerVersion* version,
+    StatusCallback update_function) {
+  DCHECK(registration);
+
+  if (provider_type !=
+          blink::mojom::ServiceWorkerProviderType::kForServiceWorker ||
+      (version && version->HasControllee())) {
+    // Don't delay update() if called by non-workers or by workers with
+    // controllees.
+    std::move(update_function).Run(blink::ServiceWorkerStatusCode::kOk);
+    return;
+  }
+
+  base::TimeDelta delay = registration->self_update_delay();
+  if (delay > kMaxSelfUpdateDelay) {
+    std::move(update_function)
+        .Run(blink::ServiceWorkerStatusCode::kErrorTimeout);
+    return;
+  }
+
+  if (delay < kSelfUpdateDelay) {
+    registration->set_self_update_delay(kSelfUpdateDelay);
+  } else {
+    registration->set_self_update_delay(delay * 2);
+  }
+
+  if (delay < base::TimeDelta::Min()) {
+    // Only enforce the delay of update() iff |delay| exists.
+    std::move(update_function).Run(blink::ServiceWorkerStatusCode::kOk);
+    return;
+  }
+
+  BrowserThread::PostDelayedTask(
+      BrowserThread::IO, FROM_HERE,
+      base::BindOnce(std::move(update_function),
+                     blink::ServiceWorkerStatusCode::kOk),
+      delay);
+}
+
 void ServiceWorkerRegistrationObjectHost::Unregister(
     UnregisterCallback callback) {
   if (!CanServeRegistrationObjectHostMethods(
@@ -302,6 +390,7 @@
     waiting = CreateCompleteObjectInfoToSend(provider_host_, waiting_version);
   if (changed_mask.active_changed())
     active = CreateCompleteObjectInfoToSend(provider_host_, active_version);
+
   DCHECK(remote_registration_);
   remote_registration_->SetVersionAttributes(
       changed_mask.changed(), std::move(installing), std::move(waiting),
diff --git a/content/browser/service_worker/service_worker_registration_object_host.h b/content/browser/service_worker/service_worker_registration_object_host.h
index b96daf0..cfca9b43 100644
--- a/content/browser/service_worker/service_worker_registration_object_host.h
+++ b/content/browser/service_worker/service_worker_registration_object_host.h
@@ -17,6 +17,9 @@
 #include "third_party/blink/public/mojom/service_worker/service_worker_registration.mojom.h"
 
 namespace content {
+namespace service_worker_registration_unittest {
+class ServiceWorkerRegistrationObjectHostTest;
+}  // namespace service_worker_registration_unittest
 
 class ServiceWorkerContextCore;
 class ServiceWorkerVersion;
@@ -46,6 +49,12 @@
   ServiceWorkerRegistration* registration() { return registration_.get(); }
 
  private:
+  friend class service_worker_registration_unittest::
+      ServiceWorkerRegistrationObjectHostTest;
+
+  using StatusCallback =
+      base::OnceCallback<void(blink::ServiceWorkerStatusCode status)>;
+
   // ServiceWorkerRegistration::Listener overrides.
   void OnVersionAttributesChanged(
       ServiceWorkerRegistration* registration,
@@ -68,6 +77,20 @@
       const std::string& value,
       SetNavigationPreloadHeaderCallback callback) override;
 
+  // Delays an update if it is called by a worker without controllee, to prevent
+  // workers from running forever (see https://crbug.com/805496).
+  // Calls |update_function| with blink::ServiceWorkerStatusCode::kOk if the
+  // update should procceed, and blink::ServiceWorkerStatusCode::kTimeout
+  // otherwise.
+  // If there is no delay, or if the delay is very long, |update_function| is
+  // executed synchronously (before this method returns).
+  //
+  // TODO(falken): See if tests can call |Update| directly, then this separate
+  // function isn't needed.
+  static void DelayUpdate(blink::mojom::ServiceWorkerProviderType provider_type,
+                          ServiceWorkerRegistration* registration,
+                          ServiceWorkerVersion* version,
+                          StatusCallback update_function);
   // Called back from ServiceWorkerContextCore when an update is complete.
   void UpdateComplete(UpdateCallback callback,
                       blink::ServiceWorkerStatusCode status,
diff --git a/content/browser/service_worker/service_worker_registration_unittest.cc b/content/browser/service_worker/service_worker_registration_unittest.cc
index 59a6e79..beed04a 100644
--- a/content/browser/service_worker/service_worker_registration_unittest.cc
+++ b/content/browser/service_worker/service_worker_registration_unittest.cc
@@ -698,6 +698,27 @@
     return error;
   }
 
+  blink::ServiceWorkerStatusCode CallDelayUpdate(
+      blink::mojom::ServiceWorkerProviderType provider_type,
+      ServiceWorkerRegistration* registration,
+      ServiceWorkerVersion* version) {
+    base::Optional<blink::ServiceWorkerStatusCode> status;
+    base::RunLoop run_loop;
+    ServiceWorkerRegistrationObjectHost::DelayUpdate(
+        blink::mojom::ServiceWorkerProviderType::kForServiceWorker,
+        registration, version,
+        base::BindOnce(
+            [](base::Optional<blink::ServiceWorkerStatusCode>* out_status,
+               base::OnceClosure callback,
+               blink::ServiceWorkerStatusCode status) {
+              *out_status = status;
+              std::move(callback).Run();
+            },
+            &status, run_loop.QuitClosure()));
+    run_loop.Run();
+    return status.value();
+  }
+
   blink::mojom::ServiceWorkerErrorType CallUnregister(
       blink::mojom::ServiceWorkerRegistrationObjectHost* registration_host) {
     blink::mojom::ServiceWorkerErrorType error =
@@ -730,21 +751,21 @@
     return status.value();
   }
 
-  int64_t SetUpRegistration(const GURL& scope, const GURL& script_url) {
-    storage()->LazyInitializeForTest(base::DoNothing());
-    base::RunLoop().RunUntilIdle();
-
-    // Prepare ServiceWorkerRegistration.
+  scoped_refptr<ServiceWorkerRegistration> CreateRegistration(
+      const GURL& scope) {
     blink::mojom::ServiceWorkerRegistrationOptions options;
     options.scope = scope;
-    scoped_refptr<ServiceWorkerRegistration> registration =
-        base::MakeRefCounted<ServiceWorkerRegistration>(
-            options, storage()->NewRegistrationId(), context()->AsWeakPtr());
-    // Prepare ServiceWorkerVersion.
+    return base::MakeRefCounted<ServiceWorkerRegistration>(
+        options, storage()->NewRegistrationId(), context()->AsWeakPtr());
+  }
+
+  scoped_refptr<ServiceWorkerVersion> CreateVersion(
+      ServiceWorkerRegistration* registration,
+      const GURL& script_url) {
     scoped_refptr<ServiceWorkerVersion> version =
-        base::MakeRefCounted<ServiceWorkerVersion>(
-            registration.get(), script_url, storage()->NewVersionId(),
-            context()->AsWeakPtr());
+        base::MakeRefCounted<ServiceWorkerVersion>(registration, script_url,
+                                                   storage()->NewVersionId(),
+                                                   context()->AsWeakPtr());
     std::vector<ServiceWorkerDatabase::ResourceRecord> records;
     records.push_back(WriteToDiskCacheSync(
         storage(), version->script_url(), storage()->NewResourceId(),
@@ -755,13 +776,26 @@
     version->set_fetch_handler_existence(
         ServiceWorkerVersion::FetchHandlerExistence::EXISTS);
     version->SetStatus(ServiceWorkerVersion::INSTALLING);
+    return version;
+  }
+
+  int64_t SetUpRegistration(const GURL& scope, const GURL& script_url) {
+    storage()->LazyInitializeForTest(base::DoNothing());
+    base::RunLoop().RunUntilIdle();
+
+    // Prepare ServiceWorkerRegistration and ServiceWorkerVersion.
+    scoped_refptr<ServiceWorkerRegistration> registration =
+        CreateRegistration(scope);
+    scoped_refptr<ServiceWorkerVersion> version =
+        CreateVersion(registration.get(), script_url);
+
     // Make the registration findable via storage functions.
     bool called = false;
     blink::ServiceWorkerStatusCode status =
         blink::ServiceWorkerStatusCode::kErrorFailed;
-    storage()->StoreRegistration(registration.get(), version.get(),
-                                 base::AdaptCallbackForRepeating(base::BindOnce(
-                                     &SaveStatusCallback, &called, &status)));
+    storage()->StoreRegistration(
+        registration.get(), version.get(),
+        base::BindOnce(&SaveStatusCallback, &called, &status));
     base::RunLoop().RunUntilIdle();
     EXPECT_EQ(blink::ServiceWorkerStatusCode::kOk, status);
 
@@ -893,6 +927,102 @@
   SetBrowserClientForTesting(old_browser_client);
 }
 
+TEST_F(ServiceWorkerRegistrationObjectHostTest, Update_NoDelayFromControllee) {
+  const GURL kScope("https://www.example.com/");
+  const GURL kScriptUrl("https://www.example.com/sw.js");
+  int64_t registration_id = SetUpRegistration(kScope, kScriptUrl);
+  const int64_t kProviderId = 99;  // Dummy value
+  ServiceWorkerRemoteProviderEndpoint remote_endpoint =
+      PrepareProviderHost(kProviderId, kScope);
+  blink::mojom::ServiceWorkerRegistrationObjectHostAssociatedPtr
+      registration_host_ptr;
+
+  blink::mojom::ServiceWorkerRegistrationObjectInfoPtr info =
+      GetRegistrationFromRemote(remote_endpoint.host_ptr()->get(), kScope);
+  registration_host_ptr.Bind(std::move(info->host_ptr_info));
+  // Ignore the messages to the registration object, otherwise the callbacks
+  // issued from |registration_host_ptr| may wait for receiving the messages to
+  // |info->request|.
+  info->request = nullptr;
+
+  // Get registration and set |self_update_delay| to zero.
+  ServiceWorkerRegistration* registration =
+      context()->GetLiveRegistration(registration_id);
+  ASSERT_TRUE(registration);
+  registration->set_self_update_delay(base::TimeDelta());
+  EXPECT_EQ(base::TimeDelta(), registration->self_update_delay());
+
+  EXPECT_EQ(blink::mojom::ServiceWorkerErrorType::kNone,
+            CallUpdate(registration_host_ptr.get()));
+  EXPECT_EQ(base::TimeDelta(), registration->self_update_delay());
+}
+
+TEST_F(ServiceWorkerRegistrationObjectHostTest,
+       Update_DelayFromWorkerWithoutControllee) {
+  const GURL kScope("https://www.example.com/");
+  const GURL kScriptUrl("https://www.example.com/sw.js");
+  scoped_refptr<ServiceWorkerRegistration> registration =
+      CreateRegistration(kScope);
+  scoped_refptr<ServiceWorkerVersion> version =
+      CreateVersion(registration.get(), kScriptUrl);
+
+  // Initially set |self_update_delay| to zero.
+  registration->set_self_update_delay(base::TimeDelta());
+  EXPECT_EQ(base::TimeDelta(), registration->self_update_delay());
+
+  EXPECT_EQ(blink::ServiceWorkerStatusCode::kOk,
+            CallDelayUpdate(
+                blink::mojom::ServiceWorkerProviderType::kForServiceWorker,
+                registration.get(), version.get()));
+  EXPECT_LT(base::TimeDelta(), registration->self_update_delay());
+
+  // TODO(falken): Add a test verifying that a delayed update will be executed
+  // eventually.
+
+  // Set |self_update_delay| to a time so that update() will reject immediately.
+  registration->set_self_update_delay(base::TimeDelta::FromMinutes(5));
+  EXPECT_EQ(blink::ServiceWorkerStatusCode::kErrorTimeout,
+            CallDelayUpdate(
+                blink::mojom::ServiceWorkerProviderType::kForServiceWorker,
+                registration.get(), version.get()));
+  EXPECT_LE(base::TimeDelta::FromMinutes(5), registration->self_update_delay());
+}
+
+TEST_F(ServiceWorkerRegistrationObjectHostTest,
+       Update_NoDelayFromWorkerWithControllee) {
+  const GURL kScope("https://www.example.com/");
+  const GURL kScriptUrl("https://www.example.com/sw.js");
+  const int64_t kProviderId = 99;  // Dummy value
+  scoped_refptr<ServiceWorkerRegistration> registration =
+      CreateRegistration(kScope);
+  scoped_refptr<ServiceWorkerVersion> version =
+      CreateVersion(registration.get(), kScriptUrl);
+  ServiceWorkerRemoteProviderEndpoint remote_endpoint;
+  std::unique_ptr<ServiceWorkerProviderHost> host = CreateProviderHostForWindow(
+      helper_->mock_render_process_id(), kProviderId,
+      true /* is_parent_frame_secure */, context()->AsWeakPtr(),
+      &remote_endpoint);
+  host->SetDocumentUrl(kScope);
+  version->AddControllee(host.get());
+
+  // Initially set |self_update_delay| to zero.
+  registration->set_self_update_delay(base::TimeDelta());
+  EXPECT_EQ(blink::ServiceWorkerStatusCode::kOk,
+            CallDelayUpdate(
+                blink::mojom::ServiceWorkerProviderType::kForServiceWorker,
+                registration.get(), version.get()));
+  EXPECT_EQ(base::TimeDelta(), registration->self_update_delay());
+
+  // Set |self_update_delay| to a time so that update() will reject immediately
+  // if the worker doesn't have at least one controlee.
+  registration->set_self_update_delay(base::TimeDelta::FromMinutes(5));
+  EXPECT_EQ(blink::ServiceWorkerStatusCode::kOk,
+            CallDelayUpdate(
+                blink::mojom::ServiceWorkerProviderType::kForServiceWorker,
+                registration.get(), version.get()));
+  EXPECT_EQ(base::TimeDelta::FromMinutes(5), registration->self_update_delay());
+}
+
 TEST_F(ServiceWorkerRegistrationObjectHostTest, Unregister_Success) {
   const GURL kScope("https://www.example.com/");
   const GURL kScriptUrl("https://www.example.com/sw.js");
diff --git a/content/browser/service_worker/service_worker_version.cc b/content/browser/service_worker/service_worker_version.cc
index 4dbeba6..b9ae2602 100644
--- a/content/browser/service_worker/service_worker_version.cc
+++ b/content/browser/service_worker/service_worker_version.cc
@@ -538,6 +538,21 @@
       << "Event of type " << static_cast<int>(event_type)
       << " can only be dispatched to an active worker: " << status();
 
+  if (event_type != ServiceWorkerMetrics::EventType::INSTALL &&
+      event_type != ServiceWorkerMetrics::EventType::ACTIVATE &&
+      event_type != ServiceWorkerMetrics::EventType::MESSAGE) {
+    // Reset the self-update delay iff this is not an event that can triggered
+    // by a service worker itself. Otherwise, service workers can use update()
+    // to keep running forever via install and activate events, or postMessage()
+    // between themselves to reset the delay via message event.
+    // postMessage() resets the delay in ServiceWorkerObjectHost, iff it didn't
+    // come from a service worker.
+    ServiceWorkerRegistration* registration =
+        context_->GetLiveRegistration(registration_id_);
+    DCHECK(registration) << "running workers should have a live registration";
+    registration->set_self_update_delay(base::TimeDelta());
+  }
+
   auto request = std::make_unique<InflightRequest>(
       std::move(error_callback), clock_->Now(), tick_clock_->NowTicks(),
       event_type);
@@ -669,6 +684,12 @@
   RestartTick(&idle_time_);
   ClearTick(&no_controllees_time_);
 
+  ServiceWorkerRegistration* registration =
+      context_->GetLiveRegistration(registration_id_);
+  if (registration) {
+    registration->set_self_update_delay(base::TimeDelta());
+  }
+
   // Notify observers asynchronously for consistency with RemoveControllee.
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
diff --git a/content/browser/service_worker/service_worker_version_unittest.cc b/content/browser/service_worker/service_worker_version_unittest.cc
index 2b3f970..dbd520b0 100644
--- a/content/browser/service_worker/service_worker_version_unittest.cc
+++ b/content/browser/service_worker/service_worker_version_unittest.cc
@@ -773,6 +773,42 @@
   EXPECT_EQ(run_time, version_->update_timer_.desired_run_time());
 }
 
+// Tests the delay mechanism for self-updating service workers, to prevent
+// them from running forever (see https://crbug.com/805496).
+TEST_F(ServiceWorkerVersionTest, ResetUpdateDelay) {
+  const base::TimeDelta kMinute = base::TimeDelta::FromMinutes(1);
+  const base::TimeDelta kNoDelay = base::TimeDelta();
+
+  // Initialize the delay.
+  version_->SetStatus(ServiceWorkerVersion::ACTIVATED);
+  registration_->SetActiveVersion(version_);
+  registration_->set_self_update_delay(kMinute);
+
+  // Events that can be triggered by a worker should not reset the delay.
+  // See the comment in ServiceWorkerVersion::StartRequestWithCustomTimeout.
+  SimulateDispatchEvent(ServiceWorkerMetrics::EventType::INSTALL);
+  SimulateDispatchEvent(ServiceWorkerMetrics::EventType::ACTIVATE);
+  SimulateDispatchEvent(ServiceWorkerMetrics::EventType::MESSAGE);
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(kMinute, registration_->self_update_delay());
+
+  // Events that can only be triggered externally reset the delay.
+  // Repeat the test for several such events.
+  SimulateDispatchEvent(ServiceWorkerMetrics::EventType::SYNC);
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(kNoDelay, registration_->self_update_delay());
+
+  registration_->set_self_update_delay(kMinute);
+  SimulateDispatchEvent(ServiceWorkerMetrics::EventType::NOTIFICATION_CLICK);
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(kNoDelay, registration_->self_update_delay());
+
+  registration_->set_self_update_delay(kMinute);
+  SimulateDispatchEvent(ServiceWorkerMetrics::EventType::PUSH);
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(kNoDelay, registration_->self_update_delay());
+}
+
 TEST_F(ServiceWorkerVersionTest, UpdateCachedMetadata) {
   CachedMetadataUpdateListener listener;
   version_->AddObserver(&listener);
diff --git a/content/browser/web_contents/web_contents_view_mac.mm b/content/browser/web_contents/web_contents_view_mac.mm
index f14cb05..94848b56 100644
--- a/content/browser/web_contents/web_contents_view_mac.mm
+++ b/content/browser/web_contents/web_contents_view_mac.mm
@@ -450,15 +450,13 @@
 }
 
 void WebContentsViewMac::SetParentUiLayer(ui::Layer* parent_ui_layer) {
+  parent_ui_layer_ = parent_ui_layer;
   // Remove any child NSViews that have been destroyed.
   for (auto iter = child_views_.begin(); iter != child_views_.end();) {
-    auto iter_next = iter;
-    iter_next++;
     if (*iter)
-      (*iter)->SetParentUiLayer(parent_ui_layer);
+      (*iter++)->SetParentUiLayer(parent_ui_layer);
     else
-      child_views_.erase(iter);
-    iter = iter_next;
+      iter = child_views_.erase(iter);
   }
 }
 
diff --git a/content/browser/webauth/authenticator_type_converters.h b/content/browser/webauth/authenticator_type_converters.h
index cc4a53d..4d4847b 100644
--- a/content/browser/webauth/authenticator_type_converters.h
+++ b/content/browser/webauth/authenticator_type_converters.h
@@ -8,7 +8,7 @@
 #include <vector>
 
 #include "device/fido/authenticator_selection_criteria.h"
-#include "device/fido/fido_cable_discovery.h"
+#include "device/fido/cable/fido_cable_discovery.h"
 #include "device/fido/fido_transport_protocol.h"
 #include "device/fido/public_key_credential_descriptor.h"
 #include "device/fido/public_key_credential_params.h"
diff --git a/content/renderer/webclipboard_impl_browsertest.cc b/content/renderer/webclipboard_impl_browsertest.cc
index 181dfe0..870a090 100644
--- a/content/renderer/webclipboard_impl_browsertest.cc
+++ b/content/renderer/webclipboard_impl_browsertest.cc
@@ -22,7 +22,13 @@
   ~WebClipboardImplTest() override = default;
 };
 
-IN_PROC_BROWSER_TEST_F(WebClipboardImplTest, PasteRTF) {
+#if defined(OS_CHROMEOS)
+// Test is flaky on ChromeOS (https://crbug.com/867339).
+#define MAYBE_PasteRTF DISABLED_PasteRTF
+#else
+#define MAYBE_PasteRTF PasteRTF
+#endif
+IN_PROC_BROWSER_TEST_F(WebClipboardImplTest, MAYBE_PasteRTF) {
   BrowserTestClipboardScope clipboard;
 
   const std::string rtf_content = "{\\rtf1\\ansi Hello, {\\b world.}}";
diff --git a/device/BUILD.gn b/device/BUILD.gn
index 21cd7e4e..a36c191 100644
--- a/device/BUILD.gn
+++ b/device/BUILD.gn
@@ -67,12 +67,12 @@
     "fido/ble/fido_ble_connection_unittest.cc",
     "fido/ble/fido_ble_device_unittest.cc",
     "fido/ble/fido_ble_frames_unittest.cc",
+    "fido/cable/fido_cable_device_unittest.cc",
+    "fido/cable/fido_cable_discovery_unittest.cc",
+    "fido/cable/fido_cable_handshake_handler_unittest.cc",
     "fido/ctap_request_unittest.cc",
     "fido/ctap_response_unittest.cc",
     "fido/fake_fido_discovery_unittest.cc",
-    "fido/fido_cable_device_unittest.cc",
-    "fido/fido_cable_discovery_unittest.cc",
-    "fido/fido_cable_handshake_handler_unittest.cc",
     "fido/fido_discovery_unittest.cc",
     "fido/fido_parsing_utils_unittest.cc",
     "fido/fido_request_handler_unittest.cc",
diff --git a/device/fido/BUILD.gn b/device/fido/BUILD.gn
index 6efd796..ac443f8a 100644
--- a/device/fido/BUILD.gn
+++ b/device/fido/BUILD.gn
@@ -39,6 +39,12 @@
     "ble/fido_ble_transaction.h",
     "ble/fido_ble_uuids.cc",
     "ble/fido_ble_uuids.h",
+    "cable/fido_cable_device.cc",
+    "cable/fido_cable_device.h",
+    "cable/fido_cable_discovery.cc",
+    "cable/fido_cable_discovery.h",
+    "cable/fido_cable_handshake_handler.cc",
+    "cable/fido_cable_handshake_handler.h",
     "ctap2_device_operation.h",
     "ctap_empty_authenticator_request.cc",
     "ctap_empty_authenticator_request.h",
@@ -54,12 +60,6 @@
     "fido_attestation_statement.cc",
     "fido_attestation_statement.h",
     "fido_authenticator.h",
-    "fido_cable_device.cc",
-    "fido_cable_device.h",
-    "fido_cable_discovery.cc",
-    "fido_cable_discovery.h",
-    "fido_cable_handshake_handler.cc",
-    "fido_cable_handshake_handler.h",
     "fido_constants.cc",
     "fido_constants.h",
     "fido_device.cc",
@@ -239,7 +239,7 @@
 
 fuzzer_test("fido_cable_handshake_handler_fuzzer") {
   sources = [
-    "fido_cable_handshake_handler_fuzzer.cc",
+    "cable/fido_cable_handshake_handler_fuzzer.cc",
   ]
   deps = [
     ":fido",
diff --git a/device/fido/fido_cable_device.cc b/device/fido/cable/fido_cable_device.cc
similarity index 98%
rename from device/fido/fido_cable_device.cc
rename to device/fido/cable/fido_cable_device.cc
index a0581df1..4eccfe35 100644
--- a/device/fido/fido_cable_device.cc
+++ b/device/fido/cable/fido_cable_device.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "device/fido/fido_cable_device.h"
+#include "device/fido/cable/fido_cable_device.h"
 
 #include <utility>
 
@@ -128,9 +128,9 @@
         FROM_HERE, base::BindOnce(std::move(callback), base::nullopt));
     state_ = State::kDeviceError;
     return;
-    }
+  }
 
-    ++encryption_data_->write_sequence_num;
+  ++encryption_data_->write_sequence_num;
 
   AddToPendingFrames(FidoBleDeviceCommand::kMsg, std::move(command),
                      std::move(callback));
diff --git a/device/fido/fido_cable_device.h b/device/fido/cable/fido_cable_device.h
similarity index 94%
rename from device/fido/fido_cable_device.h
rename to device/fido/cable/fido_cable_device.h
index 9475ada..137055f 100644
--- a/device/fido/fido_cable_device.h
+++ b/device/fido/cable/fido_cable_device.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef DEVICE_FIDO_FIDO_CABLE_DEVICE_H_
-#define DEVICE_FIDO_FIDO_CABLE_DEVICE_H_
+#ifndef DEVICE_FIDO_CABLE_FIDO_CABLE_DEVICE_H_
+#define DEVICE_FIDO_CABLE_FIDO_CABLE_DEVICE_H_
 
 #include <array>
 #include <memory>
@@ -76,4 +76,4 @@
 
 }  // namespace device
 
-#endif  // DEVICE_FIDO_FIDO_CABLE_DEVICE_H_
+#endif  // DEVICE_FIDO_CABLE_FIDO_CABLE_DEVICE_H_
diff --git a/device/fido/fido_cable_device_unittest.cc b/device/fido/cable/fido_cable_device_unittest.cc
similarity index 99%
rename from device/fido/fido_cable_device_unittest.cc
rename to device/fido/cable/fido_cable_device_unittest.cc
index ab51af3..8cd0f968 100644
--- a/device/fido/fido_cable_device_unittest.cc
+++ b/device/fido/cable/fido_cable_device_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "device/fido/fido_cable_device.h"
+#include "device/fido/cable/fido_cable_device.h"
 
 #include <array>
 #include <limits>
diff --git a/device/fido/fido_cable_discovery.cc b/device/fido/cable/fido_cable_discovery.cc
similarity index 98%
rename from device/fido/fido_cable_discovery.cc
rename to device/fido/cable/fido_cable_discovery.cc
index f6e0ddb..158cd92 100644
--- a/device/fido/fido_cable_discovery.cc
+++ b/device/fido/cable/fido_cable_discovery.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "device/fido/fido_cable_discovery.h"
+#include "device/fido/cable/fido_cable_discovery.h"
 
 #include <algorithm>
 #include <memory>
@@ -18,8 +18,8 @@
 #include "device/bluetooth/bluetooth_discovery_session.h"
 #include "device/bluetooth/bluetooth_uuid.h"
 #include "device/fido/ble/fido_ble_uuids.h"
-#include "device/fido/fido_cable_device.h"
-#include "device/fido/fido_cable_handshake_handler.h"
+#include "device/fido/cable/fido_cable_device.h"
+#include "device/fido/cable/fido_cable_handshake_handler.h"
 #include "device/fido/fido_parsing_utils.h"
 
 namespace device {
diff --git a/device/fido/fido_cable_discovery.h b/device/fido/cable/fido_cable_discovery.h
similarity index 96%
rename from device/fido/fido_cable_discovery.h
rename to device/fido/cable/fido_cable_discovery.h
index 2107095..02c5cb8 100644
--- a/device/fido/fido_cable_discovery.h
+++ b/device/fido/cable/fido_cable_discovery.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef DEVICE_FIDO_FIDO_CABLE_DISCOVERY_H_
-#define DEVICE_FIDO_FIDO_CABLE_DISCOVERY_H_
+#ifndef DEVICE_FIDO_CABLE_FIDO_CABLE_DISCOVERY_H_
+#define DEVICE_FIDO_CABLE_FIDO_CABLE_DISCOVERY_H_
 
 #include <stdint.h>
 
@@ -117,4 +117,4 @@
 
 }  // namespace device
 
-#endif  // DEVICE_FIDO_FIDO_CABLE_DISCOVERY_H_
+#endif  // DEVICE_FIDO_CABLE_FIDO_CABLE_DISCOVERY_H_
diff --git a/device/fido/fido_cable_discovery_unittest.cc b/device/fido/cable/fido_cable_discovery_unittest.cc
similarity index 99%
rename from device/fido/fido_cable_discovery_unittest.cc
rename to device/fido/cable/fido_cable_discovery_unittest.cc
index 8d64848..dc69e63 100644
--- a/device/fido/fido_cable_discovery_unittest.cc
+++ b/device/fido/cable/fido_cable_discovery_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "device/fido/fido_cable_discovery.h"
+#include "device/fido/cable/fido_cable_discovery.h"
 
 #include <algorithm>
 #include <memory>
@@ -17,7 +17,7 @@
 #include "device/bluetooth/test/mock_bluetooth_adapter.h"
 #include "device/fido/ble/fido_ble_device.h"
 #include "device/fido/ble/fido_ble_uuids.h"
-#include "device/fido/fido_cable_handshake_handler.h"
+#include "device/fido/cable/fido_cable_handshake_handler.h"
 #include "device/fido/fido_parsing_utils.h"
 #include "device/fido/mock_fido_discovery_observer.h"
 #include "testing/gmock/include/gmock/gmock.h"
diff --git a/device/fido/fido_cable_handshake_handler.cc b/device/fido/cable/fido_cable_handshake_handler.cc
similarity index 97%
rename from device/fido/fido_cable_handshake_handler.cc
rename to device/fido/cable/fido_cable_handshake_handler.cc
index a47c5d0..966a476 100644
--- a/device/fido/fido_cable_handshake_handler.cc
+++ b/device/fido/cable/fido_cable_handshake_handler.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "device/fido/fido_cable_handshake_handler.h"
+#include "device/fido/cable/fido_cable_handshake_handler.h"
 
 #include <algorithm>
 #include <utility>
@@ -14,7 +14,7 @@
 #include "crypto/hkdf.h"
 #include "crypto/hmac.h"
 #include "crypto/random.h"
-#include "device/fido/fido_cable_device.h"
+#include "device/fido/cable/fido_cable_device.h"
 #include "device/fido/fido_constants.h"
 #include "device/fido/fido_parsing_utils.h"
 
diff --git a/device/fido/fido_cable_handshake_handler.h b/device/fido/cable/fido_cable_handshake_handler.h
similarity index 91%
rename from device/fido/fido_cable_handshake_handler.h
rename to device/fido/cable/fido_cable_handshake_handler.h
index fd764e53..175b55d 100644
--- a/device/fido/fido_cable_handshake_handler.h
+++ b/device/fido/cable/fido_cable_handshake_handler.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef DEVICE_FIDO_FIDO_CABLE_HANDSHAKE_HANDLER_H_
-#define DEVICE_FIDO_FIDO_CABLE_HANDSHAKE_HANDLER_H_
+#ifndef DEVICE_FIDO_CABLE_FIDO_CABLE_HANDSHAKE_HANDLER_H_
+#define DEVICE_FIDO_CABLE_FIDO_CABLE_HANDSHAKE_HANDLER_H_
 
 #include <stdint.h>
 
@@ -59,4 +59,4 @@
 
 }  // namespace device
 
-#endif  // DEVICE_FIDO_FIDO_CABLE_HANDSHAKE_HANDLER_H_
+#endif  // DEVICE_FIDO_CABLE_FIDO_CABLE_HANDSHAKE_HANDLER_H_
diff --git a/device/fido/fido_cable_handshake_handler_fuzzer.cc b/device/fido/cable/fido_cable_handshake_handler_fuzzer.cc
similarity index 91%
rename from device/fido/fido_cable_handshake_handler_fuzzer.cc
rename to device/fido/cable/fido_cable_handshake_handler_fuzzer.cc
index 64a9a7a..35a4351 100644
--- a/device/fido/fido_cable_handshake_handler_fuzzer.cc
+++ b/device/fido/cable/fido_cable_handshake_handler_fuzzer.cc
@@ -8,8 +8,8 @@
 #include <array>
 
 #include "base/containers/span.h"
-#include "device/fido/fido_cable_device.h"
-#include "device/fido/fido_cable_handshake_handler.h"
+#include "device/fido/cable/fido_cable_device.h"
+#include "device/fido/cable/fido_cable_handshake_handler.h"
 #include "device/fido/fido_constants.h"
 
 namespace {
diff --git a/device/fido/fido_cable_handshake_handler_unittest.cc b/device/fido/cable/fido_cable_handshake_handler_unittest.cc
similarity index 98%
rename from device/fido/fido_cable_handshake_handler_unittest.cc
rename to device/fido/cable/fido_cable_handshake_handler_unittest.cc
index 376eb20..b2e2c08b 100644
--- a/device/fido/fido_cable_handshake_handler_unittest.cc
+++ b/device/fido/cable/fido_cable_handshake_handler_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "device/fido/fido_cable_handshake_handler.h"
+#include "device/fido/cable/fido_cable_handshake_handler.h"
 
 #include <array>
 #include <limits>
@@ -21,7 +21,7 @@
 #include "device/bluetooth/test/bluetooth_test.h"
 #include "device/fido/ble/fido_ble_frames.h"
 #include "device/fido/ble/mock_fido_ble_connection.h"
-#include "device/fido/fido_cable_device.h"
+#include "device/fido/cable/fido_cable_device.h"
 #include "device/fido/fido_constants.h"
 #include "device/fido/fido_parsing_utils.h"
 #include "device/fido/test_callback_receiver.h"
diff --git a/device/fido/ctap_get_assertion_request.h b/device/fido/ctap_get_assertion_request.h
index c92ae9f5..beda6ca 100644
--- a/device/fido/ctap_get_assertion_request.h
+++ b/device/fido/ctap_get_assertion_request.h
@@ -14,7 +14,7 @@
 #include "base/containers/span.h"
 #include "base/macros.h"
 #include "base/optional.h"
-#include "device/fido/fido_cable_discovery.h"
+#include "device/fido/cable/fido_cable_discovery.h"
 #include "device/fido/fido_constants.h"
 #include "device/fido/public_key_credential_descriptor.h"
 
diff --git a/device/fido/get_assertion_request_handler.cc b/device/fido/get_assertion_request_handler.cc
index bc300d8..b1ff520 100644
--- a/device/fido/get_assertion_request_handler.cc
+++ b/device/fido/get_assertion_request_handler.cc
@@ -9,8 +9,8 @@
 
 #include "base/bind.h"
 #include "device/fido/authenticator_get_assertion_response.h"
+#include "device/fido/cable/fido_cable_discovery.h"
 #include "device/fido/fido_authenticator.h"
-#include "device/fido/fido_cable_discovery.h"
 #include "device/fido/get_assertion_task.h"
 
 namespace device {
diff --git a/extensions/browser/api/networking_config/networking_config_service.cc b/extensions/browser/api/networking_config/networking_config_service.cc
index 4fff9e3..f14ba95 100644
--- a/extensions/browser/api/networking_config/networking_config_service.cc
+++ b/extensions/browser/api/networking_config/networking_config_service.cc
@@ -35,6 +35,18 @@
   return true;
 }
 
+std::string LookUpExtensionName(content::BrowserContext* context,
+                                std::string extension_id) {
+  extensions::ExtensionRegistry* extension_registry =
+      extensions::ExtensionRegistry::Get(context);
+  DCHECK(extension_registry);
+  const extensions::Extension* extension = extension_registry->GetExtensionById(
+      extension_id, extensions::ExtensionRegistry::ENABLED);
+  if (extension == nullptr)
+    return std::string();
+  return extension->name();
+}
+
 }  // namespace
 
 NetworkingConfigService::AuthenticationResult::AuthenticationResult()
@@ -97,18 +109,35 @@
   // Transform hex_ssid to uppercase.
   transform(hex_ssid.begin(), hex_ssid.end(), hex_ssid.begin(), toupper);
 
-  return hex_ssid_to_extension_id_.insert(make_pair(hex_ssid, extension_id))
-      .second;
+  // If |hex_ssid| is already in the map, i.e. if a hex ssid is already
+  // registered, this call should fail. TODO(stevenjb): Return an error code so
+  // that the extension API can respond with a better error.
+  if (!hex_ssid_to_extension_id_.insert(make_pair(hex_ssid, extension_id))
+           .second) {
+    LOG(ERROR) << "\'" << hex_ssid << "\' is already registered.";
+    return false;
+  }
+
+  chromeos::NetworkHandler::Get()
+      ->network_state_handler()
+      ->SetCaptivePortalProviderForHexSsid(
+          hex_ssid, extension_id,
+          LookUpExtensionName(browser_context_, extension_id));
+  return true;
 }
 
 void NetworkingConfigService::UnregisterExtension(
     const std::string& extension_id) {
   for (auto it = hex_ssid_to_extension_id_.begin();
        it != hex_ssid_to_extension_id_.end();) {
-    if (it->second == extension_id)
-      hex_ssid_to_extension_id_.erase(it++);
-    else
+    if (it->second == extension_id) {
+      chromeos::NetworkHandler::Get()
+          ->network_state_handler()
+          ->SetCaptivePortalProviderForHexSsid(it->first, "", "");
+      it = hex_ssid_to_extension_id_.erase(it);
+    } else {
       ++it;
+    }
   }
 }
 
diff --git a/extensions/browser/api/networking_config/networking_config_service_chromeos_unittest.cc b/extensions/browser/api/networking_config/networking_config_service_chromeos_unittest.cc
index a04f4f10..cfb4704d 100644
--- a/extensions/browser/api/networking_config/networking_config_service_chromeos_unittest.cc
+++ b/extensions/browser/api/networking_config/networking_config_service_chromeos_unittest.cc
@@ -6,6 +6,8 @@
 
 #include <utility>
 
+#include "chromeos/dbus/dbus_thread_manager.h"
+#include "chromeos/network/network_handler.h"
 #include "extensions/browser/api_unittest.h"
 #include "extensions/browser/extension_registry.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -45,6 +47,8 @@
 
   void SetUp() override {
     ApiUnitTest::SetUp();
+    chromeos::DBusThreadManager::Initialize();
+    chromeos::NetworkHandler::Initialize();
     extension_registry_ = std::unique_ptr<ExtensionRegistry>(
         new ExtensionRegistry(browser_context()));
     std::unique_ptr<MockEventDelegate> mock_event_delegate =
@@ -56,6 +60,12 @@
     DCHECK(service_);
   }
 
+  void TearDown() override {
+    chromeos::NetworkHandler::Shutdown();
+    chromeos::DBusThreadManager::Shutdown();
+    ApiUnitTest::TearDown();
+  }
+
  protected:
   std::unique_ptr<ExtensionRegistry> extension_registry_;
   std::unique_ptr<NetworkingConfigService> service_;
diff --git a/extensions/renderer/activity_log_converter_strategy.cc b/extensions/renderer/activity_log_converter_strategy.cc
index b6c07472..1663d15 100644
--- a/extensions/renderer/activity_log_converter_strategy.cc
+++ b/extensions/renderer/activity_log_converter_strategy.cc
@@ -24,19 +24,23 @@
       isolate, v8::Isolate::DisallowJavascriptExecutionScope::THROW_ON_FAILURE);
   v8::Local<v8::String> name = v8::String::NewFromUtf8(isolate, "[");
   if (object->IsFunction()) {
-    name =
-        v8::String::Concat(name, v8::String::NewFromUtf8(isolate, "Function"));
+    name = v8::String::Concat(isolate, name,
+                              v8::String::NewFromUtf8(isolate, "Function"));
     v8::Local<v8::Value> fname =
         v8::Local<v8::Function>::Cast(object)->GetName();
     if (fname->IsString() && v8::Local<v8::String>::Cast(fname)->Length()) {
-      name = v8::String::Concat(name, v8::String::NewFromUtf8(isolate, " "));
-      name = v8::String::Concat(name, v8::Local<v8::String>::Cast(fname));
-      name = v8::String::Concat(name, v8::String::NewFromUtf8(isolate, "()"));
+      name = v8::String::Concat(isolate, name,
+                                v8::String::NewFromUtf8(isolate, " "));
+      name =
+          v8::String::Concat(isolate, name, v8::Local<v8::String>::Cast(fname));
+      name = v8::String::Concat(isolate, name,
+                                v8::String::NewFromUtf8(isolate, "()"));
     }
   } else {
-    name = v8::String::Concat(name, object->GetConstructorName());
+    name = v8::String::Concat(isolate, name, object->GetConstructorName());
   }
-  name = v8::String::Concat(name, v8::String::NewFromUtf8(isolate, "]"));
+  name =
+      v8::String::Concat(isolate, name, v8::String::NewFromUtf8(isolate, "]"));
 
   if (try_catch.HasCaught()) {
     return std::unique_ptr<base::Value>(
diff --git a/extensions/renderer/module_system.cc b/extensions/renderer/module_system.cc
index a83c07e..a30a806 100644
--- a/extensions/renderer/module_system.cc
+++ b/extensions/renderer/module_system.cc
@@ -109,9 +109,9 @@
   v8::Local<v8::Object> obj = args.This();
   CHECK_EQ(2, args.Length());
   CHECK(args[0]->IsString());
-  v8::Maybe<bool> result =
-      obj->DefineOwnProperty(args.GetIsolate()->GetCurrentContext(),
-                             args[0]->ToString(), args[1], v8::ReadOnly);
+  v8::Maybe<bool> result = obj->DefineOwnProperty(
+      args.GetIsolate()->GetCurrentContext(),
+      args[0]->ToString(args.GetIsolate()), args[1], v8::ReadOnly);
   if (!result.FromMaybe(false))
     LOG(ERROR) << "Failed to set private property on the export.";
 }
@@ -656,8 +656,8 @@
       "$JSON, $Object, $RegExp, $String, $Error) {"
       "'use strict';");
   v8::Local<v8::String> right = ToV8StringUnsafe(GetIsolate(), "\n})");
-  return handle_scope.Escape(v8::Local<v8::String>(
-      v8::String::Concat(left, v8::String::Concat(source, right))));
+  return handle_scope.Escape(v8::Local<v8::String>(v8::String::Concat(
+      GetIsolate(), left, v8::String::Concat(GetIsolate(), source, right))));
 }
 
 void ModuleSystem::Private(const v8::FunctionCallbackInfo<v8::Value>& args) {
diff --git a/extensions/renderer/safe_builtins.cc b/extensions/renderer/safe_builtins.cc
index 24514d4..eac8522 100644
--- a/extensions/renderer/safe_builtins.cc
+++ b/extensions/renderer/safe_builtins.cc
@@ -182,7 +182,8 @@
     if (info[1]->IsObject()) {
       recv = v8::Local<v8::Object>::Cast(info[1]);
     } else if (info[1]->IsString()) {
-      recv = v8::StringObject::New(v8::Local<v8::String>::Cast(info[1]))
+      recv = v8::StringObject::New(info.GetIsolate(),
+                                   v8::Local<v8::String>::Cast(info[1]))
                  .As<v8::Object>();
     } else {
       info.GetIsolate()->ThrowException(
diff --git a/extensions/renderer/script_context.cc b/extensions/renderer/script_context.cc
index ff759b0..2616ca5f 100644
--- a/extensions/renderer/script_context.cc
+++ b/extensions/renderer/script_context.cc
@@ -428,7 +428,7 @@
   }
   std::string result;
   for (int i = 0; i < stack_trace->GetFrameCount(); ++i) {
-    v8::Local<v8::StackFrame> frame = stack_trace->GetFrame(i);
+    v8::Local<v8::StackFrame> frame = stack_trace->GetFrame(isolate(), i);
     CHECK(!frame.IsEmpty());
     result += base::StringPrintf(
         "\n    at %s (%s:%d:%d)",
diff --git a/gpu/command_buffer/service/gr_cache_controller.cc b/gpu/command_buffer/service/gr_cache_controller.cc
index 7708c6e..61717d8 100644
--- a/gpu/command_buffer/service/gr_cache_controller.cc
+++ b/gpu/command_buffer/service/gr_cache_controller.cc
@@ -47,8 +47,7 @@
   }
 
   context_state_->context->MakeCurrent(context_state_->surface.get());
-  context_state_->gr_context->purgeUnlockedResources(
-      false /* scratchResourcesOnly */);
+  context_state_->gr_context->freeGpuResources();
 }
 
 }  // namespace raster
diff --git a/headless/BUILD.gn b/headless/BUILD.gn
index 7070fd4..ad0ee65 100644
--- a/headless/BUILD.gn
+++ b/headless/BUILD.gn
@@ -930,6 +930,10 @@
   if (is_win) {
     deps += [ "//build/win:default_exe_manifest" ]
   }
+
+  if (is_mac) {
+    deps += [ "//sandbox/mac:seatbelt" ]
+  }
 }
 
 process_version("version_header") {
diff --git a/headless/app/DEPS b/headless/app/DEPS
index a3c5a9c..7646185 100644
--- a/headless/app/DEPS
+++ b/headless/app/DEPS
@@ -1,5 +1,6 @@
 include_rules = {
   "+cc/base/switches.h",
   "+components/viz/common/switches.h",
+  "+sandbox/mac",
 }
 
diff --git a/headless/app/headless_shell_main.cc b/headless/app/headless_shell_main.cc
index 5f63fcb..b8963e2 100644
--- a/headless/app/headless_shell_main.cc
+++ b/headless/app/headless_shell_main.cc
@@ -8,6 +8,9 @@
 #if defined(OS_WIN)
 #include "content/public/app/sandbox_helper_win.h"
 #include "sandbox/win/src/sandbox_types.h"
+#elif defined(OS_MACOSX)
+#include "base/logging.h"
+#include "sandbox/mac/seatbelt_exec.h"
 #endif
 
 int main(int argc, const char** argv) {
@@ -16,6 +19,15 @@
   content::InitializeSandboxInfo(&sandbox_info);
   return headless::HeadlessShellMain(0, &sandbox_info);
 #else
+#if defined(OS_MACOSX)
+  sandbox::SeatbeltExecServer::CreateFromArgumentsResult seatbelt =
+      sandbox::SeatbeltExecServer::CreateFromArguments(
+          argv[0], argc, const_cast<char**>(argv));
+  if (seatbelt.sandbox_required) {
+    CHECK(seatbelt.server->InitializeSandbox());
+  }
+#endif  // defined(OS_MACOSX)
+
   return headless::HeadlessShellMain(argc, argv);
 #endif  // defined(OS_WIN)
 }
diff --git a/infra/config/global/luci-milo.cfg b/infra/config/global/luci-milo.cfg
index 195acfa..65158e3 100644
--- a/infra/config/global/luci-milo.cfg
+++ b/infra/config/global/luci-milo.cfg
@@ -3456,6 +3456,18 @@
   refs: "refs/heads/master"
   manifest_name: "REVISION"
   builders {
+    name: "buildbot/chromium.webrtc/Android Builder"
+    name: "buildbucket/luci.webrtc.ci/Android Builder"
+    category: "android"
+    short_name: "bld"
+  }
+  builders {
+    name: "buildbot/chromium.webrtc/Android Tester"
+    name: "buildbucket/luci.webrtc.ci/Android Tester"
+    category: "android"
+    short_name: "tst"
+  }
+  builders {
     name: "buildbot/chromium.webrtc/Linux Builder"
     name: "buildbucket/luci.webrtc.ci/Linux Builder"
     category: "linux"
diff --git a/ios/chrome/browser/metrics/external_url_tab_usage_recorder_egtest.mm b/ios/chrome/browser/metrics/external_url_tab_usage_recorder_egtest.mm
index 6194416d..a24d7f0 100644
--- a/ios/chrome/browser/metrics/external_url_tab_usage_recorder_egtest.mm
+++ b/ios/chrome/browser/metrics/external_url_tab_usage_recorder_egtest.mm
@@ -29,8 +29,7 @@
 
 @implementation ExternalURLTabUsageRecorderTestCase
 
-// TODO(crbug.com/847948): This test is faling on devices.
-// TODO(crbug.com/852341): This test is faling on simulators.
+// TODO(crbug.com/852341): This test is failing on devices and simulators.
 // Verify correct recording of metrics when the reloading of an evicted tab
 // fails.
 - (void)DISABLED_testEvictedTabReloadFailure {
diff --git a/ios/chrome/browser/passwords/BUILD.gn b/ios/chrome/browser/passwords/BUILD.gn
index ecb64d3a..61423cf 100644
--- a/ios/chrome/browser/passwords/BUILD.gn
+++ b/ios/chrome/browser/passwords/BUILD.gn
@@ -73,7 +73,6 @@
     "//ios/chrome/app/strings",
     "//ios/chrome/app/theme",
     "//ios/chrome/browser",
-    "//ios/chrome/browser/autofill",
     "//ios/chrome/browser/browser_state",
     "//ios/chrome/browser/infobars",
     "//ios/chrome/browser/signin",
diff --git a/ios/chrome/browser/sync/ios_chrome_sync_client.mm b/ios/chrome/browser/sync/ios_chrome_sync_client.mm
index 4a63231..d534ef2 100644
--- a/ios/chrome/browser/sync/ios_chrome_sync_client.mm
+++ b/ios/chrome/browser/sync/ios_chrome_sync_client.mm
@@ -13,7 +13,9 @@
 #include "components/autofill/core/browser/webdata/autocomplete_sync_bridge.h"
 #include "components/autofill/core/browser/webdata/autofill_profile_sync_bridge.h"
 #include "components/autofill/core/browser/webdata/autofill_profile_syncable_service.h"
+#include "components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge.h"
 #include "components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service.h"
+#include "components/autofill/core/browser/webdata/autofill_wallet_sync_bridge.h"
 #include "components/autofill/core/browser/webdata/autofill_wallet_syncable_service.h"
 #include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
 #include "components/browser_sync/browser_sync_switches.h"
@@ -350,6 +352,18 @@
                  web_data_service_.get())
           ->change_processor()
           ->GetControllerDelegateOnUIThread();
+    case syncer::AUTOFILL_WALLET_DATA: {
+      return autofill::AutofillWalletSyncBridge::FromWebDataService(
+                 web_data_service_.get())
+          ->change_processor()
+          ->GetControllerDelegateOnUIThread();
+    }
+    case syncer::AUTOFILL_WALLET_METADATA: {
+      return autofill::AutofillWalletMetadataSyncBridge::FromWebDataService(
+                 web_data_service_.get())
+          ->change_processor()
+          ->GetControllerDelegateOnUIThread();
+    }
     case syncer::TYPED_URLS: {
       history::HistoryService* history =
           ios::HistoryServiceFactory::GetForBrowserState(
diff --git a/ios/chrome/browser/ui/collection_view/cells/collection_view_cell_constants.h b/ios/chrome/browser/ui/collection_view/cells/collection_view_cell_constants.h
index 7c4ee4f..a796ed3 100644
--- a/ios/chrome/browser/ui/collection_view/cells/collection_view_cell_constants.h
+++ b/ios/chrome/browser/ui/collection_view/cells/collection_view_cell_constants.h
@@ -16,11 +16,11 @@
 
 // The font size and color to use for detail text that is on the trailing edge
 // of the top line.
-const int kUIKitDetailTextColor = 0x8E8E93;
+const int kUIKitDetailTextColor = 0x767676;
 const CGFloat kUIKitDetailFontSize = 17;
 
 // The font size and color to use for detail text that is on its own line.
-const int kUIKitMultilineDetailTextColor = 0x8E8E93;
+const int kUIKitMultilineDetailTextColor = 0x767676;
 const CGFloat kUIKitMultilineDetailFontSize = 12;
 
 // The font size and color to use for footer text in UIKit-style cells.
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_cell.mm b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_cell.mm
index 6dd085d..52155e6 100644
--- a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_cell.mm
+++ b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_cell.mm
@@ -122,7 +122,7 @@
     _faviconView.font = [[MDCTypography fontLoader] mediumFontOfSize:10];
     if (IsUIRefreshPhase1Enabled()) {
       _additionalInformationLabel.textColor =
-          [UIColor colorWithWhite:0 alpha:0.4];
+          [UIColor colorWithWhite:0 alpha:0.54];
     } else {
       _additionalInformationLabel.textColor =
           [[MDCPalette greyPalette] tint700];
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_constants.mm b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_constants.mm
index 8d30ced..7e62bfa9 100644
--- a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_constants.mm
+++ b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_constants.mm
@@ -13,4 +13,4 @@
 const NSInteger kLabelNumLines = 2;
 const CGFloat kSpaceIconTitle = 10;
 const CGSize kCellSize = {73, 100};
-const CGFloat kTitleAlpha = 0.41;
+const CGFloat kTitleAlpha = 0.54;
diff --git a/ios/chrome/browser/ui/history/history_table_view_controller.mm b/ios/chrome/browser/ui/history/history_table_view_controller.mm
index 627b9bde..7bf194f 100644
--- a/ios/chrome/browser/ui/history/history_table_view_controller.mm
+++ b/ios/chrome/browser/ui/history/history_table_view_controller.mm
@@ -62,6 +62,8 @@
 const int kMaxFetchCount = 100;
 // Separation space between sections.
 const CGFloat kSeparationSpaceBetweenSections = 9;
+// The Alpha value used by the SearchBar when disabled.
+const CGFloat kAlphaForDisabledSearchBar = 0.5;
 }  // namespace
 
 @interface HistoryTableViewController ()<HistoryEntriesStatusItemDelegate,
@@ -848,6 +850,8 @@
     self.clearBrowsingDataButton, spaceButton, self.editButton
   ]
                animated:animated];
+  [self.searchController.searchBar setUserInteractionEnabled:YES];
+  self.searchController.searchBar.alpha = 1.0;
   [self updateToolbarButtons];
 }
 
@@ -860,6 +864,8 @@
                            action:nil];
   [self setToolbarItems:@[ self.deleteButton, spaceButton, self.cancelButton ]
                animated:animated];
+  [self.searchController.searchBar setUserInteractionEnabled:NO];
+  self.searchController.searchBar.alpha = kAlphaForDisabledSearchBar;
   [self updateToolbarButtons];
 }
 
diff --git a/ios/chrome/browser/ui/omnibox/omnibox_coordinator.mm b/ios/chrome/browser/ui/omnibox/omnibox_coordinator.mm
index 6658a656..74e7732 100644
--- a/ios/chrome/browser/ui/omnibox/omnibox_coordinator.mm
+++ b/ios/chrome/browser/ui/omnibox/omnibox_coordinator.mm
@@ -5,6 +5,7 @@
 #import "ios/chrome/browser/ui/omnibox/omnibox_coordinator.h"
 
 #include "base/logging.h"
+#include "base/strings/sys_string_conversions.h"
 #include "components/omnibox/browser/omnibox_edit_model.h"
 #include "components/strings/grit/components_strings.h"
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
@@ -12,6 +13,7 @@
 #import "ios/chrome/browser/ui/location_bar/location_bar_constants.h"
 #import "ios/chrome/browser/ui/omnibox/omnibox_mediator.h"
 #import "ios/chrome/browser/ui/omnibox/omnibox_text_field_ios.h"
+#include "ios/chrome/browser/ui/omnibox/omnibox_util.h"
 #include "ios/chrome/browser/ui/omnibox/omnibox_view_controller.h"
 #include "ios/chrome/browser/ui/omnibox/omnibox_view_ios.h"
 #import "ios/chrome/browser/ui/omnibox/popup/omnibox_popup_coordinator.h"
@@ -54,6 +56,19 @@
 
   self.viewController =
       [[OmniboxViewController alloc] initWithIncognito:isIncognito];
+  std::string defaultLeadingImageName = GetResourceNameForAutocompleteMatchType(
+      AutocompleteMatchType::URL_WHAT_YOU_TYPED, /* is_starred */ false);
+  UIImage* defaultLeadingImage =
+      [[UIImage imageNamed:base::SysUTF8ToNSString(defaultLeadingImageName)]
+          imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
+  self.viewController.defaultLeadingImage = defaultLeadingImage;
+  std::string defaultEmptyOmniboxLeadingImageName =
+      GetResourceNameForAutocompleteMatchType(
+          AutocompleteMatchType::SEARCH_SUGGEST, /* is_starred */ false);
+  UIImage* defaultEmptyOmniboxLeadingImage = [[UIImage
+      imageNamed:base::SysUTF8ToNSString(defaultEmptyOmniboxLeadingImageName)]
+      imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
+  self.viewController.emptyTextLeadingImage = defaultEmptyOmniboxLeadingImage;
 
   self.viewController.dispatcher =
       static_cast<id<LoadQueryCommands, OmniboxFocuser>>(self.dispatcher);
diff --git a/ios/chrome/browser/ui/omnibox/omnibox_view_controller.h b/ios/chrome/browser/ui/omnibox/omnibox_view_controller.h
index c6936d22..8aeaa26 100644
--- a/ios/chrome/browser/ui/omnibox/omnibox_view_controller.h
+++ b/ios/chrome/browser/ui/omnibox/omnibox_view_controller.h
@@ -21,6 +21,13 @@
 // The textfield used by this view controller.
 @property(nonatomic, readonly, strong) OmniboxTextFieldIOS* textField;
 
+// The default leading image to be used on omnibox focus before this is updated
+// via OmniboxConsumer protocol.
+@property(nonatomic, strong) UIImage* defaultLeadingImage;
+
+// The default leading image to be used whenever the omnibox text is empty.
+@property(nonatomic, strong) UIImage* emptyTextLeadingImage;
+
 // Designated initializer.
 - (instancetype)initWithIncognito:(BOOL)isIncognito;
 
diff --git a/ios/chrome/browser/ui/omnibox/omnibox_view_controller.mm b/ios/chrome/browser/ui/omnibox/omnibox_view_controller.mm
index 8633c9c..a5a20a9 100644
--- a/ios/chrome/browser/ui/omnibox/omnibox_view_controller.mm
+++ b/ios/chrome/browser/ui/omnibox/omnibox_view_controller.mm
@@ -37,6 +37,8 @@
 @implementation OmniboxViewController
 @synthesize incognito = _incognito;
 @synthesize dispatcher = _dispatcher;
+@synthesize defaultLeadingImage = _defaultLeadingImage;
+@synthesize emptyTextLeadingImage = _emptyTextLeadingImage;
 @dynamic view;
 
 - (instancetype)initWithIncognito:(BOOL)isIncognito {
@@ -92,6 +94,11 @@
          selector:@selector(textFieldDidBeginEditing)
              name:UITextFieldTextDidBeginEditingNotification
            object:self.textField];
+  [[NSNotificationCenter defaultCenter]
+      addObserver:self
+         selector:@selector(textFieldDidChange)
+             name:UITextFieldTextDidChangeNotification
+           object:self.textField];
 }
 
 - (void)traitCollectionDidChange:(UITraitCollection*)previousTraitCollection {
@@ -135,6 +142,16 @@
 - (void)textFieldDidBeginEditing {
   // Update the clear button state.
   [self updateClearButtonVisibility];
+  [self.view setLeadingImage:self.textField.text.length
+                                 ? self.defaultLeadingImage
+                                 : self.emptyTextLeadingImage];
+}
+
+- (void)textFieldDidChange {
+  // If the text is empty, update the leading image.
+  if (self.textField.text.length == 0) {
+    [self.view setLeadingImage:self.emptyTextLeadingImage];
+  }
 }
 
 #pragma mark clear button
@@ -185,6 +202,7 @@
     // Calling setText: does not trigger UIControlEventEditingChanged, so update
     // the clear button visibility manually.
     [self updateClearButtonVisibility];
+    [self textFieldDidChange];
   }
 }
 
diff --git a/ios/chrome/browser/ui/settings/sync_encryption_passphrase_collection_view_controller.mm b/ios/chrome/browser/ui/settings/sync_encryption_passphrase_collection_view_controller.mm
index 5e1d5218..54d9c98 100644
--- a/ios/chrome/browser/ui/settings/sync_encryption_passphrase_collection_view_controller.mm
+++ b/ios/chrome/browser/ui/settings/sync_encryption_passphrase_collection_view_controller.mm
@@ -326,12 +326,13 @@
   CollectionViewItem* item =
       [self.collectionViewModel itemAtIndexPath:indexPath];
   if (item.type == ItemTypeMessage) {
-    CardMultilineCell* messageCell =
-        base::mac::ObjCCastStrict<CardMultilineCell>(cell);
-    if (experimental_flags::IsSettingsUIRebootEnabled()) {
-      messageCell.textLabel.font =
-          [UIFont boldSystemFontOfSize:kUIKitMainFontSize];
-    } else {
+    // Changing the font weight may reflow the text onto a different number of
+    // lines, but the collection view doesn't know that it needs to layout the
+    // cell again. Sidestep this bug by leaving the font at a normal weight
+    // under UIRefresh.
+    if (!experimental_flags::IsSettingsUIRebootEnabled()) {
+      CardMultilineCell* messageCell =
+          base::mac::ObjCCastStrict<CardMultilineCell>(cell);
       messageCell.textLabel.font =
           [[MDCTypography fontLoader] mediumFontOfSize:14];
     }
diff --git a/ios/third_party/firebase/.gitignore b/ios/third_party/firebase/.gitignore
new file mode 100644
index 0000000..0354386
--- /dev/null
+++ b/ios/third_party/firebase/.gitignore
@@ -0,0 +1,3 @@
+/Analytics
+/NOTICES
+/README.md
diff --git a/ios/web/web_state/ui/crw_web_controller.mm b/ios/web/web_state/ui/crw_web_controller.mm
index 4e48ec8..2abad79 100644
--- a/ios/web/web_state/ui/crw_web_controller.mm
+++ b/ios/web/web_state/ui/crw_web_controller.mm
@@ -4987,10 +4987,6 @@
                                   NSURLCredential*))completionHandler {
   [self didReceiveWebViewNavigationDelegateCallback];
 
-  // This callback should never be triggered for placeholder navigations.
-  DCHECK(!(web::GetWebClient()->IsSlimNavigationManagerEnabled() &&
-           IsPlaceholderUrl(net::GURLWithNSURL(webView.URL))));
-
   NSString* authMethod = challenge.protectionSpace.authenticationMethod;
   if ([authMethod isEqual:NSURLAuthenticationMethodHTTPBasic] ||
       [authMethod isEqual:NSURLAuthenticationMethodNTLM] ||
diff --git a/net/third_party/spdy/core/priority_write_scheduler.h b/net/third_party/spdy/core/priority_write_scheduler.h
index ba75f3ac..7738c7a 100644
--- a/net/third_party/spdy/core/priority_write_scheduler.h
+++ b/net/third_party/spdy/core/priority_write_scheduler.h
@@ -250,8 +250,7 @@
   // Returns the number of ready streams.
   size_t NumReadyStreams() const override { return num_ready_streams_; }
 
-  // This function is used for debugging and test only. Returns true if a stream
-  // is ready.
+  // Returns true if a stream is ready.
   bool IsStreamReady(StreamIdType stream_id) const {
     auto it = stream_infos_.find(stream_id);
     if (it == stream_infos_.end()) {
diff --git a/rlz/lib/rlz_lib.cc b/rlz/lib/rlz_lib.cc
index d61189ad..493ae90 100644
--- a/rlz/lib/rlz_lib.cc
+++ b/rlz/lib/rlz_lib.cc
@@ -395,6 +395,18 @@
                        const char* product_brand,
                        const char* product_id,
                        const char* product_lang,
+                       bool exclude_machine_id) {
+  return SendFinancialPing(product, access_points, product_signature,
+                           product_brand, product_id, product_lang,
+                           exclude_machine_id, false);
+}
+
+bool SendFinancialPing(Product product,
+                       const AccessPoint* access_points,
+                       const char* product_signature,
+                       const char* product_brand,
+                       const char* product_id,
+                       const char* product_lang,
                        bool exclude_machine_id,
                        const bool skip_time_check) {
   // Create the financial ping request.  To support ChromeOS retries, the
diff --git a/rlz/lib/rlz_lib.h b/rlz/lib/rlz_lib.h
index 9bc942f..886bd0c 100644
--- a/rlz/lib/rlz_lib.h
+++ b/rlz/lib/rlz_lib.h
@@ -194,7 +194,6 @@
 // product_lang       : The language for the product (used to determine cohort).
 // exclude_machine_id : Whether the Machine ID should be explicitly excluded
 //                      based on the products privacy policy.
-// skip_time_check    : Whether the timing check.
 //
 // Returns true on successful ping and response, false otherwise.
 // Access: HKCU write.
@@ -204,6 +203,16 @@
                                    const char* product_brand,
                                    const char* product_id,
                                    const char* product_lang,
+                                   bool exclude_machine_id);
+
+// An alternate implementations of SendFinancialPing with the same behavior,
+// except the caller can optionally choose to skip the timing check.
+bool RLZ_LIB_API SendFinancialPing(Product product,
+                                   const AccessPoint* access_points,
+                                   const char* product_signature,
+                                   const char* product_brand,
+                                   const char* product_id,
+                                   const char* product_lang,
                                    bool exclude_machine_id,
                                    const bool skip_time_check);
 
diff --git a/services/identity/public/cpp/identity_manager.cc b/services/identity/public/cpp/identity_manager.cc
index 285f46b..4d3c7166 100644
--- a/services/identity/public/cpp/identity_manager.cc
+++ b/services/identity/public/cpp/identity_manager.cc
@@ -305,21 +305,24 @@
     account_info.gaia = kSupervisedUserPseudoGaiaID;
   }
 
-  // Insert the account into |accounts_with_refresh_tokens_|.
-  auto insertion_result = accounts_with_refresh_tokens_.emplace(
-      account_id, std::move(account_info));
-
-  // The account might have already been  present (e.g., this method can fire on
+  // The account might have already been present (e.g., this method can fire on
   // updating an invalid token to a valid one or vice versa); in this case we
   // sanity-check that the cached account info has the expected values.
-  if (!insertion_result.second) {
-    AccountInfo cached_account_info = insertion_result.first->second;
-    DCHECK_EQ(account_info.gaia, cached_account_info.gaia);
-    DCHECK_EQ(account_info.email, cached_account_info.email);
+  auto iterator = accounts_with_refresh_tokens_.find(account_id);
+  if (iterator != accounts_with_refresh_tokens_.end()) {
+    DCHECK_EQ(account_info.gaia, iterator->second.gaia);
+    DCHECK(gaia::AreEmailsSame(account_info.email, iterator->second.email));
+  } else {
+    auto insertion_result = accounts_with_refresh_tokens_.emplace(
+        account_id, std::move(account_info));
+    DCHECK(insertion_result.second);
+    iterator = insertion_result.first;
   }
 
+  // Use iterator instead of account_info as it may have been moved, thus is
+  // invalid to use.
   for (auto& observer : observer_list_) {
-    observer.OnRefreshTokenUpdatedForAccount(account_info, is_valid);
+    observer.OnRefreshTokenUpdatedForAccount(iterator->second, is_valid);
   }
 }
 
diff --git a/testing/buildbot/filters/mash.browser_tests.filter b/testing/buildbot/filters/mash.browser_tests.filter
index 184cd337..c4293c7 100644
--- a/testing/buildbot/filters/mash.browser_tests.filter
+++ b/testing/buildbot/filters/mash.browser_tests.filter
@@ -44,6 +44,9 @@
 -HostedAppNonClientFrameViewAshTest.*
 -HomeLauncherBrowserNonClientFrameViewAshTest.*
 
+BrowserNonClientFrameViewAshTest.NonClientHitTest*
+BrowserNonClientFrameViewAshTest.AvatarMenuButtonHitTest*
+
 # Fix immersive fullscreen mode in mash. https://crbug.com/844748.
 -ImmersiveModeBrowserViewTest.TestCaptionButtonsReceiveEventsInAppImmersiveMode*
 -ImmersiveModeBrowserViewTest.TestCaptionButtonsReceiveEventsInBrowserImmersiveMode*
@@ -177,8 +180,10 @@
 -MultiAuthEnrollmentScreenTest.*
 -ProvisionedEnrollmentScreenTest.*
 
-# VPN item not in system tray.
--NetworkingConfigDelegateChromeosTest.*
+# Ash currently uses its own NetworkHandler instance so the
+# captive_portal_provider_ member of networkState is not set correctly.
+# https://crbug.com/862420
+-NetworkingConfigChromeosTest.SystemTrayItem
 
 # Timeout device_event_log_impl.cc(156) Network: network_portal_detector_impl.cc:486 Portal detection timeout:  name= id=
 -NetworkingConfigTest.*
diff --git a/testing/buildbot/filters/viz.content_browsertests.filter b/testing/buildbot/filters/viz.content_browsertests.filter
index bf0ea54..c961980b 100644
--- a/testing/buildbot/filters/viz.content_browsertests.filter
+++ b/testing/buildbot/filters/viz.content_browsertests.filter
@@ -1,7 +1 @@
 ### Mac
-# BrowserSideFlingBrowserTest timing out https://crbug.com/842325
--BrowserSideFlingBrowserTest.AutoscrollFling
--BrowserSideFlingBrowserTest.TouchpadFling
--BrowserSideFlingBrowserTest.TouchscreenFling
--SitePerProcessBrowserTest.TouchpadGestureFlingStart
--SitePerProcessBrowserTest.TouchscreenGestureFlingStart
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
index 341eee0f..6d37ab4 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
@@ -723,8 +723,6 @@
 crbug.com/591099 storage/indexeddb/mozilla/test_objectStore_openKeyCursor.html [ Timeout ]
 crbug.com/591099 storage/indexeddb/objectstore-cursor.html [ Pass ]
 crbug.com/591099 storage/indexeddb/objectstore-keycursor.html [ Timeout ]
-crbug.com/591099 svg/as-border-image/svg-as-border-image-2.html [ Failure ]
-crbug.com/591099 svg/as-border-image/svg-as-border-image.html [ Failure ]
 crbug.com/591099 svg/custom/object-sizing-no-width-height.xhtml [ Failure ]
 crbug.com/591099 svg/filters/feTurbulence-bad-seeds.html [ Failure ]
 crbug.com/591099 svg/in-html/sizing/svg-inline.html [ Failure ]
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index 206b772..76c80984 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -2642,7 +2642,7 @@
 crbug.com/828506 [ Linux Win ] virtual/mouseevent_fractional/fast/events/touch/scroll-without-mouse-lacks-mousemove-events.html [ Pass Failure ]
 crbug.com/828506 [ Linux Win ] virtual/scroll_customization/fast/events/touch/scroll-without-mouse-lacks-mousemove-events.html [ Pass Failure ]
 crbug.com/828506 [ Linux Win ] virtual/user-activation-v2/fast/events/touch/scroll-without-mouse-lacks-mousemove-events.html [ Pass Failure ]
-
+crbug.com/828506 [ Linux Win ] virtual/paint-touchaction-rects/fast/events/touch/scroll-without-mouse-lacks-mousemove-events.html [ Failure Pass ]
 
 # Failure messages are unstable so we cannot create baselines.
 crbug.com/832071 external/wpt/service-workers/service-worker/worker-client-id.https.html [ Failure ]
@@ -4670,6 +4670,7 @@
 
 ### virtual/gpu/fast/canvas/ blending layout tests timeout
 crbug.com/866850 [ Linux Mac ] virtual/gpu/fast/canvas/canvas-blend-image.html [ Pass Timeout ]
+crbug.com/866850 [ Linux Mac ] virtual/gpu/fast/canvas/canvas-blending-color-over-image.html [ Pass Timeout ]
 crbug.com/866850 [ Linux Mac ] virtual/gpu/fast/canvas/canvas-blending-gradient-over-image.html [ Pass Timeout ]
 crbug.com/866850 [ Linux Mac ] virtual/gpu/fast/canvas/canvas-blending-image-over-image.html [ Pass Timeout ]
 crbug.com/866850 [ Linux Mac ] virtual/gpu/fast/canvas/canvas-blending-pattern-over-color.html [ Pass Timeout ]
@@ -4682,4 +4683,3 @@
 crbug.com/866965 [ Linux ] virtual/outofblink-cors-ns/external/wpt/service-workers/service-worker/interfaces-sw.https.html [ Timeout Pass ]
 crbug.com/866965 [ Linux ] virtual/outofblink-cors/external/wpt/service-workers/service-worker/interfaces-sw.https.html [ Timeout Pass ]
 crbug.com/866965 [ Linux ] virtual/service-worker-servicification/external/wpt/service-workers/service-worker/interfaces-sw.https.html [ Timeout Pass ]
-crbug.com/867181 [ Win10 ] virtual/paint-touchaction-rects/fast/events/touch/scroll-without-mouse-lacks-mousemove-events.html [ Failure Pass ]
diff --git a/third_party/WebKit/LayoutTests/compositing/rtl/rtl-iframe-absolute-overflow-expected.png b/third_party/WebKit/LayoutTests/compositing/rtl/rtl-iframe-absolute-overflow-expected.png
index 0ec8463..b37b180 100644
--- a/third_party/WebKit/LayoutTests/compositing/rtl/rtl-iframe-absolute-overflow-expected.png
+++ b/third_party/WebKit/LayoutTests/compositing/rtl/rtl-iframe-absolute-overflow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/compositing/rtl/rtl-iframe-absolute-overflow-expected.txt b/third_party/WebKit/LayoutTests/compositing/rtl/rtl-iframe-absolute-overflow-expected.txt
index 4fb10f76..e6cb740 100644
--- a/third_party/WebKit/LayoutTests/compositing/rtl/rtl-iframe-absolute-overflow-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/rtl/rtl-iframe-absolute-overflow-expected.txt
@@ -29,11 +29,13 @@
     },
     {
       "name": "Scrolling Layer",
+      "position": [15, 0],
       "bounds": [385, 385],
       "drawsContent": false
     },
     {
       "name": "Scrolling Contents Layer",
+      "position": [15, 0],
       "bounds": [1000, 1000],
       "backgroundColor": "#FF0000",
       "transform": 1
@@ -52,19 +54,18 @@
     },
     {
       "name": "Horizontal Scrollbar Layer",
-      "position": [0, 385],
+      "position": [15, 385],
       "bounds": [385, 15],
       "drawsContent": false
     },
     {
       "name": "Vertical Scrollbar Layer",
-      "position": [385, 0],
       "bounds": [15, 385],
       "drawsContent": false
     },
     {
       "name": "Scroll Corner Layer",
-      "position": [385, 385],
+      "position": [0, 385],
       "bounds": [15, 15]
     }
   ],
@@ -86,7 +87,7 @@
         [1, 0, 0, 0],
         [0, 1, 0, 0],
         [0, 0, 1, 0],
-        [665, 50, 0, 1]
+        [680, 50, 0, 1]
       ]
     }
   ]
diff --git a/third_party/WebKit/LayoutTests/compositing/rtl/rtl-iframe-absolute-overflow-scrolled-expected.png b/third_party/WebKit/LayoutTests/compositing/rtl/rtl-iframe-absolute-overflow-scrolled-expected.png
index f3ec1ff5..d034ccea 100644
--- a/third_party/WebKit/LayoutTests/compositing/rtl/rtl-iframe-absolute-overflow-scrolled-expected.png
+++ b/third_party/WebKit/LayoutTests/compositing/rtl/rtl-iframe-absolute-overflow-scrolled-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/compositing/rtl/rtl-iframe-absolute-overflow-scrolled-expected.txt b/third_party/WebKit/LayoutTests/compositing/rtl/rtl-iframe-absolute-overflow-scrolled-expected.txt
index 5f9aae9e..bfb7bb0 100644
--- a/third_party/WebKit/LayoutTests/compositing/rtl/rtl-iframe-absolute-overflow-scrolled-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/rtl/rtl-iframe-absolute-overflow-scrolled-expected.txt
@@ -29,11 +29,13 @@
     },
     {
       "name": "Scrolling Layer",
+      "position": [15, 0],
       "bounds": [385, 385],
       "drawsContent": false
     },
     {
       "name": "Scrolling Contents Layer",
+      "position": [15, 0],
       "bounds": [1000, 1000],
       "backgroundColor": "#FF0000",
       "transform": 1
@@ -52,19 +54,18 @@
     },
     {
       "name": "Horizontal Scrollbar Layer",
-      "position": [0, 385],
+      "position": [15, 385],
       "bounds": [385, 15],
       "drawsContent": false
     },
     {
       "name": "Vertical Scrollbar Layer",
-      "position": [385, 0],
       "bounds": [15, 385],
       "drawsContent": false
     },
     {
       "name": "Scroll Corner Layer",
-      "position": [385, 385],
+      "position": [0, 385],
       "bounds": [15, 15]
     }
   ],
@@ -86,7 +87,7 @@
         [1, 0, 0, 0],
         [0, 1, 0, 0],
         [0, 0, 1, 0],
-        [51, 50, 0, 1]
+        [66, 50, 0, 1]
       ]
     }
   ]
diff --git a/third_party/WebKit/LayoutTests/compositing/rtl/rtl-iframe-fixed-overflow-expected.png b/third_party/WebKit/LayoutTests/compositing/rtl/rtl-iframe-fixed-overflow-expected.png
index 0ec8463..b37b180 100644
--- a/third_party/WebKit/LayoutTests/compositing/rtl/rtl-iframe-fixed-overflow-expected.png
+++ b/third_party/WebKit/LayoutTests/compositing/rtl/rtl-iframe-fixed-overflow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/compositing/rtl/rtl-iframe-fixed-overflow-expected.txt b/third_party/WebKit/LayoutTests/compositing/rtl/rtl-iframe-fixed-overflow-expected.txt
index 17e7b97..2c2c0e57 100644
--- a/third_party/WebKit/LayoutTests/compositing/rtl/rtl-iframe-fixed-overflow-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/rtl/rtl-iframe-fixed-overflow-expected.txt
@@ -29,18 +29,20 @@
     },
     {
       "name": "Scrolling Layer",
+      "position": [15, 0],
       "bounds": [385, 385],
       "drawsContent": false
     },
     {
       "name": "Scrolling Contents Layer",
+      "position": [15, 0],
       "bounds": [1000, 1000],
       "backgroundColor": "#FF0000",
       "transform": 1
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='positioned indicator'",
-      "position": [665, 50],
+      "position": [680, 50],
       "bounds": [100, 100],
       "contentsOpaque": true,
       "backgroundColor": "#FF0000",
@@ -60,19 +62,18 @@
     },
     {
       "name": "Horizontal Scrollbar Layer",
-      "position": [0, 385],
+      "position": [15, 385],
       "bounds": [385, 15],
       "drawsContent": false
     },
     {
       "name": "Vertical Scrollbar Layer",
-      "position": [385, 0],
       "bounds": [15, 385],
       "drawsContent": false
     },
     {
       "name": "Scroll Corner Layer",
-      "position": [385, 385],
+      "position": [0, 385],
       "bounds": [15, 15]
     }
   ],
@@ -94,7 +95,7 @@
         [1, 0, 0, 0],
         [0, 1, 0, 0],
         [0, 0, 1, 0],
-        [665, 50, 0, 1]
+        [680, 50, 0, 1]
       ]
     }
   ]
diff --git a/third_party/WebKit/LayoutTests/compositing/rtl/rtl-iframe-fixed-overflow-scrolled-expected.png b/third_party/WebKit/LayoutTests/compositing/rtl/rtl-iframe-fixed-overflow-scrolled-expected.png
index f3ec1ff5..d034ccea 100644
--- a/third_party/WebKit/LayoutTests/compositing/rtl/rtl-iframe-fixed-overflow-scrolled-expected.png
+++ b/third_party/WebKit/LayoutTests/compositing/rtl/rtl-iframe-fixed-overflow-scrolled-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/compositing/rtl/rtl-iframe-fixed-overflow-scrolled-expected.txt b/third_party/WebKit/LayoutTests/compositing/rtl/rtl-iframe-fixed-overflow-scrolled-expected.txt
index 17e7b97..2c2c0e57 100644
--- a/third_party/WebKit/LayoutTests/compositing/rtl/rtl-iframe-fixed-overflow-scrolled-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/rtl/rtl-iframe-fixed-overflow-scrolled-expected.txt
@@ -29,18 +29,20 @@
     },
     {
       "name": "Scrolling Layer",
+      "position": [15, 0],
       "bounds": [385, 385],
       "drawsContent": false
     },
     {
       "name": "Scrolling Contents Layer",
+      "position": [15, 0],
       "bounds": [1000, 1000],
       "backgroundColor": "#FF0000",
       "transform": 1
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='positioned indicator'",
-      "position": [665, 50],
+      "position": [680, 50],
       "bounds": [100, 100],
       "contentsOpaque": true,
       "backgroundColor": "#FF0000",
@@ -60,19 +62,18 @@
     },
     {
       "name": "Horizontal Scrollbar Layer",
-      "position": [0, 385],
+      "position": [15, 385],
       "bounds": [385, 15],
       "drawsContent": false
     },
     {
       "name": "Vertical Scrollbar Layer",
-      "position": [385, 0],
       "bounds": [15, 385],
       "drawsContent": false
     },
     {
       "name": "Scroll Corner Layer",
-      "position": [385, 385],
+      "position": [0, 385],
       "bounds": [15, 15]
     }
   ],
@@ -94,7 +95,7 @@
         [1, 0, 0, 0],
         [0, 1, 0, 0],
         [0, 0, 1, 0],
-        [665, 50, 0, 1]
+        [680, 50, 0, 1]
       ]
     }
   ]
diff --git a/third_party/WebKit/LayoutTests/external/wpt/pointerlock/mouse_buttons_back_forward-manual.html b/third_party/WebKit/LayoutTests/external/wpt/pointerlock/mouse_buttons_back_forward-manual.html
new file mode 100644
index 0000000..06e0a5da
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/pointerlock/mouse_buttons_back_forward-manual.html
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <meta charset="utf-8" />
+        <title>Mouse Button Back/Forward</title>
+        <link rel="author" title="Google" href="http://www.google.com/" />
+        <script src="/resources/testharness.js"></script>
+        <script src="/resources/testharnessreport.js"></script>
+        <script>
+            var testMouseUp = async_test('Tests that when pointer is locked, the mouseup is preventable.');
+            var received_back = false;
+            var received_forward = false;
+            window.addEventListener('mouseup', function(e) {
+              if (e.button == 0) {
+                document.body.requestPointerLock();
+              } else if (e.button == 3) {
+                received_back = true;
+                e.preventDefault();
+              } else if (e.button == 4) {
+                received_forward = true;
+                e.preventDefault();
+              }
+              if (document.pointerLockElement && received_back && received_forward) {
+                testMouseUp.done();
+                document.exitPointerLock();
+              }
+            });
+
+        </script>
+
+    </head>
+    <body id="target">
+        <h4>Test Description: Tests that the mouseup event is prevented.
+            <ol>
+                <li>Click the left mouse button to lock pointer</li>
+                <li>Click the back mouse button</li>
+                <li>Click the back mouse forward</li>
+            </ol>
+        </h4>
+    </body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt_automation/pointerlock/mouse_buttons_back_forward-manual-automation.js b/third_party/WebKit/LayoutTests/external/wpt_automation/pointerlock/mouse_buttons_back_forward-manual-automation.js
new file mode 100644
index 0000000..d259f6db7
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt_automation/pointerlock/mouse_buttons_back_forward-manual-automation.js
@@ -0,0 +1,8 @@
+importAutomationScript('/pointerevents/pointerevent_common_input.js');
+function inject_input() {
+  return mouseClickInTarget('#target', undefined, "left").then(function() {
+    return mouseClickInTarget('#target', undefined, "back").then(function() {
+      return mouseClickInTarget('#target', undefined, "forward");
+    });
+  });
+}
diff --git a/third_party/WebKit/LayoutTests/fast/events/touch/gesture/gesture-tap-frame-overlap.html b/third_party/WebKit/LayoutTests/fast/events/touch/gesture/gesture-tap-frame-overlap.html
new file mode 100644
index 0000000..5fa3516
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/events/touch/gesture/gesture-tap-frame-overlap.html
@@ -0,0 +1,60 @@
+<!DOCTYPE html>
+<html>
+<script src="../../../../resources/testharness.js"></script>
+<script src="../../../../resources/testharnessreport.js"></script>
+<script src="../../../../resources/gesture-util.js"></script>
+<style type="text/css">
+body {
+    margin: 0;
+}
+#box1{
+  position: fixed;
+  bottom: 96px;
+  left: 0;
+  right: 0;
+  height: 100px;
+  background-color: #1976D2;
+  z-index: 101;
+}
+#box2 {
+  position: fixed;
+  bottom: 0;
+  left: 0;
+  right: 0;
+  height: 100px;
+  background-color: #03A9F4;
+  z-index: 100;
+}
+</style>
+<body>
+<div id="box1"></div>
+<div id="box2"></div>
+
+<script>
+var outerCount = 0;
+var innerCount = 0;
+document.addEventListener("click", function(event) {
+    outerCount++;
+})
+function createIframe() {
+    var fr = document.createElement('iframe');
+    fr.frameborder="0";
+    fr.style.height = (window.innerHeight - 50) + "px";
+    fr.style.width = "100%";
+    document.body.appendChild(fr);
+    fr.contentDocument.body.innerHTML = '<div id="target" style="margin: 0px; width: 100%; height: ' + window.innerHeight + 'px; background-color:red"></div>';
+    fr.contentDocument.getElementById("target").addEventListener("click", function(event) {
+        innerCount++;
+    })
+}
+
+promise_test (async() => {
+    createIframe();
+    await touchTapOn(innerWidth / 2, window.innerHeight - 100);
+    assert_equals(innerCount, 0);
+    assert_equals(outerCount, 1);
+})
+
+</script>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/html/marquee/marquee-zero-width-crash-expected.txt b/third_party/WebKit/LayoutTests/html/marquee/marquee-zero-width-crash-expected.txt
new file mode 100644
index 0000000..654ddf7f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/html/marquee/marquee-zero-width-crash-expected.txt
@@ -0,0 +1 @@
+This test passes if it does not crash.
diff --git a/third_party/WebKit/LayoutTests/html/marquee/marquee-zero-width-crash.html b/third_party/WebKit/LayoutTests/html/marquee/marquee-zero-width-crash.html
new file mode 100644
index 0000000..af39c63
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/html/marquee/marquee-zero-width-crash.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<title>Test: Positive content-width, zero marquee-width should not crash</title>
+<style>
+/* Style taken from clusterfuzz reproduction in http://crbug.com/866289 */
+marquee {
+  display: table-row-group;
+  padding-left: 100px;
+}
+</style>
+<marquee></marquee>
+
+<div>This test passes if it does not crash.</div>
+
+<script>
+if (window.testRunner)
+  testRunner.dumpAsText();
+</script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/serviceworker/update-no-controllee.https-expected.txt b/third_party/WebKit/LayoutTests/http/tests/serviceworker/update-no-controllee.https-expected.txt
deleted file mode 100644
index 3e0ec4b..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/serviceworker/update-no-controllee.https-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This is a testharness.js-based test.
-FAIL Verify multiple updates from service workers without controllees do not resolve immediately assert_equals: update should not have succeeded expected "failure" but got "success"
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/as-border-image/svg-as-border-image-2-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/as-border-image/svg-as-border-image-2-expected.png
index 85f6436..e531dd0 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/as-border-image/svg-as-border-image-2-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/as-border-image/svg-as-border-image-2-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/as-border-image/svg-as-border-image-2-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/svg/as-border-image/svg-as-border-image-2-expected.txt
index cb7001e..8a2e016 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/as-border-image/svg-as-border-image-2-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/as-border-image/svg-as-border-image-2-expected.txt
@@ -3,37 +3,33 @@
 layer at (0,0) size 800x600
   LayoutBlockFlow {HTML} at (0,0) size 800x600
     LayoutBlockFlow {BODY} at (8,8) size 784x584
-      LayoutBlockFlow {DIV} at (0,0) size 370x438.81 [border: (1px solid #000000)]
-        LayoutBlockFlow {H2} at (1,20.91) size 368x27
+      LayoutBlockFlow {DIV} at (0,0) size 366x438.81 [border: (1px solid #000000)]
+        LayoutBlockFlow {H2} at (1,20.91) size 364x27
           LayoutText {#text} at (0,0) size 195x26
             text run at (0,0) width 195: "SVG border-image"
-        LayoutBlockFlow (anonymous) at (1,67.81) size 368x370
+        LayoutBlockFlow (anonymous) at (1,67.81) size 364x370
           LayoutBlockFlow {DIV} at (10,10) size 160x160 [border: (30px solid #000000)]
           LayoutText {#text} at (180,165) size 4x19
             text run at (180,165) width 4: " "
           LayoutBlockFlow {DIV} at (194,10) size 160x160 [border: (30px solid #000000)]
-          LayoutText {#text} at (364,165) size 4x19
-            text run at (364,165) width 4: " "
-          LayoutBR {BR} at (0,0) size 0x0
+          LayoutBR {BR} at (364,180) size 0x0
           LayoutBlockFlow {DIV} at (10,195) size 160x160 [border: (30px solid #000000)]
           LayoutText {#text} at (180,350) size 4x19
             text run at (180,350) width 4: " "
           LayoutBlockFlow {DIV} at (194,195) size 160x160 [border: (30px solid #000000)]
           LayoutText {#text} at (0,0) size 0x0
-      LayoutText {#text} at (370,417) size 4x20
-        text run at (370,417) width 4: " "
-      LayoutBlockFlow {DIV} at (374,0) size 370x438.81 [border: (1px solid #000000)]
-        LayoutBlockFlow {H2} at (1,20.91) size 368x27
+      LayoutText {#text} at (366,417) size 4x20
+        text run at (366,417) width 4: " "
+      LayoutBlockFlow {DIV} at (370,0) size 366x438.81 [border: (1px solid #000000)]
+        LayoutBlockFlow {H2} at (1,20.91) size 364x27
           LayoutText {#text} at (0,0) size 197x26
             text run at (0,0) width 197: "PNG border-image"
-        LayoutBlockFlow (anonymous) at (1,67.81) size 368x370
+        LayoutBlockFlow (anonymous) at (1,67.81) size 364x370
           LayoutBlockFlow {DIV} at (10,10) size 160x160 [border: (30px solid #000000)]
           LayoutText {#text} at (180,165) size 4x19
             text run at (180,165) width 4: " "
           LayoutBlockFlow {DIV} at (194,10) size 160x160 [border: (30px solid #000000)]
-          LayoutText {#text} at (364,165) size 4x19
-            text run at (364,165) width 4: " "
-          LayoutBR {BR} at (0,0) size 0x0
+          LayoutBR {BR} at (364,180) size 0x0
           LayoutBlockFlow {DIV} at (10,195) size 160x160 [border: (30px solid #000000)]
           LayoutText {#text} at (180,350) size 4x19
             text run at (180,350) width 4: " "
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/as-border-image/svg-as-border-image-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/as-border-image/svg-as-border-image-expected.png
index 659d31bc..d80f7c8 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/as-border-image/svg-as-border-image-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/as-border-image/svg-as-border-image-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/as-border-image/svg-as-border-image-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/svg/as-border-image/svg-as-border-image-expected.txt
index cb7001e..8a2e016 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/as-border-image/svg-as-border-image-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/as-border-image/svg-as-border-image-expected.txt
@@ -3,37 +3,33 @@
 layer at (0,0) size 800x600
   LayoutBlockFlow {HTML} at (0,0) size 800x600
     LayoutBlockFlow {BODY} at (8,8) size 784x584
-      LayoutBlockFlow {DIV} at (0,0) size 370x438.81 [border: (1px solid #000000)]
-        LayoutBlockFlow {H2} at (1,20.91) size 368x27
+      LayoutBlockFlow {DIV} at (0,0) size 366x438.81 [border: (1px solid #000000)]
+        LayoutBlockFlow {H2} at (1,20.91) size 364x27
           LayoutText {#text} at (0,0) size 195x26
             text run at (0,0) width 195: "SVG border-image"
-        LayoutBlockFlow (anonymous) at (1,67.81) size 368x370
+        LayoutBlockFlow (anonymous) at (1,67.81) size 364x370
           LayoutBlockFlow {DIV} at (10,10) size 160x160 [border: (30px solid #000000)]
           LayoutText {#text} at (180,165) size 4x19
             text run at (180,165) width 4: " "
           LayoutBlockFlow {DIV} at (194,10) size 160x160 [border: (30px solid #000000)]
-          LayoutText {#text} at (364,165) size 4x19
-            text run at (364,165) width 4: " "
-          LayoutBR {BR} at (0,0) size 0x0
+          LayoutBR {BR} at (364,180) size 0x0
           LayoutBlockFlow {DIV} at (10,195) size 160x160 [border: (30px solid #000000)]
           LayoutText {#text} at (180,350) size 4x19
             text run at (180,350) width 4: " "
           LayoutBlockFlow {DIV} at (194,195) size 160x160 [border: (30px solid #000000)]
           LayoutText {#text} at (0,0) size 0x0
-      LayoutText {#text} at (370,417) size 4x20
-        text run at (370,417) width 4: " "
-      LayoutBlockFlow {DIV} at (374,0) size 370x438.81 [border: (1px solid #000000)]
-        LayoutBlockFlow {H2} at (1,20.91) size 368x27
+      LayoutText {#text} at (366,417) size 4x20
+        text run at (366,417) width 4: " "
+      LayoutBlockFlow {DIV} at (370,0) size 366x438.81 [border: (1px solid #000000)]
+        LayoutBlockFlow {H2} at (1,20.91) size 364x27
           LayoutText {#text} at (0,0) size 197x26
             text run at (0,0) width 197: "PNG border-image"
-        LayoutBlockFlow (anonymous) at (1,67.81) size 368x370
+        LayoutBlockFlow (anonymous) at (1,67.81) size 364x370
           LayoutBlockFlow {DIV} at (10,10) size 160x160 [border: (30px solid #000000)]
           LayoutText {#text} at (180,165) size 4x19
             text run at (180,165) width 4: " "
           LayoutBlockFlow {DIV} at (194,10) size 160x160 [border: (30px solid #000000)]
-          LayoutText {#text} at (364,165) size 4x19
-            text run at (364,165) width 4: " "
-          LayoutBR {BR} at (0,0) size 0x0
+          LayoutBR {BR} at (364,180) size 0x0
           LayoutBlockFlow {DIV} at (10,195) size 160x160 [border: (30px solid #000000)]
           LayoutText {#text} at (180,350) size 4x19
             text run at (180,350) width 4: " "
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/as-border-image/svg-as-border-image-2-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/as-border-image/svg-as-border-image-2-expected.png
index 9c6d810..72538246 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/as-border-image/svg-as-border-image-2-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/as-border-image/svg-as-border-image-2-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/as-border-image/svg-as-border-image-2-expected.txt b/third_party/WebKit/LayoutTests/platform/win/svg/as-border-image/svg-as-border-image-2-expected.txt
index 393845f..6088ad2 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/as-border-image/svg-as-border-image-2-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/as-border-image/svg-as-border-image-2-expected.txt
@@ -3,37 +3,33 @@
 layer at (0,0) size 800x600
   LayoutBlockFlow {HTML} at (0,0) size 800x600
     LayoutBlockFlow {BODY} at (8,8) size 784x584
-      LayoutBlockFlow {DIV} at (0,0) size 370x438.81 [border: (1px solid #000000)]
-        LayoutBlockFlow {H2} at (1,20.91) size 368x27
+      LayoutBlockFlow {DIV} at (0,0) size 366x438.81 [border: (1px solid #000000)]
+        LayoutBlockFlow {H2} at (1,20.91) size 364x27
           LayoutText {#text} at (0,0) size 193x26
             text run at (0,0) width 193: "SVG border-image"
-        LayoutBlockFlow (anonymous) at (1,67.81) size 368x370
+        LayoutBlockFlow (anonymous) at (1,67.81) size 364x370
           LayoutBlockFlow {DIV} at (10,10) size 160x160 [border: (30px solid #000000)]
           LayoutText {#text} at (180,165) size 4x19
             text run at (180,165) width 4: " "
           LayoutBlockFlow {DIV} at (194,10) size 160x160 [border: (30px solid #000000)]
-          LayoutText {#text} at (364,165) size 4x19
-            text run at (364,165) width 4: " "
-          LayoutBR {BR} at (0,0) size 0x0
+          LayoutBR {BR} at (364,180) size 0x0
           LayoutBlockFlow {DIV} at (10,195) size 160x160 [border: (30px solid #000000)]
           LayoutText {#text} at (180,350) size 4x19
             text run at (180,350) width 4: " "
           LayoutBlockFlow {DIV} at (194,195) size 160x160 [border: (30px solid #000000)]
           LayoutText {#text} at (0,0) size 0x0
-      LayoutText {#text} at (370,417) size 4x20
-        text run at (370,417) width 4: " "
-      LayoutBlockFlow {DIV} at (374,0) size 370x438.81 [border: (1px solid #000000)]
-        LayoutBlockFlow {H2} at (1,20.91) size 368x27
+      LayoutText {#text} at (366,417) size 4x20
+        text run at (366,417) width 4: " "
+      LayoutBlockFlow {DIV} at (370,0) size 366x438.81 [border: (1px solid #000000)]
+        LayoutBlockFlow {H2} at (1,20.91) size 364x27
           LayoutText {#text} at (0,0) size 195x26
             text run at (0,0) width 195: "PNG border-image"
-        LayoutBlockFlow (anonymous) at (1,67.81) size 368x370
+        LayoutBlockFlow (anonymous) at (1,67.81) size 364x370
           LayoutBlockFlow {DIV} at (10,10) size 160x160 [border: (30px solid #000000)]
           LayoutText {#text} at (180,165) size 4x19
             text run at (180,165) width 4: " "
           LayoutBlockFlow {DIV} at (194,10) size 160x160 [border: (30px solid #000000)]
-          LayoutText {#text} at (364,165) size 4x19
-            text run at (364,165) width 4: " "
-          LayoutBR {BR} at (0,0) size 0x0
+          LayoutBR {BR} at (364,180) size 0x0
           LayoutBlockFlow {DIV} at (10,195) size 160x160 [border: (30px solid #000000)]
           LayoutText {#text} at (180,350) size 4x19
             text run at (180,350) width 4: " "
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/as-border-image/svg-as-border-image-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/as-border-image/svg-as-border-image-expected.png
index a741647..43c7ca80 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/as-border-image/svg-as-border-image-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/as-border-image/svg-as-border-image-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/as-border-image/svg-as-border-image-expected.txt b/third_party/WebKit/LayoutTests/platform/win/svg/as-border-image/svg-as-border-image-expected.txt
index 393845f..6088ad2 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/as-border-image/svg-as-border-image-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/as-border-image/svg-as-border-image-expected.txt
@@ -3,37 +3,33 @@
 layer at (0,0) size 800x600
   LayoutBlockFlow {HTML} at (0,0) size 800x600
     LayoutBlockFlow {BODY} at (8,8) size 784x584
-      LayoutBlockFlow {DIV} at (0,0) size 370x438.81 [border: (1px solid #000000)]
-        LayoutBlockFlow {H2} at (1,20.91) size 368x27
+      LayoutBlockFlow {DIV} at (0,0) size 366x438.81 [border: (1px solid #000000)]
+        LayoutBlockFlow {H2} at (1,20.91) size 364x27
           LayoutText {#text} at (0,0) size 193x26
             text run at (0,0) width 193: "SVG border-image"
-        LayoutBlockFlow (anonymous) at (1,67.81) size 368x370
+        LayoutBlockFlow (anonymous) at (1,67.81) size 364x370
           LayoutBlockFlow {DIV} at (10,10) size 160x160 [border: (30px solid #000000)]
           LayoutText {#text} at (180,165) size 4x19
             text run at (180,165) width 4: " "
           LayoutBlockFlow {DIV} at (194,10) size 160x160 [border: (30px solid #000000)]
-          LayoutText {#text} at (364,165) size 4x19
-            text run at (364,165) width 4: " "
-          LayoutBR {BR} at (0,0) size 0x0
+          LayoutBR {BR} at (364,180) size 0x0
           LayoutBlockFlow {DIV} at (10,195) size 160x160 [border: (30px solid #000000)]
           LayoutText {#text} at (180,350) size 4x19
             text run at (180,350) width 4: " "
           LayoutBlockFlow {DIV} at (194,195) size 160x160 [border: (30px solid #000000)]
           LayoutText {#text} at (0,0) size 0x0
-      LayoutText {#text} at (370,417) size 4x20
-        text run at (370,417) width 4: " "
-      LayoutBlockFlow {DIV} at (374,0) size 370x438.81 [border: (1px solid #000000)]
-        LayoutBlockFlow {H2} at (1,20.91) size 368x27
+      LayoutText {#text} at (366,417) size 4x20
+        text run at (366,417) width 4: " "
+      LayoutBlockFlow {DIV} at (370,0) size 366x438.81 [border: (1px solid #000000)]
+        LayoutBlockFlow {H2} at (1,20.91) size 364x27
           LayoutText {#text} at (0,0) size 195x26
             text run at (0,0) width 195: "PNG border-image"
-        LayoutBlockFlow (anonymous) at (1,67.81) size 368x370
+        LayoutBlockFlow (anonymous) at (1,67.81) size 364x370
           LayoutBlockFlow {DIV} at (10,10) size 160x160 [border: (30px solid #000000)]
           LayoutText {#text} at (180,165) size 4x19
             text run at (180,165) width 4: " "
           LayoutBlockFlow {DIV} at (194,10) size 160x160 [border: (30px solid #000000)]
-          LayoutText {#text} at (364,165) size 4x19
-            text run at (364,165) width 4: " "
-          LayoutBR {BR} at (0,0) size 0x0
+          LayoutBR {BR} at (364,180) size 0x0
           LayoutBlockFlow {DIV} at (10,195) size 160x160 [border: (30px solid #000000)]
           LayoutText {#text} at (180,350) size 4x19
             text run at (180,350) width 4: " "
diff --git a/third_party/WebKit/LayoutTests/resources/gesture-util.js b/third_party/WebKit/LayoutTests/resources/gesture-util.js
index 7bb73356a..9fae8c4 100644
--- a/third_party/WebKit/LayoutTests/resources/gesture-util.js
+++ b/third_party/WebKit/LayoutTests/resources/gesture-util.js
@@ -236,6 +236,21 @@
   });
 }
 
+function touchTapOn(xPosition, yPosition) {
+  return new Promise(function(resolve, reject) {
+    if (window.chrome && chrome.gpuBenchmarking) {
+      chrome.gpuBenchmarking.pointerActionSequence( [
+        {source: 'touch',
+         actions: [
+            { name: 'pointerDown', x: xPosition, y: yPosition },
+            { name: 'pointerUp' }
+        ]}], resolve);
+    } else {
+      reject();
+    }
+  });
+}
+
 function approx_equals(actual, expected, epsilon) {
   return actual >= expected - epsilon && actual <= expected + epsilon;
 }
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/svg/as-border-image/svg-as-border-image-2.html b/third_party/WebKit/LayoutTests/svg/as-border-image/svg-as-border-image-2.html
index 57346e0..a9f2868 100644
--- a/third_party/WebKit/LayoutTests/svg/as-border-image/svg-as-border-image-2.html
+++ b/third_party/WebKit/LayoutTests/svg/as-border-image/svg-as-border-image-2.html
@@ -57,8 +57,7 @@
   <div class="svg">
     <h2>SVG border-image</h2>
     <div class="rr"></div>
-    <div class="rs"></div>
-    <br>
+    <div class="rs"></div><br>
     <div class="sr"></div>
     <div class="ss"></div>
   </div>
@@ -66,8 +65,7 @@
   <div class="image">
     <h2>PNG border-image</h2>
     <div class="rr"></div>
-    <div class="rs"></div>
-    <br>
+    <div class="rs"></div><br>
     <div class="sr"></div>
     <div class="ss"></div>
   </div>
diff --git a/third_party/WebKit/LayoutTests/svg/as-border-image/svg-as-border-image.html b/third_party/WebKit/LayoutTests/svg/as-border-image/svg-as-border-image.html
index a9bf8b9f..a3d7aeb 100644
--- a/third_party/WebKit/LayoutTests/svg/as-border-image/svg-as-border-image.html
+++ b/third_party/WebKit/LayoutTests/svg/as-border-image/svg-as-border-image.html
@@ -57,8 +57,7 @@
   <div class="svg">
     <h2>SVG border-image</h2>
     <div class="rr"></div>
-    <div class="rs"></div>
-    <br>
+    <div class="rs"></div><br>
     <div class="sr"></div>
     <div class="ss"></div>
   </div>
@@ -66,8 +65,7 @@
   <div class="image">
     <h2>PNG border-image</h2>
     <div class="rr"></div>
-    <div class="rs"></div>
-    <br>
+    <div class="rs"></div><br>
     <div class="sr"></div>
     <div class="ss"></div>
   </div>
diff --git a/third_party/blink/public/platform/web_feature.mojom b/third_party/blink/public/platform/web_feature.mojom
index 40516ff..98953f2 100644
--- a/third_party/blink/public/platform/web_feature.mojom
+++ b/third_party/blink/public/platform/web_feature.mojom
@@ -1974,6 +1974,7 @@
   kV8RTCPeerConnection_AddTransceiver_Method = 2513,
   kV8RTCRtpTransceiver_Direction_AttributeGetter = 2514,
   kV8RTCRtpTransceiver_Direction_AttributeSetter = 2515,
+  kHTMLLinkElementDisabledByParser = 2516,
 
   // 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/blink/renderer/bindings/core/v8/serialization/v8_script_value_serializer.cc b/third_party/blink/renderer/bindings/core/v8/serialization/v8_script_value_serializer.cc
index ec89538..d4e554b 100644
--- a/third_party/blink/renderer/bindings/core/v8/serialization/v8_script_value_serializer.cc
+++ b/third_party/blink/renderer/bindings/core/v8/serialization/v8_script_value_serializer.cc
@@ -32,6 +32,7 @@
 #include "third_party/blink/renderer/core/geometry/dom_rect_read_only.h"
 #include "third_party/blink/renderer/core/html/canvas/image_data.h"
 #include "third_party/blink/renderer/core/typed_arrays/dom_array_buffer_base.h"
+#include "third_party/blink/renderer/platform/file_metadata.h"
 #include "third_party/blink/renderer/platform/wtf/allocator/partitions.h"
 #include "third_party/blink/renderer/platform/wtf/date_math.h"
 #include "third_party/blink/renderer/platform/wtf/text/string_utf8_adaptor.h"
diff --git a/third_party/blink/renderer/bindings/core/v8/serialization/v8_script_value_serializer_test.cc b/third_party/blink/renderer/bindings/core/v8/serialization/v8_script_value_serializer_test.cc
index a32e43c7..01d2fde1 100644
--- a/third_party/blink/renderer/bindings/core/v8/serialization/v8_script_value_serializer_test.cc
+++ b/third_party/blink/renderer/bindings/core/v8/serialization/v8_script_value_serializer_test.cc
@@ -45,6 +45,7 @@
 #include "third_party/blink/renderer/core/messaging/message_port.h"
 #include "third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.h"
 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
+#include "third_party/blink/renderer/platform/file_metadata.h"
 #include "third_party/blink/renderer/platform/graphics/static_bitmap_image.h"
 #include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h"
 #include "third_party/blink/renderer/platform/wtf/date_math.h"
diff --git a/third_party/blink/renderer/core/BUILD.gn b/third_party/blink/renderer/core/BUILD.gn
index bd073cb..29d5b38 100644
--- a/third_party/blink/renderer/core/BUILD.gn
+++ b/third_party/blink/renderer/core/BUILD.gn
@@ -1983,11 +1983,11 @@
     "loader/base_fetch_context_test.cc",
     "loader/document_load_timing_test.cc",
     "loader/document_loader_test.cc",
-    "loader/document_threadable_loader_test.cc",
     "loader/frame_fetch_context_test.cc",
     "loader/idleness_detector_test.cc",
     "loader/interactive_detector_test.cc",
     "loader/link_loader_test.cc",
+    "loader/long_task_detector_test.cc",
     "loader/mixed_content_checker_test.cc",
     "loader/modulescript/module_script_loader_test.cc",
     "loader/modulescript/module_tree_linker_test.cc",
diff --git a/third_party/blink/renderer/core/clipboard/data_object.cc b/third_party/blink/renderer/core/clipboard/data_object.cc
index b81a304..70125b4f 100644
--- a/third_party/blink/renderer/core/clipboard/data_object.cc
+++ b/third_party/blink/renderer/core/clipboard/data_object.cc
@@ -36,6 +36,7 @@
 #include "third_party/blink/renderer/core/clipboard/clipboard_utilities.h"
 #include "third_party/blink/renderer/core/clipboard/dragged_isolated_file_system.h"
 #include "third_party/blink/renderer/core/clipboard/system_clipboard.h"
+#include "third_party/blink/renderer/platform/file_metadata.h"
 #include "third_party/blink/renderer/platform/paste_mode.h"
 #include "third_party/blink/renderer/platform/wtf/hash_set.h"
 
diff --git a/third_party/blink/renderer/core/clipboard/data_object_test.cc b/third_party/blink/renderer/core/clipboard/data_object_test.cc
index a28fa65..64f75a7 100644
--- a/third_party/blink/renderer/core/clipboard/data_object_test.cc
+++ b/third_party/blink/renderer/core/clipboard/data_object_test.cc
@@ -6,6 +6,7 @@
 
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/renderer/core/clipboard/data_object_item.h"
+#include "third_party/blink/renderer/platform/file_metadata.h"
 #include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/core/editing/editing_utilities.cc b/third_party/blink/renderer/core/editing/editing_utilities.cc
index 85114d2..45b02042 100644
--- a/third_party/blink/renderer/core/editing/editing_utilities.cc
+++ b/third_party/blink/renderer/core/editing/editing_utilities.cc
@@ -72,6 +72,7 @@
 #include "third_party/blink/renderer/core/layout/layout_object.h"
 #include "third_party/blink/renderer/core/layout/layout_table_cell.h"
 #include "third_party/blink/renderer/core/svg/svg_image_element.h"
+#include "third_party/blink/renderer/platform/graphics/static_bitmap_image.h"
 #include "third_party/blink/renderer/platform/wtf/assertions.h"
 #include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
 #include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
@@ -1701,7 +1702,7 @@
 
   if (layout_object->IsCanvas()) {
     return ToHTMLCanvasElement(const_cast<Node&>(node))
-        .CopiedImage(kFrontBuffer, kPreferNoAcceleration);
+        .Snapshot(kFrontBuffer, kPreferNoAcceleration);
   }
 
   if (!layout_object->IsImage())
diff --git a/third_party/blink/renderer/core/editing/finder/text_finder.cc b/third_party/blink/renderer/core/editing/finder/text_finder.cc
index 3f01432..9eb03b4 100644
--- a/third_party/blink/renderer/core/editing/finder/text_finder.cc
+++ b/third_party/blink/renderer/core/editing/finder/text_finder.cc
@@ -443,7 +443,7 @@
   const double kMaxScopingDuration = 0.1;  // seconds
 
   int match_count = 0;
-  bool timed_out = false;
+  bool full_range_searched = false;
   double start_time = CurrentTime();
   PositionInFlatTree next_scoping_start;
   do {
@@ -457,6 +457,7 @@
                       search_text, options.match_case ? 0 : kCaseInsensitive);
     if (result.IsCollapsed()) {
       // Not found.
+      full_range_searched = true;
       break;
     }
     Range* result_range = Range::Create(
@@ -516,8 +517,7 @@
     search_start = result.EndPosition();
 
     next_scoping_start = search_start;
-    timed_out = (CurrentTime() - start_time) >= kMaxScopingDuration;
-  } while (!timed_out);
+  } while (CurrentTime() - start_time < kMaxScopingDuration);
 
   if (next_scoping_start.IsNotNull()) {
     resume_scoping_from_range_ =
@@ -540,7 +540,7 @@
     IncreaseMatchCount(identifier, match_count);
   }
 
-  if (timed_out) {
+  if (!full_range_searched) {
     // If we found anything during this pass, we should redraw. However, we
     // don't want to spam too much if the page is extremely long, so if we
     // reach a certain point we start throttling the redraw requests.
diff --git a/third_party/blink/renderer/core/exported/web_associated_url_loader_impl.cc b/third_party/blink/renderer/core/exported/web_associated_url_loader_impl.cc
index 383579e..210149d9b 100644
--- a/third_party/blink/renderer/core/exported/web_associated_url_loader_impl.cc
+++ b/third_party/blink/renderer/core/exported/web_associated_url_loader_impl.cc
@@ -48,9 +48,8 @@
 #include "third_party/blink/public/web/web_associated_url_loader_client.h"
 #include "third_party/blink/renderer/core/dom/context_lifecycle_observer.h"
 #include "third_party/blink/renderer/core/dom/document.h"
-#include "third_party/blink/renderer/core/loader/document_threadable_loader.h"
-#include "third_party/blink/renderer/core/loader/document_threadable_loader_client.h"
-#include "third_party/blink/renderer/core/loader/threadable_loading_context.h"
+#include "third_party/blink/renderer/core/loader/threadable_loader.h"
+#include "third_party/blink/renderer/core/loader/threadable_loader_client.h"
 #include "third_party/blink/renderer/platform/exported/wrapped_resource_request.h"
 #include "third_party/blink/renderer/platform/exported/wrapped_resource_response.h"
 #include "third_party/blink/renderer/platform/loader/cors/cors.h"
@@ -96,7 +95,7 @@
 // It forwards its ThreadableLoaderClient notifications to a
 // WebAssociatedURLLoaderClient.
 class WebAssociatedURLLoaderImpl::ClientAdapter final
-    : public DocumentThreadableLoaderClient {
+    : public ThreadableLoaderClient {
  public:
   static std::unique_ptr<ClientAdapter> Create(
       WebAssociatedURLLoaderImpl*,
@@ -119,7 +118,7 @@
   void DidFail(const ResourceError&) override;
   void DidFailRedirectCheck() override;
 
-  // DocumentThreadableLoaderClient
+  // ThreadableLoaderClient
   bool WillFollowRedirect(
       const KURL& /*new_url*/,
       const ResourceResponse& /*redirect_response*/) override;
@@ -133,7 +132,7 @@
   // WebAssociatedURLLoader::loadAsynchronously() completes.
   void EnableErrorNotifications();
 
-  // Stops loading and releases the DocumentThreadableLoader as early as
+  // Stops loading and releases the ThreadableLoader as early as
   // possible.
   WebAssociatedURLLoaderClient* ReleaseClient() {
     WebAssociatedURLLoaderClient* client = client_;
@@ -442,9 +441,8 @@
 
     Document* document = ToDocument(observer_->LifecycleContext());
     DCHECK(document);
-    loader_ = DocumentThreadableLoader::Create(
-        *ThreadableLoadingContext::Create(*document), client_adapter_.get(),
-        options, resource_loader_options);
+    loader_ = ThreadableLoader::Create(*document, client_adapter_.get(),
+                                       options, resource_loader_options);
     loader_->Start(webcore_request);
   }
 
@@ -518,7 +516,7 @@
   // without cancelling the loader means that it's possible there're some
   // non-Blink non-on-heap objects still facing on-heap Blink objects. E.g.
   // there could be a WebURLLoader instance behind the
-  // DocumentThreadableLoader instance. So, for safety, we chose to just
+  // ThreadableLoader instance. So, for safety, we chose to just
   // crash here.
   CHECK(ThreadState::Current());
 
diff --git a/third_party/blink/renderer/core/exported/web_associated_url_loader_impl.h b/third_party/blink/renderer/core/exported/web_associated_url_loader_impl.h
index 74d27ddb..cfe041c 100644
--- a/third_party/blink/renderer/core/exported/web_associated_url_loader_impl.h
+++ b/third_party/blink/renderer/core/exported/web_associated_url_loader_impl.h
@@ -17,7 +17,7 @@
 
 namespace blink {
 
-class DocumentThreadableLoader;
+class ThreadableLoader;
 class WebAssociatedURLLoaderClient;
 class Document;
 
@@ -57,10 +57,10 @@
   WebAssociatedURLLoaderClient* client_;
   WebAssociatedURLLoaderOptions options_;
 
-  // An adapter which converts the DocumentThreadableLoaderClient method
+  // An adapter which converts the hreadableLoaderClient method
   // calls into the WebURLLoaderClient method calls.
   std::unique_ptr<ClientAdapter> client_adapter_;
-  Persistent<DocumentThreadableLoader> loader_;
+  Persistent<ThreadableLoader> loader_;
 
   // A ContextLifecycleObserver for cancelling |m_loader| when the Document
   // is detached.
diff --git a/third_party/blink/renderer/core/exported/web_drag_data_test.cc b/third_party/blink/renderer/core/exported/web_drag_data_test.cc
index 7aa8936..2ea006b2 100644
--- a/third_party/blink/renderer/core/exported/web_drag_data_test.cc
+++ b/third_party/blink/renderer/core/exported/web_drag_data_test.cc
@@ -7,6 +7,7 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/public/platform/web_vector.h"
 #include "third_party/blink/renderer/core/clipboard/data_object.h"
+#include "third_party/blink/renderer/platform/file_metadata.h"
 
 namespace blink {
 
diff --git a/third_party/blink/renderer/core/exported/web_frame_test.cc b/third_party/blink/renderer/core/exported/web_frame_test.cc
index 9f27c5a..c9bd8d9 100644
--- a/third_party/blink/renderer/core/exported/web_frame_test.cc
+++ b/third_party/blink/renderer/core/exported/web_frame_test.cc
@@ -127,11 +127,7 @@
 #include "third_party/blink/renderer/core/layout/hit_test_result.h"
 #include "third_party/blink/renderer/core/layout/layout_view.h"
 #include "third_party/blink/renderer/core/loader/document_loader.h"
-#include "third_party/blink/renderer/core/loader/document_threadable_loader.h"
-#include "third_party/blink/renderer/core/loader/document_threadable_loader_client.h"
 #include "third_party/blink/renderer/core/loader/frame_load_request.h"
-#include "third_party/blink/renderer/core/loader/threadable_loader.h"
-#include "third_party/blink/renderer/core/loader/threadable_loading_context.h"
 #include "third_party/blink/renderer/core/page/chrome_client.h"
 #include "third_party/blink/renderer/core/page/page.h"
 #include "third_party/blink/renderer/core/page/scoped_page_pauser.h"
@@ -10066,21 +10062,6 @@
   helper.Reset();
 }
 
-class MockDocumentThreadableLoaderClient
-    : public DocumentThreadableLoaderClient {
- public:
-  MockDocumentThreadableLoaderClient() : failed_(false) {}
-  ~MockDocumentThreadableLoaderClient() override = default;
-
-  // DocumentThreadableLoaderClient:
-  void DidFail(const ResourceError&) override { failed_ = true; }
-
-  void Reset() { failed_ = false; }
-  bool Failed() { return failed_; }
-
-  bool failed_;
-};
-
 TEST_F(WebFrameTest, DetachRemoteFrame) {
   FrameTestHelpers::WebViewHelper helper;
   helper.InitializeRemote();
diff --git a/third_party/blink/renderer/core/fetch/fetch_data_loader.cc b/third_party/blink/renderer/core/fetch/fetch_data_loader.cc
index 00c4d01d..c4cd752 100644
--- a/third_party/blink/renderer/core/fetch/fetch_data_loader.cc
+++ b/third_party/blink/renderer/core/fetch/fetch_data_loader.cc
@@ -11,6 +11,7 @@
 #include "third_party/blink/renderer/core/fileapi/file.h"
 #include "third_party/blink/renderer/core/html/forms/form_data.h"
 #include "third_party/blink/renderer/core/html/parser/text_resource_decoder.h"
+#include "third_party/blink/renderer/platform/file_metadata.h"
 #include "third_party/blink/renderer/platform/loader/fetch/text_resource_decoder_options.h"
 #include "third_party/blink/renderer/platform/network/http_names.h"
 #include "third_party/blink/renderer/platform/network/parsed_content_disposition.h"
diff --git a/third_party/blink/renderer/core/fetch/fetch_manager.cc b/third_party/blink/renderer/core/fetch/fetch_manager.cc
index 2f245af3..ae91026 100644
--- a/third_party/blink/renderer/core/fetch/fetch_manager.cc
+++ b/third_party/blink/renderer/core/fetch/fetch_manager.cc
@@ -744,8 +744,7 @@
 }
 
 void FetchManager::Loader::PerformHTTPFetch(ExceptionState& exception_state) {
-  // CORS preflight fetch procedure is implemented inside
-  // DocumentThreadableLoader.
+  // CORS preflight fetch procedure is implemented inside ThreadableLoader.
 
   // "1. Let |HTTPRequest| be a copy of |request|, except that |HTTPRequest|'s
   //  body is a tee of |request|'s body."
@@ -837,7 +836,7 @@
   // |HTTPRequest|'s origin, serialized and utf-8 encoded, to |HTTPRequest|'s
   // header list."
   // We set Origin header in updateRequestForAccessControl() called from
-  // DocumentThreadableLoader::makeCrossOriginAccessRequest
+  // ThreadableLoader::makeCrossOriginAccessRequest
 
   // "5. Let |credentials flag| be set if either |HTTPRequest|'s credentials
   // mode is |include|, or |HTTPRequest|'s credentials mode is |same-origin|
diff --git a/third_party/blink/renderer/core/fetch/form_data_bytes_consumer.cc b/third_party/blink/renderer/core/fetch/form_data_bytes_consumer.cc
index 48bb0a5..2f69f7c 100644
--- a/third_party/blink/renderer/core/fetch/form_data_bytes_consumer.cc
+++ b/third_party/blink/renderer/core/fetch/form_data_bytes_consumer.cc
@@ -11,6 +11,7 @@
 #include "third_party/blink/renderer/core/typed_arrays/dom_array_buffer.h"
 #include "third_party/blink/renderer/core/typed_arrays/dom_array_buffer_view.h"
 #include "third_party/blink/renderer/platform/blob/blob_data.h"
+#include "third_party/blink/renderer/platform/file_metadata.h"
 #include "third_party/blink/renderer/platform/network/encoded_form_data.h"
 #include "third_party/blink/renderer/platform/network/form_data_encoder.h"
 #include "third_party/blink/renderer/platform/wtf/functional.h"
diff --git a/third_party/blink/renderer/core/fileapi/file_list_test.cc b/third_party/blink/renderer/core/fileapi/file_list_test.cc
index ef6ffca..44ac730 100644
--- a/third_party/blink/renderer/core/fileapi/file_list_test.cc
+++ b/third_party/blink/renderer/core/fileapi/file_list_test.cc
@@ -5,6 +5,7 @@
 #include "third_party/blink/renderer/core/fileapi/file_list.h"
 
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/renderer/platform/file_metadata.h"
 
 namespace blink {
 
diff --git a/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc b/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc
index 4f46e9bf..50cc1321 100644
--- a/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc
+++ b/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc
@@ -367,7 +367,6 @@
   if (rect.IsEmpty())
     return;
   canvas_is_clear_ = false;
-  ClearCopiedImage();
   if (GetLayoutObject() && !LowLatencyEnabled())
     GetLayoutObject()->SetMayNeedPaintInvalidation();
   if (Is2d() && context_->ShouldAntialias() && GetPage() &&
@@ -757,7 +756,6 @@
   size_ = size;
   did_fail_to_create_resource_provider_ = false;
   DiscardResourceProvider();
-  ClearCopiedImage();
   if (Is2d() && context_->isContextLost()) {
     context_->DidSetSurfaceSize();
   }
@@ -770,7 +768,7 @@
       ToDataURLInternal(ImageEncoderUtils::kDefaultMimeType, 0, kFrontBuffer));
 }
 
-scoped_refptr<StaticBitmapImage> HTMLCanvasElement::ToStaticBitmapImage(
+scoped_refptr<StaticBitmapImage> HTMLCanvasElement::Snapshot(
     SourceDrawingBuffer source_buffer,
     AccelerationHint hint) const {
   if (size_.IsEmpty())
@@ -844,7 +842,7 @@
   }
 
   scoped_refptr<StaticBitmapImage> image_bitmap =
-      ToStaticBitmapImage(source_buffer, kPreferNoAcceleration);
+      Snapshot(source_buffer, kPreferNoAcceleration);
   if (image_bitmap) {
     std::unique_ptr<ImageDataBuffer> data_buffer =
         ImageDataBuffer::Create(image_bitmap);
@@ -908,7 +906,7 @@
 
   CanvasAsyncBlobCreator* async_creator = nullptr;
   scoped_refptr<StaticBitmapImage> image_bitmap =
-      ToStaticBitmapImage(kBackBuffer, kPreferNoAcceleration);
+      Snapshot(kBackBuffer, kPreferNoAcceleration);
   if (image_bitmap) {
     async_creator = CanvasAsyncBlobCreator::Create(
         image_bitmap, encoding_mime_type, callback,
@@ -1139,57 +1137,12 @@
   SetCanvas2DLayerBridgeInternal(std::move(bridge));
 }
 
-scoped_refptr<Image> HTMLCanvasElement::CopiedImage(
-    SourceDrawingBuffer source_buffer,
-    AccelerationHint hint) {
-  if (PlaceholderFrame())
-    return PlaceholderFrame()->Bitmap();
-
-  if (!IsPaintable())
-    return nullptr;
-
-  if (!context_)
-    return CreateTransparentImage(Size());
-
-  if (HasImageBitmapContext()) {
-    scoped_refptr<Image> image = context_->GetImage(hint);
-    // TODO(fserb): return image?
-    if (image)
-      return context_->GetImage(hint);
-    // Special case: transferFromImageBitmap is not yet called.
-    sk_sp<SkSurface> surface =
-        SkSurface::MakeRasterN32Premul(width(), height());
-    return StaticBitmapImage::Create(surface->makeImageSnapshot());
-  }
-
-  bool need_to_update = !copied_image_;
-  // The concept of SourceDrawingBuffer is valid on only WebGL.
-  if (context_->Is3d())
-    need_to_update |= context_->PaintRenderingResultsToCanvas(source_buffer);
-  if (need_to_update) {
-    if (Is2d() && GetOrCreateCanvas2DLayerBridge()) {
-      copied_image_ = canvas2d_bridge_->NewImageSnapshot(hint);
-    } else if (Is3d() && GetOrCreateCanvasResourceProvider(hint)) {
-      copied_image_ = ResourceProvider()->Snapshot();
-    }
-    UpdateMemoryUsage();
-  }
-  return copied_image_;
-}
-
 void HTMLCanvasElement::DiscardResourceProvider() {
   canvas2d_bridge_.reset();
   CanvasResourceHost::DiscardResourceProvider();
   dirty_rect_ = FloatRect();
 }
 
-void HTMLCanvasElement::ClearCopiedImage() {
-  if (copied_image_) {
-    copied_image_ = nullptr;
-    UpdateMemoryUsage();
-  }
-}
-
 void HTMLCanvasElement::PageVisibilityChanged() {
   bool hidden = !GetPage()->IsPageVisible();
   SetSuspendOffscreenCanvasAnimation(hidden);
@@ -1199,7 +1152,6 @@
 
   context_->SetIsHidden(hidden);
   if (hidden) {
-    ClearCopiedImage();
     if (Is3d()) {
       DiscardResourceProvider();
     }
@@ -1475,9 +1427,6 @@
     }
   }
 
-  if (copied_image_)
-    non_gpu_buffer_count++;
-
   if (Is3d()) {
     if (ResourceProvider()) {
       non_gpu_buffer_count++;
diff --git a/third_party/blink/renderer/core/html/canvas/html_canvas_element.h b/third_party/blink/renderer/core/html/canvas/html_canvas_element.h
index 1b4daa3..bd98ac8 100644
--- a/third_party/blink/renderer/core/html/canvas/html_canvas_element.h
+++ b/third_party/blink/renderer/core/html/canvas/html_canvas_element.h
@@ -156,9 +156,6 @@
     return context_.Get();
   }
 
-  scoped_refptr<Image> CopiedImage(SourceDrawingBuffer, AccelerationHint);
-  void ClearCopiedImage();
-
   bool OriginClean() const override;
   void SetOriginTainted() override { origin_clean_ = false; }
 
@@ -299,6 +296,9 @@
 
   bool LowLatencyEnabled() const { return !!frame_dispatcher_; }
 
+  scoped_refptr<StaticBitmapImage> Snapshot(SourceDrawingBuffer,
+                                            AccelerationHint) const;
+
  protected:
   void DidMoveToNewDocument(Document& old_document) override;
 
@@ -331,9 +331,6 @@
 
   bool PaintsIntoCanvasBuffer() const;
 
-  scoped_refptr<StaticBitmapImage> ToStaticBitmapImage(SourceDrawingBuffer,
-                                                       AccelerationHint) const;
-
   String ToDataURLInternal(const String& mime_type,
                            const double& quality,
                            SourceDrawingBuffer) const;
@@ -368,10 +365,6 @@
   std::unique_ptr<Canvas2DLayerBridge> canvas2d_bridge_;
   void ReplaceExisting2dLayerBridge(std::unique_ptr<Canvas2DLayerBridge>);
 
-  // FIXME: This is temporary for platforms that have to copy the image buffer
-  // to render (and for CSSCanvasValue).
-  mutable scoped_refptr<Image> copied_image_;
-
   // Used for OffscreenCanvas that controls this HTML canvas element
   // and for low latency mode.
   std::unique_ptr<::blink::SurfaceLayerBridge> surface_layer_bridge_;
diff --git a/third_party/blink/renderer/core/html/html_link_element.cc b/third_party/blink/renderer/core/html/html_link_element.cc
index 1139619..fc310ad5 100644
--- a/third_party/blink/renderer/core/html/html_link_element.cc
+++ b/third_party/blink/renderer/core/html/html_link_element.cc
@@ -110,6 +110,8 @@
     importance_ = value;
   } else if (name == disabledAttr) {
     UseCounter::Count(GetDocument(), WebFeature::kHTMLLinkElementDisabled);
+    if (params.reason == AttributeModificationReason::kByParser)
+      UseCounter::Count(GetDocument(), WebFeature::kHTMLLinkElementDisabledByParser);
     if (LinkStyle* link = GetLinkStyle())
       link->SetDisabledState(!value.IsNull());
   } else {
diff --git a/third_party/blink/renderer/core/html/html_marquee_element.cc b/third_party/blink/renderer/core/html/html_marquee_element.cc
index 85588ab0..b8d3e7c 100644
--- a/third_party/blink/renderer/core/html/html_marquee_element.cc
+++ b/third_party/blink/renderer/core/html/html_marquee_element.cc
@@ -291,7 +291,7 @@
   double duration = 0;
   if (scroll_amount)
     duration = parameters.distance * scroll_delay / scroll_amount;
-  if (!duration)
+  if (duration <= 0)
     return;
 
   StringKeyframeEffectModel* effect_model = CreateEffectModel(parameters);
diff --git a/third_party/blink/renderer/core/input/event_handler.cc b/third_party/blink/renderer/core/input/event_handler.cc
index 5387f4ab..ae3c3f03 100644
--- a/third_party/blink/renderer/core/input/event_handler.cc
+++ b/third_party/blink/renderer/core/input/event_handler.cc
@@ -1766,10 +1766,9 @@
     LocalFrame* hit_frame = hit_test_result.InnerNodeFrame();
     if (!hit_frame)
       hit_frame = frame_;
-    location = HitTestLocation(hit_frame->View()->ConvertFromRootFrame(
-        LayoutPoint(adjusted_event.PositionInRootFrame())));
-    hit_test_result = EventHandlingUtil::HitTestResultInFrame(
-        hit_frame, location,
+    location = HitTestLocation(adjusted_event.PositionInRootFrame());
+    hit_test_result = root_frame.GetEventHandler().HitTestResultAtLocation(
+        location,
         (hit_type | HitTestRequest::kReadOnly) & ~HitTestRequest::kListBased);
   }
   // If we did a rect-based hit test it must be resolved to the best single node
diff --git a/third_party/blink/renderer/core/layout/layout_box.cc b/third_party/blink/renderer/core/layout/layout_box.cc
index 5d8072d..6f1a106 100644
--- a/third_party/blink/renderer/core/layout/layout_box.cc
+++ b/third_party/blink/renderer/core/layout/layout_box.cc
@@ -4408,6 +4408,7 @@
   }
 
   if (container_block->IsBox() &&
+      container_block->IsHorizontalWritingMode() == IsHorizontalWritingMode() &&
       ToLayoutBox(container_block)->ScrollsOverflowY() &&
       ToLayoutBox(container_block)
           ->ShouldPlaceBlockDirectionScrollbarOnLogicalLeft()) {
@@ -4764,6 +4765,15 @@
   }
   computed_values.extent_ = logical_height_value;
 
+  if (container_block->IsBox() &&
+      container_block->IsHorizontalWritingMode() != IsHorizontalWritingMode() &&
+      ToLayoutBox(container_block)->ScrollsOverflowY() &&
+      ToLayoutBox(container_block)
+          ->ShouldPlaceBlockDirectionScrollbarOnLogicalLeft()) {
+    logical_top_value = logical_top_value +
+                         ToLayoutBox(container_block)->VerticalScrollbarWidth();
+  }
+
   // Use computed values to calculate the vertical position.
   computed_values.position_ =
       logical_top_value + computed_values.margins_.before_;
diff --git a/third_party/blink/renderer/core/layout/layout_geometry_map_test.cc b/third_party/blink/renderer/core/layout/layout_geometry_map_test.cc
index 425ee90..cfa3920 100644
--- a/third_party/blink/renderer/core/layout/layout_geometry_map_test.cc
+++ b/third_party/blink/renderer/core/layout/layout_geometry_map_test.cc
@@ -467,7 +467,6 @@
 
   LayoutGeometryMap rgm;
   rgm.PushMappingsToAncestor(GetLayoutBox(web_view, "A"), nullptr);
-  FloatPoint point;
   FloatRect rect(0.0f, 0.0f, 5.0f, 3.0f);
 
   EXPECT_EQ(FloatQuad(FloatRect(8.0f, 8.0f, 5.0f, 3.0f)),
diff --git a/third_party/blink/renderer/core/layout/layout_list_marker.cc b/third_party/blink/renderer/core/layout/layout_list_marker.cc
index 5e34e8e..4e86707b 100644
--- a/third_party/blink/renderer/core/layout/layout_list_marker.cc
+++ b/third_party/blink/renderer/core/layout/layout_list_marker.cc
@@ -296,8 +296,6 @@
 std::pair<LayoutUnit, LayoutUnit> LayoutListMarker::InlineMarginsForInside(
     const ComputedStyle& style,
     bool is_image) {
-  LayoutUnit margin_start;
-  LayoutUnit margin_end;
   if (is_image)
     return {LayoutUnit(), LayoutUnit(kCMarkerPaddingPx)};
   switch (GetListStyleCategory(style.ListStyleType())) {
diff --git a/third_party/blink/renderer/core/layout/layout_text.cc b/third_party/blink/renderer/core/layout/layout_text.cc
index a2ff463d..e45c457 100644
--- a/third_party/blink/renderer/core/layout/layout_text.cc
+++ b/third_party/blink/renderer/core/layout/layout_text.cc
@@ -356,7 +356,6 @@
   if (truncation == kCNoTruncation)
     return IntRect();
 
-  IntRect rect;
   if (EllipsisBox* ellipsis = box->Root().GetEllipsisBox()) {
     int ellipsis_start_position = std::max<int>(start_pos - box->Start(), 0);
     int ellipsis_end_position =
@@ -2290,7 +2289,6 @@
   FloatPoint first_run_offset;
   if (const NGPhysicalBoxFragment* box_fragment =
           EnclosingBlockFlowFragment()) {
-    NGPhysicalOffsetRect bounding_box;
     const auto fragments =
         NGInlineFragmentTraversal::SelfFragmentsOf(*box_fragment, this);
     if (fragments.size()) {
diff --git a/third_party/blink/renderer/core/layout/layout_view.cc b/third_party/blink/renderer/core/layout/layout_view.cc
index c7169116..52975440 100644
--- a/third_party/blink/renderer/core/layout/layout_view.cc
+++ b/third_party/blink/renderer/core/layout/layout_view.cc
@@ -262,6 +262,22 @@
   }
 }
 
+bool LayoutView::ShouldPlaceBlockDirectionScrollbarOnLogicalLeft() const {
+  LocalFrame& frame = GetFrameView()->GetFrame();
+  // See crbug.com/249860
+  if (frame.IsMainFrame())
+    return false;
+  // <body> inherits 'direction' from <html>, so checking style on the body is
+  // sufficient.
+  if (Element* body = GetDocument().body()) {
+    if (LayoutObject* body_layout_object = body->GetLayoutObject()) {
+      return body_layout_object->Style()
+          ->ShouldPlaceBlockDirectionScrollbarOnLogicalLeft();
+    }
+  }
+  return false;
+}
+
 void LayoutView::UpdateBlockLayout(bool relayout_children) {
   SubtreeLayoutScope layout_scope(*this);
 
diff --git a/third_party/blink/renderer/core/layout/layout_view.h b/third_party/blink/renderer/core/layout/layout_view.h
index fed51c0..0954c1e 100644
--- a/third_party/blink/renderer/core/layout/layout_view.h
+++ b/third_party/blink/renderer/core/layout/layout_view.h
@@ -241,13 +241,7 @@
   void SetShouldDoFullPaintInvalidationOnResizeIfNeeded(bool width_changed,
                                                         bool height_changed);
 
-  // The document scrollbar is always on the right, even in RTL. This is to
-  // prevent it from moving around on navigations.
-  // TODO(skobes): This is not quite the ideal behavior, see
-  // http://crbug.com/250514 and http://crbug.com/249860.
-  bool ShouldPlaceBlockDirectionScrollbarOnLogicalLeft() const override {
-    return false;
-  }
+  bool ShouldPlaceBlockDirectionScrollbarOnLogicalLeft() const override;
 
   LayoutRect DebugRect() const override;
 
diff --git a/third_party/blink/renderer/core/loader/BUILD.gn b/third_party/blink/renderer/core/loader/BUILD.gn
index f5b9aab..0f384d92 100644
--- a/third_party/blink/renderer/core/loader/BUILD.gn
+++ b/third_party/blink/renderer/core/loader/BUILD.gn
@@ -20,9 +20,6 @@
     "document_load_timing.h",
     "document_loader.cc",
     "document_loader.h",
-    "document_threadable_loader.cc",
-    "document_threadable_loader.h",
-    "document_threadable_loader_client.h",
     "empty_clients.cc",
     "empty_clients.h",
     "form_submission.cc",
@@ -51,6 +48,8 @@
     "link_loader.cc",
     "link_loader.h",
     "link_loader_client.h",
+    "long_task_detector.cc",
+    "long_task_detector.h",
     "mixed_content_checker.cc",
     "mixed_content_checker.h",
     "modulescript/document_module_script_fetcher.cc",
@@ -130,8 +129,6 @@
     "threadable_loading_context.h",
     "worker_fetch_context.cc",
     "worker_fetch_context.h",
-    "worker_threadable_loader.cc",
-    "worker_threadable_loader.h",
   ]
 
   public_deps = [
diff --git a/third_party/blink/renderer/core/loader/document_threadable_loader.cc b/third_party/blink/renderer/core/loader/document_threadable_loader.cc
deleted file mode 100644
index 27721b93..0000000
--- a/third_party/blink/renderer/core/loader/document_threadable_loader.cc
+++ /dev/null
@@ -1,1262 +0,0 @@
-/*
- * Copyright (C) 2011, 2012 Google Inc. All rights reserved.
- * Copyright (C) 2013, Intel Corporation
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "third_party/blink/renderer/core/loader/document_threadable_loader.h"
-
-#include <memory>
-#include "base/memory/weak_ptr.h"
-#include "base/single_thread_task_runner.h"
-#include "services/network/public/cpp/cors/cors_error_status.h"
-#include "services/network/public/mojom/cors.mojom-blink.h"
-#include "services/network/public/mojom/fetch_api.mojom-blink.h"
-#include "third_party/blink/public/common/service_worker/service_worker_utils.h"
-#include "third_party/blink/public/platform/platform.h"
-#include "third_party/blink/public/platform/task_type.h"
-#include "third_party/blink/public/platform/web_cors.h"
-#include "third_party/blink/public/platform/web_security_origin.h"
-#include "third_party/blink/public/platform/web_url_request.h"
-#include "third_party/blink/renderer/core/dom/document.h"
-#include "third_party/blink/renderer/core/frame/frame_console.h"
-#include "third_party/blink/renderer/core/frame/local_frame.h"
-#include "third_party/blink/renderer/core/frame/local_frame_client.h"
-#include "third_party/blink/renderer/core/frame/web_feature.h"
-#include "third_party/blink/renderer/core/inspector/console_message.h"
-#include "third_party/blink/renderer/core/inspector/inspector_network_agent.h"
-#include "third_party/blink/renderer/core/inspector/inspector_trace_events.h"
-#include "third_party/blink/renderer/core/loader/base_fetch_context.h"
-#include "third_party/blink/renderer/core/loader/document_threadable_loader_client.h"
-#include "third_party/blink/renderer/core/loader/frame_loader.h"
-#include "third_party/blink/renderer/core/loader/threadable_loader_client.h"
-#include "third_party/blink/renderer/core/loader/threadable_loading_context.h"
-#include "third_party/blink/renderer/core/probe/core_probes.h"
-#include "third_party/blink/renderer/platform/exported/wrapped_resource_request.h"
-#include "third_party/blink/renderer/platform/heap/self_keep_alive.h"
-#include "third_party/blink/renderer/platform/loader/cors/cors.h"
-#include "third_party/blink/renderer/platform/loader/cors/cors_error_string.h"
-#include "third_party/blink/renderer/platform/loader/fetch/fetch_parameters.h"
-#include "third_party/blink/renderer/platform/loader/fetch/resource.h"
-#include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h"
-#include "third_party/blink/renderer/platform/loader/fetch/resource_loader.h"
-#include "third_party/blink/renderer/platform/loader/fetch/resource_loader_options.h"
-#include "third_party/blink/renderer/platform/loader/fetch/resource_request.h"
-#include "third_party/blink/renderer/platform/shared_buffer.h"
-#include "third_party/blink/renderer/platform/weborigin/scheme_registry.h"
-#include "third_party/blink/renderer/platform/weborigin/security_origin.h"
-#include "third_party/blink/renderer/platform/weborigin/security_policy.h"
-#include "third_party/blink/renderer/platform/wtf/assertions.h"
-
-namespace blink {
-
-namespace {
-
-// Fetch API Spec: https://fetch.spec.whatwg.org/#cors-preflight-fetch-0
-AtomicString CreateAccessControlRequestHeadersHeader(
-    const HTTPHeaderMap& headers) {
-  Vector<String> filtered_headers;
-  for (const auto& header : headers) {
-    // Exclude CORS-safelisted headers.
-    if (CORS::IsCORSSafelistedHeader(header.key, header.value))
-      continue;
-    // Calling a deprecated function, but eventually this function,
-    // |CreateAccessControlRequestHeadersHeader| will be removed.
-    // When the request is from a Worker, referrer header was added by
-    // WorkerThreadableLoader. But it should not be added to
-    // Access-Control-Request-Headers header.
-    if (DeprecatedEqualIgnoringCase(header.key, "referer"))
-      continue;
-    filtered_headers.push_back(header.key.DeprecatedLower());
-  }
-  if (!filtered_headers.size())
-    return g_null_atom;
-
-  // Sort header names lexicographically.
-  std::sort(filtered_headers.begin(), filtered_headers.end(),
-            WTF::CodePointCompareLessThan);
-  StringBuilder header_buffer;
-  for (const String& header : filtered_headers) {
-    if (!header_buffer.IsEmpty())
-      header_buffer.Append(",");
-    header_buffer.Append(header);
-  }
-
-  return header_buffer.ToAtomicString();
-}
-
-class EmptyDataHandle final : public WebDataConsumerHandle {
- private:
-  class EmptyDataReader final : public WebDataConsumerHandle::Reader {
-   public:
-    explicit EmptyDataReader(
-        WebDataConsumerHandle::Client* client,
-        scoped_refptr<base::SingleThreadTaskRunner> task_runner)
-        : factory_(this) {
-      task_runner->PostTask(
-          FROM_HERE, WTF::Bind(&EmptyDataReader::Notify, factory_.GetWeakPtr(),
-                               WTF::Unretained(client)));
-    }
-
-   private:
-    Result BeginRead(const void** buffer,
-                     WebDataConsumerHandle::Flags,
-                     size_t* available) override {
-      *available = 0;
-      *buffer = nullptr;
-      return kDone;
-    }
-    Result EndRead(size_t) override {
-      return WebDataConsumerHandle::kUnexpectedError;
-    }
-    void Notify(WebDataConsumerHandle::Client* client) {
-      client->DidGetReadable();
-    }
-    base::WeakPtrFactory<EmptyDataReader> factory_;
-  };
-
-  std::unique_ptr<Reader> ObtainReader(
-      Client* client,
-      scoped_refptr<base::SingleThreadTaskRunner> task_runner) override {
-    return std::make_unique<EmptyDataReader>(client, std::move(task_runner));
-  }
-  const char* DebugName() const override { return "EmptyDataHandle"; }
-};
-
-}  // namespace
-
-// DetachedClient is a ThreadableLoaderClient for a "detached"
-// DocumentThreadableLoader. It's for fetch requests with keepalive set, so
-// it keeps itself alive during loading.
-class DocumentThreadableLoader::DetachedClient final
-    : public GarbageCollectedFinalized<DetachedClient>,
-      public ThreadableLoaderClient {
- public:
-  explicit DetachedClient(DocumentThreadableLoader* loader)
-      : self_keep_alive_(this), loader_(loader) {}
-  ~DetachedClient() override {}
-
-  void DidFinishLoading(unsigned long identifier) override {
-    self_keep_alive_.Clear();
-  }
-  void DidFail(const ResourceError&) override { self_keep_alive_.Clear(); }
-  void DidFailRedirectCheck() override { self_keep_alive_.Clear(); }
-  void Trace(Visitor* visitor) { visitor->Trace(loader_); }
-
- private:
-  SelfKeepAlive<DetachedClient> self_keep_alive_;
-  // Keep it alive.
-  const Member<DocumentThreadableLoader> loader_;
-};
-
-// Max number of CORS redirects handled in DocumentThreadableLoader. Same number
-// as net/url_request/url_request.cc, and same number as
-// https://fetch.spec.whatwg.org/#concept-http-fetch, Step 4.
-// FIXME: currently the number of redirects is counted and limited here and in
-// net/url_request/url_request.cc separately.
-static const int kMaxCORSRedirects = 20;
-
-// static
-void DocumentThreadableLoader::LoadResourceSynchronously(
-    ThreadableLoadingContext& loading_context,
-    const ResourceRequest& request,
-    ThreadableLoaderClient& client,
-    const ThreadableLoaderOptions& options,
-    const ResourceLoaderOptions& resource_loader_options) {
-  (new DocumentThreadableLoader(loading_context, &client, kLoadSynchronously,
-                                options, resource_loader_options))
-      ->Start(request);
-}
-
-// static
-std::unique_ptr<ResourceRequest>
-DocumentThreadableLoader::CreateAccessControlPreflightRequest(
-    const ResourceRequest& request,
-    const SecurityOrigin* origin) {
-  const KURL& request_url = request.Url();
-
-  DCHECK(request_url.User().IsEmpty());
-  DCHECK(request_url.Pass().IsEmpty());
-
-  std::unique_ptr<ResourceRequest> preflight_request =
-      std::make_unique<ResourceRequest>(request_url);
-  preflight_request->SetHTTPMethod(HTTPNames::OPTIONS);
-  preflight_request->SetHTTPHeaderField(
-      HTTPNames::Access_Control_Request_Method, request.HttpMethod());
-  preflight_request->SetPriority(request.Priority());
-  preflight_request->SetRequestContext(request.GetRequestContext());
-  preflight_request->SetFetchCredentialsMode(
-      network::mojom::FetchCredentialsMode::kOmit);
-  preflight_request->SetSkipServiceWorker(true);
-  // TODO(domfarolino): Use ReferrerString() once https://crbug.com/850813 is
-  // closed and we stop storing the referrer string as a `Referer` header.
-  preflight_request->SetReferrerString(request.HttpReferrer());
-  preflight_request->SetReferrerPolicy(request.GetReferrerPolicy());
-
-  if (request.IsExternalRequest()) {
-    preflight_request->SetHTTPHeaderField(
-        HTTPNames::Access_Control_Request_External, "true");
-  }
-
-  const AtomicString request_headers =
-      CreateAccessControlRequestHeadersHeader(request.HttpHeaderFields());
-  if (request_headers != g_null_atom) {
-    preflight_request->SetHTTPHeaderField(
-        HTTPNames::Access_Control_Request_Headers, request_headers);
-  }
-
-  if (origin)
-    preflight_request->SetHTTPOrigin(origin);
-
-  return preflight_request;
-}
-
-// static
-std::unique_ptr<ResourceRequest>
-DocumentThreadableLoader::CreateAccessControlPreflightRequestForTesting(
-    const ResourceRequest& request) {
-  return CreateAccessControlPreflightRequest(request, nullptr);
-}
-
-// static
-DocumentThreadableLoader* DocumentThreadableLoader::Create(
-    ThreadableLoadingContext& loading_context,
-    ThreadableLoaderClient* client,
-    const ThreadableLoaderOptions& options,
-    const ResourceLoaderOptions& resource_loader_options) {
-  return new DocumentThreadableLoader(loading_context, client,
-                                      kLoadAsynchronously, options,
-                                      resource_loader_options);
-}
-
-DocumentThreadableLoader::DocumentThreadableLoader(
-    ThreadableLoadingContext& loading_context,
-    ThreadableLoaderClient* client,
-    BlockingBehavior blocking_behavior,
-    const ThreadableLoaderOptions& options,
-    const ResourceLoaderOptions& resource_loader_options)
-    : client_(client),
-      loading_context_(&loading_context),
-      options_(options),
-      resource_loader_options_(resource_loader_options),
-      out_of_blink_cors_(RuntimeEnabledFeatures::OutOfBlinkCORSEnabled()),
-      cors_flag_(false),
-      security_origin_(resource_loader_options_.security_origin),
-      is_using_data_consumer_handle_(false),
-      async_(blocking_behavior == kLoadAsynchronously),
-      request_context_(WebURLRequest::kRequestContextUnspecified),
-      fetch_request_mode_(network::mojom::FetchRequestMode::kSameOrigin),
-      fetch_credentials_mode_(network::mojom::FetchCredentialsMode::kOmit),
-      timeout_timer_(
-          GetExecutionContext()->GetTaskRunner(TaskType::kNetworking),
-          this,
-          &DocumentThreadableLoader::DidTimeout),
-      cors_redirect_limit_(0),
-      redirect_mode_(network::mojom::FetchRedirectMode::kFollow),
-      override_referrer_(false) {
-  DCHECK(client);
-}
-
-void DocumentThreadableLoader::Start(const ResourceRequest& request) {
-  // Setting an outgoing referer is only supported in the async code path.
-  DCHECK(async_ || request.HttpReferrer().IsEmpty());
-
-  bool cors_enabled =
-      CORS::IsCORSEnabledRequestMode(request.GetFetchRequestMode());
-
-  // kPreventPreflight can be used only when the CORS is enabled.
-  DCHECK(request.CORSPreflightPolicy() ==
-             network::mojom::CORSPreflightPolicy::kConsiderPreflight ||
-         cors_enabled);
-
-  if (cors_enabled)
-    cors_redirect_limit_ = kMaxCORSRedirects;
-
-  request_context_ = request.GetRequestContext();
-  fetch_request_mode_ = request.GetFetchRequestMode();
-  fetch_credentials_mode_ = request.GetFetchCredentialsMode();
-  redirect_mode_ = request.GetFetchRedirectMode();
-
-  if (request.GetFetchRequestMode() ==
-      network::mojom::FetchRequestMode::kNoCORS) {
-    SECURITY_CHECK(WebCORS::IsNoCORSAllowedContext(request_context_));
-  } else {
-    cors_flag_ = !GetSecurityOrigin()->CanRequest(request.Url());
-  }
-
-  // The CORS flag variable is not yet used at the step in the spec that
-  // corresponds to this line, but divert |cors_flag_| here for convenience.
-  if (cors_flag_ && request.GetFetchRequestMode() ==
-                        network::mojom::FetchRequestMode::kSameOrigin) {
-    ThreadableLoaderClient* client = client_;
-    Clear();
-    ResourceError error = ResourceError::CancelledDueToAccessCheckError(
-        request.Url(), ResourceRequestBlockedReason::kOther,
-        CORS::GetErrorString(
-            CORS::ErrorParameter::CreateForDisallowedByMode(request.Url())));
-    GetExecutionContext()->AddConsoleMessage(ConsoleMessage::Create(
-        kJSMessageSource, kErrorMessageLevel, error.LocalizedDescription()));
-    client->DidFail(error);
-    return;
-  }
-
-  request_started_ = CurrentTimeTicks();
-
-  // Save any headers on the request here. If this request redirects
-  // cross-origin, we cancel the old request create a new one, and copy these
-  // headers.
-  request_headers_ = request.HttpHeaderFields();
-
-  ResourceRequest new_request(request);
-
-  // Set the service worker mode to none if "bypass for network" in DevTools is
-  // enabled.
-  bool should_bypass_service_worker = false;
-  probe::shouldBypassServiceWorker(GetExecutionContext(),
-                                   &should_bypass_service_worker);
-  if (should_bypass_service_worker)
-    new_request.SetSkipServiceWorker(true);
-
-  // In S13nServiceWorker, if the controller service worker has no fetch event
-  // handler, it's skipped entirely, so we should treat that case the same as
-  // having no controller. In non-S13nServiceWorker, we can't do that since we
-  // don't know which service worker will handle the request since it's
-  // determined on the browser process and skipWaiting() can happen in the
-  // meantime.
-  //
-  // TODO(crbug.com/715640): When non-S13nServiceWorker is removed,
-  // is_controlled_by_service_worker is the same as
-  // ControllerServiceWorkerMode::kControlled, so this code can be simplified.
-  bool is_controlled_by_service_worker = false;
-  switch (
-      loading_context_->GetResourceFetcher()->IsControlledByServiceWorker()) {
-    case blink::mojom::ControllerServiceWorkerMode::kControlled:
-      is_controlled_by_service_worker = true;
-      break;
-    case blink::mojom::ControllerServiceWorkerMode::kNoFetchEventHandler:
-      if (ServiceWorkerUtils::IsServicificationEnabled())
-        is_controlled_by_service_worker = false;
-      else
-        is_controlled_by_service_worker = true;
-      break;
-    case blink::mojom::ControllerServiceWorkerMode::kNoController:
-      is_controlled_by_service_worker = false;
-      break;
-  }
-
-  // Process the CORS protocol inside the DocumentThreadableLoader for the
-  // following cases:
-  //
-  // - When the request is sync or the protocol is unsupported since we can
-  //   assume that any service worker (SW) is skipped for such requests by
-  //   content/ code.
-  // - When |skip_service_worker| is true, any SW will be skipped.
-  // - If we're not yet controlled by a SW, then we're sure that this
-  //   request won't be intercepted by a SW. In case we end up with
-  //   sending a CORS preflight request, the actual request to be sent later
-  //   may be intercepted. This is taken care of in LoadPreflightRequest() by
-  //   setting |skip_service_worker| to true.
-  //
-  // From the above analysis, you can see that the request can never be
-  // intercepted by a SW inside this if-block. It's because:
-  // - |skip_service_worker| needs to be false, and
-  // - we're controlled by a SW at this point
-  // to allow a SW to intercept the request. Even when the request gets issued
-  // asynchronously after performing the CORS preflight, it doesn't get
-  // intercepted since LoadPreflightRequest() sets the flag to kNone in advance.
-  if (!async_ || new_request.GetSkipServiceWorker() ||
-      !SchemeRegistry::ShouldTreatURLSchemeAsAllowingServiceWorkers(
-          new_request.Url().Protocol()) ||
-      !is_controlled_by_service_worker) {
-    DispatchInitialRequest(new_request);
-    return;
-  }
-
-  if (CORS::IsCORSEnabledRequestMode(request.GetFetchRequestMode())) {
-    // Save the request to fallback_request_for_service_worker to use when the
-    // service worker doesn't handle (call respondWith()) a CORS enabled
-    // request.
-    fallback_request_for_service_worker_ = ResourceRequest(request);
-    // Skip the service worker for the fallback request.
-    fallback_request_for_service_worker_.SetSkipServiceWorker(true);
-  }
-
-  LoadRequest(new_request, resource_loader_options_);
-}
-
-void DocumentThreadableLoader::DispatchInitialRequest(
-    ResourceRequest& request) {
-  if (out_of_blink_cors_ || (!request.IsExternalRequest() && !cors_flag_)) {
-    LoadRequest(request, resource_loader_options_);
-    return;
-  }
-
-  DCHECK(CORS::IsCORSEnabledRequestMode(request.GetFetchRequestMode()) ||
-         request.IsExternalRequest());
-
-  MakeCrossOriginAccessRequest(request);
-}
-
-void DocumentThreadableLoader::PrepareCrossOriginRequest(
-    ResourceRequest& request) const {
-  if (GetSecurityOrigin())
-    request.SetHTTPOrigin(GetSecurityOrigin());
-
-  // TODO(domfarolino): Stop setting the HTTPReferrer header, and instead use
-  // ResourceRequest::referrer_. See https://crbug.com/850813.
-  if (override_referrer_)
-    request.SetHTTPReferrer(referrer_after_redirect_);
-}
-
-void DocumentThreadableLoader::LoadPreflightRequest(
-    const ResourceRequest& actual_request,
-    const ResourceLoaderOptions& actual_options) {
-  std::unique_ptr<ResourceRequest> preflight_request =
-      CreateAccessControlPreflightRequest(actual_request, GetSecurityOrigin());
-
-  actual_request_ = actual_request;
-  actual_options_ = actual_options;
-
-  // Explicitly set |skip_service_worker| to true here. Although the page is
-  // not controlled by a SW at this point, a new SW may be controlling the
-  // page when this actual request gets sent later. We should not send the
-  // actual request to the SW. See https://crbug.com/604583.
-  actual_request_.SetSkipServiceWorker(true);
-
-  // Create a ResourceLoaderOptions for preflight.
-  ResourceLoaderOptions preflight_options = actual_options;
-
-  LoadRequest(*preflight_request, preflight_options);
-}
-
-void DocumentThreadableLoader::MakeCrossOriginAccessRequest(
-    const ResourceRequest& request) {
-  DCHECK(CORS::IsCORSEnabledRequestMode(request.GetFetchRequestMode()) ||
-         request.IsExternalRequest());
-  DCHECK(client_);
-  DCHECK(!GetResource());
-
-  // Cross-origin requests are only allowed certain registered schemes. We would
-  // catch this when checking response headers later, but there is no reason to
-  // send a request, preflighted or not, that's guaranteed to be denied.
-  if (!SchemeRegistry::ShouldTreatURLSchemeAsCORSEnabled(
-          request.Url().Protocol())) {
-    DispatchDidFailAccessControlCheck(
-        ResourceError::CancelledDueToAccessCheckError(
-            request.Url(), ResourceRequestBlockedReason::kOther,
-            String::Format(
-                "Cross origin requests are only supported for protocol "
-                "schemes: %s.",
-                SchemeRegistry::ListOfCORSEnabledURLSchemes().Ascii().data())));
-    return;
-  }
-
-  // Non-secure origins may not make "external requests":
-  // https://wicg.github.io/cors-rfc1918/#integration-fetch
-  String error_message;
-  if (!GetExecutionContext()->IsSecureContext(error_message) &&
-      request.IsExternalRequest()) {
-    DispatchDidFailAccessControlCheck(
-        ResourceError::CancelledDueToAccessCheckError(
-            request.Url(), ResourceRequestBlockedReason::kOrigin,
-            "Requests to internal network resources are not allowed "
-            "from non-secure contexts (see https://goo.gl/Y0ZkNV). "
-            "This is an experimental restriction which is part of "
-            "'https://mikewest.github.io/cors-rfc1918/'."));
-    return;
-  }
-
-  ResourceRequest cross_origin_request(request);
-  ResourceLoaderOptions cross_origin_options(resource_loader_options_);
-
-  cross_origin_request.RemoveUserAndPassFromURL();
-
-  // Enforce the CORS preflight for checking the Access-Control-Allow-External
-  // header. The CORS preflight cache doesn't help for this purpose.
-  if (request.IsExternalRequest()) {
-    LoadPreflightRequest(cross_origin_request, cross_origin_options);
-    return;
-  }
-
-  if (request.GetFetchRequestMode() !=
-      network::mojom::FetchRequestMode::kCORSWithForcedPreflight) {
-    if (request.CORSPreflightPolicy() ==
-        network::mojom::CORSPreflightPolicy::kPreventPreflight) {
-      PrepareCrossOriginRequest(cross_origin_request);
-      LoadRequest(cross_origin_request, cross_origin_options);
-      return;
-    }
-
-    DCHECK_EQ(request.CORSPreflightPolicy(),
-              network::mojom::CORSPreflightPolicy::kConsiderPreflight);
-
-    // We use ContainsOnlyCORSSafelistedOrForbiddenHeaders() here since
-    // |request| may have been modified in the process of loading (not from
-    // the user's input). For example, referrer. We need to accept them. For
-    // security, we must reject forbidden headers/methods at the point we
-    // accept user's input. Not here.
-    if (CORS::IsCORSSafelistedMethod(request.HttpMethod()) &&
-        CORS::ContainsOnlyCORSSafelistedOrForbiddenHeaders(
-            request.HttpHeaderFields())) {
-      PrepareCrossOriginRequest(cross_origin_request);
-      LoadRequest(cross_origin_request, cross_origin_options);
-      return;
-    }
-  }
-
-  // Now, we need to check that the request passes the CORS preflight either by
-  // issuing a CORS preflight or based on an entry in the CORS preflight cache.
-
-  bool should_ignore_preflight_cache = false;
-  // Prevent use of the CORS preflight cache when instructed by the DevTools
-  // not to use caches.
-  probe::shouldForceCORSPreflight(GetExecutionContext(),
-                                  &should_ignore_preflight_cache);
-  if (should_ignore_preflight_cache ||
-      !CORS::CheckIfRequestCanSkipPreflight(
-          GetSecurityOrigin()->ToString(), cross_origin_request.Url(),
-          cross_origin_request.GetFetchCredentialsMode(),
-          cross_origin_request.HttpMethod(),
-          cross_origin_request.HttpHeaderFields())) {
-    LoadPreflightRequest(cross_origin_request, cross_origin_options);
-    return;
-  }
-
-  // We don't want any requests that could involve a CORS preflight to get
-  // intercepted by a foreign SW, even if we have the result of the preflight
-  // cached already. See https://crbug.com/674370.
-  cross_origin_request.SetSkipServiceWorker(true);
-
-  PrepareCrossOriginRequest(cross_origin_request);
-  LoadRequest(cross_origin_request, cross_origin_options);
-}
-
-DocumentThreadableLoader::~DocumentThreadableLoader() {
-  // |client_| is a raw pointer and having a non-null |client_| here probably
-  // means UaF.
-  // In the detached case, |this| is held by DetachedClient defined above, but
-  // SelfKeepAlive in DetachedClient is forcibly cancelled on worker thread
-  // termination. We can safely ignore this case.
-  CHECK(!client_ || detached_);
-  DCHECK(!GetResource());
-}
-
-void DocumentThreadableLoader::OverrideTimeout(
-    unsigned long timeout_milliseconds) {
-  DCHECK(async_);
-
-  // |m_requestStartedSeconds| == 0.0 indicates loading is already finished and
-  // |m_timeoutTimer| is already stopped, and thus we do nothing for such cases.
-  // See https://crbug.com/551663 for details.
-  if (request_started_ <= TimeTicks())
-    return;
-
-  timeout_timer_.Stop();
-  // At the time of this method's implementation, it is only ever called by
-  // XMLHttpRequest, when the timeout attribute is set after sending the
-  // request.
-  //
-  // The XHR request says to resolve the time relative to when the request
-  // was initially sent, however other uses of this method may need to
-  // behave differently, in which case this should be re-arranged somehow.
-  if (timeout_milliseconds) {
-    TimeDelta elapsed_time = CurrentTimeTicks() - request_started_;
-    TimeDelta next_fire = TimeDelta::FromMilliseconds(timeout_milliseconds);
-    TimeDelta resolved_time = std::max(next_fire - elapsed_time, TimeDelta());
-    timeout_timer_.StartOneShot(resolved_time, FROM_HERE);
-  }
-}
-
-void DocumentThreadableLoader::Cancel() {
-  // Cancel can re-enter, and therefore |resource()| might be null here as a
-  // result.
-  if (!client_ || !GetResource()) {
-    Clear();
-    return;
-  }
-
-  DispatchDidFail(ResourceError::CancelledError(GetResource()->Url()));
-}
-
-void DocumentThreadableLoader::Detach() {
-  Resource* resource = GetResource();
-  if (!resource)
-    return;
-  detached_ = true;
-  client_ = new DetachedClient(this);
-}
-
-void DocumentThreadableLoader::SetDefersLoading(bool value) {
-  if (GetResource() && GetResource()->Loader())
-    GetResource()->Loader()->SetDefersLoading(value);
-}
-
-void DocumentThreadableLoader::Clear() {
-  client_ = nullptr;
-  timeout_timer_.Stop();
-  request_started_ = TimeTicks();
-  if (GetResource())
-    checker_.WillRemoveClient();
-  ClearResource();
-}
-
-// In this method, we can clear |request| to tell content::WebURLLoaderImpl of
-// Chromium not to follow the redirect. This works only when this method is
-// called by RawResource::willSendRequest(). If called by
-// RawResource::didAddClient(), clearing |request| won't be propagated to
-// content::WebURLLoaderImpl. So, this loader must also get detached from the
-// resource by calling clearResource().
-// TODO(toyoshim): Implement OOR-CORS mode specific redirect code.
-bool DocumentThreadableLoader::RedirectReceived(
-    Resource* resource,
-    const ResourceRequest& new_request,
-    const ResourceResponse& redirect_response) {
-  DCHECK(client_);
-  DCHECK_EQ(resource, GetResource());
-
-  checker_.RedirectReceived();
-
-  const KURL& new_url = new_request.Url();
-  const KURL& original_url = redirect_response.Url();
-
-  if (!actual_request_.IsNull()) {
-    DCHECK(!out_of_blink_cors_);
-    ReportResponseReceived(resource->Identifier(), redirect_response);
-
-    HandlePreflightFailure(
-        original_url, CORS::GetErrorString(
-                          CORS::ErrorParameter::CreateForDisallowedRedirect()));
-
-    return false;
-  }
-
-  if (redirect_mode_ == network::mojom::FetchRedirectMode::kManual) {
-    // We use |redirect_mode_| to check the original redirect mode.
-    // |new_request| is a new request for redirect. So we don't set the
-    // redirect mode of it in WebURLLoaderImpl::Context::OnReceivedRedirect().
-    DCHECK(new_request.UseStreamOnResponse());
-    // There is no need to read the body of redirect response because there is
-    // no way to read the body of opaque-redirect filtered response's internal
-    // response.
-    // TODO(horo): If we support any API which expose the internal body, we will
-    // have to read the body. And also HTTPCache changes will be needed because
-    // it doesn't store the body of redirect responses.
-    ResponseReceived(resource, redirect_response,
-                     std::make_unique<EmptyDataHandle>());
-
-    if (client_) {
-      DCHECK(actual_request_.IsNull());
-      NotifyFinished(resource);
-    }
-
-    return false;
-  }
-
-  if (redirect_mode_ == network::mojom::FetchRedirectMode::kError) {
-    ThreadableLoaderClient* client = client_;
-    Clear();
-    client->DidFailRedirectCheck();
-
-    return false;
-  }
-
-  if (out_of_blink_cors_) {
-    client_->DidReceiveRedirectTo(new_url);
-    if (client_->IsDocumentThreadableLoaderClient()) {
-      return static_cast<DocumentThreadableLoaderClient*>(client_)
-          ->WillFollowRedirect(new_url, redirect_response);
-    }
-    return true;
-  }
-
-  // Allow same origin requests to continue after allowing clients to audit the
-  // redirect.
-  if (IsAllowedRedirect(new_request.GetFetchRequestMode(), new_url)) {
-    client_->DidReceiveRedirectTo(new_url);
-    if (client_->IsDocumentThreadableLoaderClient()) {
-      return static_cast<DocumentThreadableLoaderClient*>(client_)
-          ->WillFollowRedirect(new_url, redirect_response);
-    }
-    return true;
-  }
-
-  if (cors_redirect_limit_ <= 0) {
-    ThreadableLoaderClient* client = client_;
-    Clear();
-    client->DidFailRedirectCheck();
-    return false;
-  }
-
-  --cors_redirect_limit_;
-
-  probe::didReceiveCORSRedirectResponse(
-      GetExecutionContext(), resource->Identifier(),
-      GetDocument() && GetDocument()->GetFrame()
-          ? GetDocument()->GetFrame()->Loader().GetDocumentLoader()
-          : nullptr,
-      redirect_response, resource);
-
-  base::Optional<network::mojom::CORSError> redirect_error =
-      CORS::CheckRedirectLocation(new_url);
-  if (redirect_error) {
-    DispatchDidFailAccessControlCheck(
-        ResourceError::CancelledDueToAccessCheckError(
-            original_url, ResourceRequestBlockedReason::kOther,
-            CORS::GetErrorString(CORS::ErrorParameter::CreateForRedirectCheck(
-                *redirect_error, original_url, new_url))));
-    return false;
-  }
-
-  if (cors_flag_) {
-    // The redirect response must pass the access control check if the CORS
-    // flag is set.
-    base::Optional<network::CORSErrorStatus> access_error = CORS::CheckAccess(
-        original_url, redirect_response.HttpStatusCode(),
-        redirect_response.HttpHeaderFields(),
-        new_request.GetFetchCredentialsMode(), *GetSecurityOrigin());
-    if (access_error) {
-      DispatchDidFailAccessControlCheck(
-          ResourceError::CancelledDueToAccessCheckError(
-              original_url, ResourceRequestBlockedReason::kOther,
-              CORS::GetErrorString(CORS::ErrorParameter::CreateForAccessCheck(
-                  *access_error, original_url,
-                  redirect_response.HttpStatusCode(), *GetSecurityOrigin(),
-                  request_context_, new_url))));
-      return false;
-    }
-  }
-
-  client_->DidReceiveRedirectTo(new_url);
-
-  // FIXME: consider combining this with CORS redirect handling performed by
-  // CrossOriginAccessControl::handleRedirect().
-  if (GetResource())
-    checker_.WillRemoveClient();
-  ClearResource();
-
-  // If
-  // - CORS flag is set, and
-  // - the origin of the redirect target URL is not same origin with the origin
-  //   of the current request's URL
-  // set the source origin to a unique opaque origin.
-  //
-  // See https://fetch.spec.whatwg.org/#http-redirect-fetch.
-  if (cors_flag_) {
-    scoped_refptr<const SecurityOrigin> original_origin =
-        SecurityOrigin::Create(original_url);
-    scoped_refptr<const SecurityOrigin> new_origin =
-        SecurityOrigin::Create(new_url);
-    if (!original_origin->IsSameSchemeHostPort(new_origin.get()))
-      security_origin_ = SecurityOrigin::CreateUniqueOpaque();
-  }
-
-  // Set |cors_flag_| so that further logic (corresponds to the main fetch in
-  // the spec) will be performed with CORS flag set.
-  // See https://fetch.spec.whatwg.org/#http-redirect-fetch.
-  cors_flag_ = true;
-
-  // Save the referrer to use when following the redirect.
-  override_referrer_ = true;
-  // TODO(domfarolino): Use ReferrerString() once https://crbug.com/850813 is
-  // closed and we stop storing the referrer string as a `Referer` header.
-  referrer_after_redirect_ =
-      Referrer(new_request.HttpReferrer(), new_request.GetReferrerPolicy());
-
-  ResourceRequest cross_origin_request(new_request);
-
-  // Remove any headers that may have been added by the network layer that cause
-  // access control to fail.
-  cross_origin_request.ClearHTTPReferrer();
-  cross_origin_request.ClearHTTPOrigin();
-  cross_origin_request.ClearHTTPUserAgent();
-  // Add any request headers which we previously saved from the
-  // original request.
-  for (const auto& header : request_headers_)
-    cross_origin_request.SetHTTPHeaderField(header.key, header.value);
-  MakeCrossOriginAccessRequest(cross_origin_request);
-
-  return false;
-}
-
-void DocumentThreadableLoader::RedirectBlocked() {
-  checker_.RedirectBlocked();
-
-  // Tells the client that a redirect was received but not followed (for an
-  // unknown reason).
-  ThreadableLoaderClient* client = client_;
-  Clear();
-  client->DidFailRedirectCheck();
-}
-
-void DocumentThreadableLoader::DataSent(
-    Resource* resource,
-    unsigned long long bytes_sent,
-    unsigned long long total_bytes_to_be_sent) {
-  DCHECK(client_);
-  DCHECK_EQ(resource, GetResource());
-  DCHECK(async_);
-
-  checker_.DataSent();
-  client_->DidSendData(bytes_sent, total_bytes_to_be_sent);
-}
-
-void DocumentThreadableLoader::DataDownloaded(Resource* resource,
-                                              int data_length) {
-  DCHECK(client_);
-  DCHECK_EQ(resource, GetResource());
-  DCHECK(actual_request_.IsNull());
-
-  checker_.DataDownloaded();
-  client_->DidDownloadData(data_length);
-}
-
-void DocumentThreadableLoader::DidReceiveResourceTiming(
-    Resource* resource,
-    const ResourceTimingInfo& info) {
-  DCHECK(client_);
-  DCHECK_EQ(resource, GetResource());
-
-  client_->DidReceiveResourceTiming(info);
-}
-
-void DocumentThreadableLoader::DidDownloadToBlob(
-    Resource* resource,
-    scoped_refptr<BlobDataHandle> blob) {
-  DCHECK(client_);
-  DCHECK_EQ(resource, GetResource());
-
-  checker_.DidDownloadToBlob();
-  client_->DidDownloadToBlob(std::move(blob));
-}
-
-
-void DocumentThreadableLoader::HandlePreflightResponse(
-    const ResourceResponse& response) {
-  base::Optional<network::CORSErrorStatus> cors_error_status =
-      CORS::CheckPreflightAccess(response.Url(), response.HttpStatusCode(),
-                                 response.HttpHeaderFields(),
-                                 actual_request_.GetFetchCredentialsMode(),
-                                 *GetSecurityOrigin());
-  if (cors_error_status) {
-    HandlePreflightFailure(
-        response.Url(),
-        CORS::GetErrorString(CORS::ErrorParameter::CreateForAccessCheck(
-            *cors_error_status, response.Url(), 0 /* status_code */,
-            *GetSecurityOrigin(), request_context_)));
-    return;
-  }
-
-  base::Optional<network::mojom::CORSError> preflight_error =
-      CORS::CheckPreflight(response.HttpStatusCode());
-  if (preflight_error) {
-    HandlePreflightFailure(
-        response.Url(), CORS::GetErrorString(
-                            CORS::ErrorParameter::CreateForPreflightStatusCheck(
-                                response.HttpStatusCode())));
-    return;
-  }
-
-  if (actual_request_.IsExternalRequest()) {
-    base::Optional<network::CORSErrorStatus> external_preflight_status =
-        CORS::CheckExternalPreflight(response.HttpHeaderFields());
-    if (external_preflight_status) {
-      HandlePreflightFailure(
-          response.Url(),
-          CORS::GetErrorString(
-              CORS::ErrorParameter::CreateForExternalPreflightCheck(
-                  *external_preflight_status)));
-      return;
-    }
-  }
-
-  String access_control_error_description;
-  if (!CORS::EnsurePreflightResultAndCacheOnSuccess(
-          response.HttpHeaderFields(), GetSecurityOrigin()->ToString(),
-          actual_request_.Url(), actual_request_.HttpMethod(),
-          actual_request_.HttpHeaderFields(),
-          actual_request_.GetFetchCredentialsMode(),
-          &access_control_error_description)) {
-    HandlePreflightFailure(response.Url(), access_control_error_description);
-  }
-}
-
-void DocumentThreadableLoader::ReportResponseReceived(
-    unsigned long identifier,
-    const ResourceResponse& response) {
-  LocalFrame* frame = GetDocument() ? GetDocument()->GetFrame() : nullptr;
-  if (!frame)
-    return;
-  DocumentLoader* loader = frame->Loader().GetDocumentLoader();
-  probe::didReceiveResourceResponse(GetExecutionContext(), identifier, loader,
-                                    response, GetResource());
-  frame->Console().ReportResourceResponseReceived(loader, identifier, response);
-}
-
-void DocumentThreadableLoader::ResponseReceived(
-    Resource* resource,
-    const ResourceResponse& response,
-    std::unique_ptr<WebDataConsumerHandle> handle) {
-  DCHECK_EQ(resource, GetResource());
-  DCHECK(client_);
-
-  checker_.ResponseReceived();
-
-  if (handle)
-    is_using_data_consumer_handle_ = true;
-
-  // TODO(toyoshim): Support OOR-CORS preflight and Service Worker case.
-  // Note that CORS-preflight is usually handled in the Network Service side,
-  // but still done in Blink side when it is needed on redirects.
-  // https://crbug.com/736308.
-  if (out_of_blink_cors_ && !response.WasFetchedViaServiceWorker()) {
-    DCHECK(actual_request_.IsNull());
-    fallback_request_for_service_worker_ = ResourceRequest();
-    client_->DidReceiveResponse(resource->Identifier(), response,
-                                std::move(handle));
-    return;
-  }
-
-  // Code path for legacy Blink CORS.
-  if (!actual_request_.IsNull()) {
-    ReportResponseReceived(resource->Identifier(), response);
-    HandlePreflightResponse(response);
-    return;
-  }
-
-  if (response.WasFetchedViaServiceWorker()) {
-    if (response.WasFallbackRequiredByServiceWorker()) {
-      // At this point we must have m_fallbackRequestForServiceWorker. (For
-      // SharedWorker the request won't be CORS or CORS-with-preflight,
-      // therefore fallback-to-network is handled in the browser process when
-      // the ServiceWorker does not call respondWith().)
-      DCHECK(!fallback_request_for_service_worker_.IsNull());
-      ReportResponseReceived(resource->Identifier(), response);
-      LoadFallbackRequestForServiceWorker();
-      return;
-    }
-
-    // It's possible that we issue a fetch with request with non "no-cors"
-    // mode but get an opaque filtered response if a service worker is involved.
-    // We dispatch a CORS failure for the case.
-    // TODO(yhirano): This is probably not spec conformant. Fix it after
-    // https://github.com/w3c/preload/issues/100 is addressed.
-    if (fetch_request_mode_ != network::mojom::FetchRequestMode::kNoCORS &&
-        response.ResponseTypeViaServiceWorker() ==
-            network::mojom::FetchResponseType::kOpaque) {
-      DispatchDidFailAccessControlCheck(
-          ResourceError::CancelledDueToAccessCheckError(
-              response.Url(), ResourceRequestBlockedReason::kOther,
-              CORS::GetErrorString(
-                  CORS::ErrorParameter::CreateForInvalidResponse(
-                      response.Url(), *GetSecurityOrigin()))));
-      return;
-    }
-
-    fallback_request_for_service_worker_ = ResourceRequest();
-    client_->DidReceiveResponse(resource->Identifier(), response,
-                                std::move(handle));
-    return;
-  }
-
-  // Even if the request met the conditions to get handled by a Service Worker
-  // in the constructor of this class (and therefore
-  // |m_fallbackRequestForServiceWorker| is set), the Service Worker may skip
-  // processing the request. Only if the request is same origin, the skipped
-  // response may come here (wasFetchedViaServiceWorker() returns false) since
-  // such a request doesn't have to go through the CORS algorithm by calling
-  // loadFallbackRequestForServiceWorker().
-  DCHECK(fallback_request_for_service_worker_.IsNull() ||
-         GetSecurityOrigin()->CanRequest(
-             fallback_request_for_service_worker_.Url()));
-  fallback_request_for_service_worker_ = ResourceRequest();
-
-  if (CORS::IsCORSEnabledRequestMode(fetch_request_mode_) && cors_flag_) {
-    base::Optional<network::CORSErrorStatus> access_error = CORS::CheckAccess(
-        response.Url(), response.HttpStatusCode(), response.HttpHeaderFields(),
-        fetch_credentials_mode_, *GetSecurityOrigin());
-    if (access_error) {
-      ReportResponseReceived(resource->Identifier(), response);
-      DispatchDidFailAccessControlCheck(
-          ResourceError::CancelledDueToAccessCheckError(
-              response.Url(), ResourceRequestBlockedReason::kOther,
-              CORS::GetErrorString(CORS::ErrorParameter::CreateForAccessCheck(
-                  *access_error, response.Url(), response.HttpStatusCode(),
-                  *GetSecurityOrigin(), request_context_))));
-      return;
-    }
-  }
-
-  client_->DidReceiveResponse(resource->Identifier(), response,
-                              std::move(handle));
-}
-
-void DocumentThreadableLoader::SetSerializedCachedMetadata(Resource*,
-                                                           const char* data,
-                                                           size_t size) {
-  checker_.SetSerializedCachedMetadata();
-
-  if (!actual_request_.IsNull())
-    return;
-  client_->DidReceiveCachedMetadata(data, size);
-}
-
-void DocumentThreadableLoader::DataReceived(Resource* resource,
-                                            const char* data,
-                                            size_t data_length) {
-  DCHECK_EQ(resource, GetResource());
-  DCHECK(client_);
-
-  checker_.DataReceived();
-
-  if (is_using_data_consumer_handle_)
-    return;
-
-  // Preflight data should be invisible to clients.
-  if (!actual_request_.IsNull())
-    return;
-
-  DCHECK(fallback_request_for_service_worker_.IsNull());
-
-  // TODO(junov): Fix the ThreadableLoader ecosystem to use size_t. Until then,
-  // we use safeCast to trap potential overflows.
-  client_->DidReceiveData(data, SafeCast<unsigned>(data_length));
-}
-
-void DocumentThreadableLoader::NotifyFinished(Resource* resource) {
-  DCHECK(client_);
-  DCHECK_EQ(resource, GetResource());
-
-  checker_.NotifyFinished(resource);
-
-  // Don't throw an exception for failed sync local file loads.
-  // TODO(japhet): This logic has been moved around but unchanged since 2007.
-  // Tested by fast/xmlhttprequest/xmlhttprequest-missing-file-exception.html
-  // Do we still need this?
-  bool is_sync_to_local_file = resource->Url().IsLocalFile() && !async_;
-
-  if (resource->ErrorOccurred() && !is_sync_to_local_file) {
-    DispatchDidFail(resource->GetResourceError());
-    return;
-  }
-
-  DCHECK(fallback_request_for_service_worker_.IsNull());
-
-  if (!actual_request_.IsNull()) {
-    DCHECK(actual_request_.IsExternalRequest() || cors_flag_);
-    LoadActualRequest();
-    return;
-  }
-
-  ThreadableLoaderClient* client = client_;
-  // Protect the resource in |didFinishLoading| in order not to release the
-  // downloaded file.
-  Persistent<Resource> protect = GetResource();
-  Clear();
-  client->DidFinishLoading(resource->Identifier());
-}
-
-void DocumentThreadableLoader::DidTimeout(TimerBase* timer) {
-  DCHECK(async_);
-  DCHECK_EQ(timer, &timeout_timer_);
-  // clearResource() may be called in clear() and some other places. clear()
-  // calls stop() on |m_timeoutTimer|. In the other places, the resource is set
-  // again. If the creation fails, clear() is called. So, here, resource() is
-  // always non-nullptr.
-  DCHECK(GetResource());
-  // When |m_client| is set to nullptr only in clear() where |m_timeoutTimer|
-  // is stopped. So, |m_client| is always non-nullptr here.
-  DCHECK(client_);
-
-  DispatchDidFail(ResourceError::TimeoutError(GetResource()->Url()));
-}
-
-void DocumentThreadableLoader::LoadFallbackRequestForServiceWorker() {
-  if (GetResource())
-    checker_.WillRemoveClient();
-  ClearResource();
-  ResourceRequest fallback_request(fallback_request_for_service_worker_);
-  fallback_request_for_service_worker_ = ResourceRequest();
-  DispatchInitialRequest(fallback_request);
-}
-
-void DocumentThreadableLoader::LoadActualRequest() {
-  ResourceRequest actual_request = actual_request_;
-  ResourceLoaderOptions actual_options = actual_options_;
-  actual_request_ = ResourceRequest();
-  actual_options_ = ResourceLoaderOptions();
-
-  if (GetResource())
-    checker_.WillRemoveClient();
-  ClearResource();
-
-  PrepareCrossOriginRequest(actual_request);
-  LoadRequest(actual_request, actual_options);
-}
-
-void DocumentThreadableLoader::HandlePreflightFailure(
-    const KURL& url,
-    const String& error_description) {
-  // Prevent NotifyFinished() from bypassing access check.
-  actual_request_ = ResourceRequest();
-
-  DispatchDidFailAccessControlCheck(
-      ResourceError::CancelledDueToAccessCheckError(
-          url, ResourceRequestBlockedReason::kOther, error_description));
-}
-
-void DocumentThreadableLoader::DispatchDidFailAccessControlCheck(
-    const ResourceError& error) {
-  const String message = "Failed to load " + error.FailingURL() + ": " +
-                         error.LocalizedDescription();
-  GetExecutionContext()->AddConsoleMessage(
-      ConsoleMessage::Create(kJSMessageSource, kErrorMessageLevel, message));
-
-  ThreadableLoaderClient* client = client_;
-  Clear();
-  client->DidFail(error);
-}
-
-void DocumentThreadableLoader::DispatchDidFail(const ResourceError& error) {
-  if (error.CORSErrorStatus()) {
-    DCHECK(out_of_blink_cors_);
-    // TODO(toyoshim): Should consider to pass correct arguments instead of
-    // KURL(), and 0 to GetErrorString().
-    // We still need plumbing some more information.
-    GetExecutionContext()->AddConsoleMessage(ConsoleMessage::Create(
-        kJSMessageSource, kErrorMessageLevel,
-        "Failed to load " + error.FailingURL() + ": " +
-            CORS::GetErrorString(CORS::ErrorParameter::Create(
-                                     *error.CORSErrorStatus(),
-                                     KURL(error.FailingURL()), KURL(), 0,
-                                     *GetSecurityOrigin(), request_context_))
-                .Utf8()
-                .data()));
-  }
-  ThreadableLoaderClient* client = client_;
-  Clear();
-  client->DidFail(error);
-}
-
-
-void DocumentThreadableLoader::LoadRequest(
-    ResourceRequest& request,
-    ResourceLoaderOptions resource_loader_options) {
-  resource_loader_options.cors_handling_by_resource_fetcher =
-      kDisableCORSHandlingByResourceFetcher;
-
-  bool allow_stored_credentials = false;
-  switch (request.GetFetchCredentialsMode()) {
-    case network::mojom::FetchCredentialsMode::kOmit:
-      break;
-    case network::mojom::FetchCredentialsMode::kSameOrigin:
-      // TODO(toyoshim): It's wrong to use |cors_flag| here. Fix it to use the
-      // response tainting.
-      //
-      // TODO(toyoshim): The credentials mode must work even when the "no-cors"
-      // mode is in use. See the following issues:
-      // - https://github.com/whatwg/fetch/issues/130
-      // - https://github.com/whatwg/fetch/issues/169
-      allow_stored_credentials = !cors_flag_;
-      break;
-    case network::mojom::FetchCredentialsMode::kInclude:
-      allow_stored_credentials = true;
-      break;
-  }
-  request.SetAllowStoredCredentials(allow_stored_credentials);
-
-  resource_loader_options.security_origin = security_origin_;
-
-  if (!actual_request_.IsNull())
-    resource_loader_options.data_buffering_policy = kBufferData;
-
-  TimeDelta timeout =
-      TimeDelta::FromMilliseconds(options_.timeout_milliseconds);
-  if (options_.timeout_milliseconds > 0) {
-    if (!async_) {
-      request.SetTimeoutInterval(timeout);
-    } else if (!timeout_timer_.IsActive()) {
-      // The timer can be active if this is the actual request of a
-      // CORS-with-preflight request.
-      timeout_timer_.StartOneShot(timeout, FROM_HERE);
-    }
-  }
-
-  FetchParameters new_params(request, resource_loader_options);
-  DCHECK(!GetResource());
-
-  checker_.WillAddClient();
-  ResourceFetcher* fetcher = loading_context_->GetResourceFetcher();
-  if (request.GetRequestContext() == WebURLRequest::kRequestContextVideo ||
-      request.GetRequestContext() == WebURLRequest::kRequestContextAudio) {
-    DCHECK(async_);
-    RawResource::FetchMedia(new_params, fetcher, this);
-  } else if (request.GetRequestContext() ==
-             WebURLRequest::kRequestContextManifest) {
-    DCHECK(async_);
-    RawResource::FetchManifest(new_params, fetcher, this);
-  } else if (async_) {
-    RawResource::Fetch(new_params, fetcher, this);
-  } else {
-    RawResource::FetchSynchronously(new_params, fetcher, this);
-  }
-}
-
-bool DocumentThreadableLoader::IsAllowedRedirect(
-    network::mojom::FetchRequestMode fetch_request_mode,
-    const KURL& url) const {
-  if (fetch_request_mode == network::mojom::FetchRequestMode::kNoCORS)
-    return true;
-
-  return !cors_flag_ && GetSecurityOrigin()->CanRequest(url);
-}
-
-const SecurityOrigin* DocumentThreadableLoader::GetSecurityOrigin() const {
-  return security_origin_
-             ? security_origin_.get()
-             : loading_context_->GetFetchContext()->GetSecurityOrigin();
-}
-
-Document* DocumentThreadableLoader::GetDocument() const {
-  ExecutionContext* context = GetExecutionContext();
-  if (context->IsDocument())
-    return ToDocument(context);
-  return nullptr;
-}
-
-ExecutionContext* DocumentThreadableLoader::GetExecutionContext() const {
-  DCHECK(loading_context_);
-  return loading_context_->GetExecutionContext();
-}
-
-void DocumentThreadableLoader::Trace(blink::Visitor* visitor) {
-  visitor->Trace(loading_context_);
-  ThreadableLoader::Trace(visitor);
-  RawResourceClient::Trace(visitor);
-}
-
-}  // namespace blink
diff --git a/third_party/blink/renderer/core/loader/document_threadable_loader.h b/third_party/blink/renderer/core/loader/document_threadable_loader.h
deleted file mode 100644
index 2082201e..0000000
--- a/third_party/blink/renderer/core/loader/document_threadable_loader.h
+++ /dev/null
@@ -1,244 +0,0 @@
-/*
- * Copyright (C) 2009, 2012 Google Inc. All rights reserved.
- * Copyright (C) 2013, Intel Corporation
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_DOCUMENT_THREADABLE_LOADER_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_DOCUMENT_THREADABLE_LOADER_H_
-
-#include <memory>
-#include "services/network/public/mojom/fetch_api.mojom-blink.h"
-#include "third_party/blink/renderer/core/core_export.h"
-#include "third_party/blink/renderer/core/loader/threadable_loader.h"
-#include "third_party/blink/renderer/platform/heap/handle.h"
-#include "third_party/blink/renderer/platform/loader/fetch/raw_resource.h"
-#include "third_party/blink/renderer/platform/loader/fetch/resource_error.h"
-#include "third_party/blink/renderer/platform/network/http_header_map.h"
-#include "third_party/blink/renderer/platform/timer.h"
-#include "third_party/blink/renderer/platform/weborigin/referrer.h"
-#include "third_party/blink/renderer/platform/wtf/forward.h"
-#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
-#include "third_party/blink/renderer/platform/wtf/time.h"
-
-namespace blink {
-
-class Document;
-class KURL;
-class ResourceRequest;
-class SecurityOrigin;
-class ThreadableLoaderClient;
-class ThreadableLoadingContext;
-
-// TODO(horo): We are using this class not only in documents, but also in
-// workers. We should change the name to ThreadableLoaderImpl.
-class CORE_EXPORT DocumentThreadableLoader final : public ThreadableLoader,
-                                                   private RawResourceClient {
-  USING_GARBAGE_COLLECTED_MIXIN(DocumentThreadableLoader);
-
- public:
-  static void LoadResourceSynchronously(ThreadableLoadingContext&,
-                                        const ResourceRequest&,
-                                        ThreadableLoaderClient&,
-                                        const ThreadableLoaderOptions&,
-                                        const ResourceLoaderOptions&);
-
-  // Exposed for testing. Code outside this class should not call this function.
-  static std::unique_ptr<ResourceRequest>
-  CreateAccessControlPreflightRequestForTesting(const ResourceRequest&);
-
-  static DocumentThreadableLoader* Create(ThreadableLoadingContext&,
-                                          ThreadableLoaderClient*,
-                                          const ThreadableLoaderOptions&,
-                                          const ResourceLoaderOptions&);
-  ~DocumentThreadableLoader() override;
-
-  void Start(const ResourceRequest&) override;
-
-  void OverrideTimeout(unsigned long timeout) override;
-
-  void Cancel() override;
-  void Detach() override;
-  void SetDefersLoading(bool);
-
-  // Exposed for thread-correctness DCHECKs in WorkerThreadableLoader.
-  ExecutionContext* GetExecutionContext() const;
-
-  void Trace(blink::Visitor*) override;
-
- private:
-  class DetachedClient;
-  enum BlockingBehavior { kLoadSynchronously, kLoadAsynchronously };
-
-  static std::unique_ptr<ResourceRequest> CreateAccessControlPreflightRequest(
-      const ResourceRequest&,
-      const SecurityOrigin*);
-
-  DocumentThreadableLoader(ThreadableLoadingContext&,
-                           ThreadableLoaderClient*,
-                           BlockingBehavior,
-                           const ThreadableLoaderOptions&,
-                           const ResourceLoaderOptions&);
-
-  void Clear();
-
-  // ResourceClient
-  void NotifyFinished(Resource*) override;
-
-  String DebugName() const override { return "DocumentThreadableLoader"; }
-
-  // RawResourceClient
-  void DataSent(Resource*,
-                unsigned long long bytes_sent,
-                unsigned long long total_bytes_to_be_sent) override;
-  void ResponseReceived(Resource*,
-                        const ResourceResponse&,
-                        std::unique_ptr<WebDataConsumerHandle>) override;
-  void SetSerializedCachedMetadata(Resource*, const char*, size_t) override;
-  void DataReceived(Resource*, const char* data, size_t data_length) override;
-  bool RedirectReceived(Resource*,
-                        const ResourceRequest&,
-                        const ResourceResponse&) override;
-  void RedirectBlocked() override;
-  void DataDownloaded(Resource*, int) override;
-  void DidReceiveResourceTiming(Resource*, const ResourceTimingInfo&) override;
-  void DidDownloadToBlob(Resource*, scoped_refptr<BlobDataHandle>) override;
-
-  // Notify Inspector and log to console about resource response. Use this
-  // method if response is not going to be finished normally.
-  void ReportResponseReceived(unsigned long identifier,
-                              const ResourceResponse&);
-
-  void DidTimeout(TimerBase*);
-  // Calls the appropriate loading method according to policy and data about
-  // origin. Only for handling the initial load (including fallback after
-  // consulting ServiceWorker).
-  void DispatchInitialRequest(ResourceRequest&);
-  void MakeCrossOriginAccessRequest(const ResourceRequest&);
-
-  // Loads m_fallbackRequestForServiceWorker.
-  void LoadFallbackRequestForServiceWorker();
-  // Issues a CORS preflight.
-  void LoadPreflightRequest(const ResourceRequest&,
-                            const ResourceLoaderOptions&);
-  // Loads actual_request_.
-  void LoadActualRequest();
-  // Clears actual_request_ and reports access control check failure to
-  // m_client.
-  void HandlePreflightFailure(const KURL&, const String& error_description);
-  // Investigates the response for the preflight request. If successful,
-  // the actual request will be made later in NotifyFinished().
-  void HandlePreflightResponse(const ResourceResponse&);
-
-  void DispatchDidFailAccessControlCheck(const ResourceError&);
-  void DispatchDidFail(const ResourceError&);
-
-  void PrepareCrossOriginRequest(ResourceRequest&) const;
-
-  // This method modifies the ResourceRequest by calling
-  // SetAllowStoredCredentials() on it based on same-origin-ness and the
-  // credentials mode.
-  //
-  // This method configures the ResourceLoaderOptions so that the underlying
-  // ResourceFetcher doesn't perform some part of the CORS logic since this
-  // class performs it by itself.
-  void LoadRequest(ResourceRequest&, ResourceLoaderOptions);
-  bool IsAllowedRedirect(network::mojom::FetchRequestMode, const KURL&) const;
-
-  const SecurityOrigin* GetSecurityOrigin() const;
-
-  // Returns null if the loader is not associated with Document.
-  // TODO(kinuko): Remove dependency to document.
-  Document* GetDocument() const;
-
-  ThreadableLoaderClient* client_;
-  Member<ThreadableLoadingContext> loading_context_;
-
-  const ThreadableLoaderOptions options_;
-  // Some items may be overridden by m_forceDoNotAllowStoredCredentials and
-  // m_securityOrigin. In such a case, build a ResourceLoaderOptions with
-  // up-to-date values from them and this variable, and use it.
-  const ResourceLoaderOptions resource_loader_options_;
-
-  // True when feature OutOfBlinkCORS is enabled (https://crbug.com/736308).
-  bool out_of_blink_cors_;
-
-  // Corresponds to the CORS flag in the Fetch spec.
-  bool cors_flag_;
-  scoped_refptr<const SecurityOrigin> security_origin_;
-
-  // Set to true when the response data is given to a data consumer handle.
-  bool is_using_data_consumer_handle_;
-
-  const bool async_;
-
-  // Holds the original request context (used for sanity checks).
-  WebURLRequest::RequestContext request_context_;
-
-  // Saved so that we can use the original value for the modes in
-  // ResponseReceived() where |resource| might be a reused one (e.g. preloaded
-  // resource) which can have different modes.
-  network::mojom::FetchRequestMode fetch_request_mode_;
-  network::mojom::FetchCredentialsMode fetch_credentials_mode_;
-
-  // Holds the original request for fallback in case the Service Worker
-  // does not respond.
-  ResourceRequest fallback_request_for_service_worker_;
-
-  // Holds the original request and options for it during preflight request
-  // handling phase.
-  ResourceRequest actual_request_;
-  ResourceLoaderOptions actual_options_;
-
-  // stores request headers in case of a cross-origin redirect.
-  HTTPHeaderMap request_headers_;
-
-  TaskRunnerTimer<DocumentThreadableLoader> timeout_timer_;
-  TimeTicks request_started_;  // Time an asynchronous fetch request is started
-
-  // Max number of times that this DocumentThreadableLoader can follow
-  // cross-origin redirects. This is used to limit the number of redirects. But
-  // this value is not the max number of total redirects allowed, because
-  // same-origin redirects are not counted here.
-  int cors_redirect_limit_;
-
-  network::mojom::FetchRedirectMode redirect_mode_;
-
-  // Holds the referrer after a redirect response was received. This referrer is
-  // used to populate the HTTP Referer header when following the redirect.
-  bool override_referrer_;
-  Referrer referrer_after_redirect_;
-
-  bool detached_ = false;
-
-  RawResourceClientStateChecker checker_;
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_DOCUMENT_THREADABLE_LOADER_H_
diff --git a/third_party/blink/renderer/core/loader/document_threadable_loader_client.h b/third_party/blink/renderer/core/loader/document_threadable_loader_client.h
deleted file mode 100644
index 9554ac3..0000000
--- a/third_party/blink/renderer/core/loader/document_threadable_loader_client.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright (C) 2011 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_DOCUMENT_THREADABLE_LOADER_CLIENT_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_DOCUMENT_THREADABLE_LOADER_CLIENT_H_
-
-#include "base/macros.h"
-#include "third_party/blink/renderer/core/loader/threadable_loader_client.h"
-
-namespace blink {
-
-class KURL;
-class ResourceResponse;
-
-class DocumentThreadableLoaderClient : public ThreadableLoaderClient {
-  USING_FAST_MALLOC(DocumentThreadableLoaderClient);
-
- public:
-  bool IsDocumentThreadableLoaderClient() final { return true; }
-
-  virtual bool WillFollowRedirect(const KURL& new_url,
-                                  const ResourceResponse&) {
-    return true;
-  }
-
- protected:
-  DocumentThreadableLoaderClient() = default;
-
-  DISALLOW_COPY_AND_ASSIGN(DocumentThreadableLoaderClient);
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_DOCUMENT_THREADABLE_LOADER_CLIENT_H_
diff --git a/third_party/blink/renderer/core/loader/document_threadable_loader_test.cc b/third_party/blink/renderer/core/loader/document_threadable_loader_test.cc
deleted file mode 100644
index b0371724..0000000
--- a/third_party/blink/renderer/core/loader/document_threadable_loader_test.cc
+++ /dev/null
@@ -1,92 +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 "third_party/blink/renderer/core/loader/document_threadable_loader.h"
-
-#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/public/platform/web_cors.h"
-#include "third_party/blink/renderer/platform/exported/wrapped_resource_response.h"
-#include "third_party/blink/renderer/platform/loader/fetch/resource_response.h"
-
-namespace blink {
-
-namespace {
-
-TEST(DocumentThreadableLoaderCreatePreflightRequestTest, LexicographicalOrder) {
-  ResourceRequest request;
-  request.AddHTTPHeaderField("Orange", "Orange");
-  request.AddHTTPHeaderField("Apple", "Red");
-  request.AddHTTPHeaderField("Kiwifruit", "Green");
-  request.AddHTTPHeaderField("Content-Type", "application/octet-stream");
-  request.AddHTTPHeaderField("Strawberry", "Red");
-
-  std::unique_ptr<ResourceRequest> preflight =
-      DocumentThreadableLoader::CreateAccessControlPreflightRequestForTesting(
-          request);
-
-  EXPECT_EQ("apple,content-type,kiwifruit,orange,strawberry",
-            preflight->HttpHeaderField("Access-Control-Request-Headers"));
-}
-
-TEST(DocumentThreadableLoaderCreatePreflightRequestTest, ExcludeSimpleHeaders) {
-  ResourceRequest request;
-  request.AddHTTPHeaderField("Accept", "everything");
-  request.AddHTTPHeaderField("Accept-Language", "everything");
-  request.AddHTTPHeaderField("Content-Language", "everything");
-  request.AddHTTPHeaderField("Save-Data", "on");
-
-  std::unique_ptr<ResourceRequest> preflight =
-      DocumentThreadableLoader::CreateAccessControlPreflightRequestForTesting(
-          request);
-
-  // Do not emit empty-valued headers; an empty list of non-"CORS safelisted"
-  // request headers should cause "Access-Control-Request-Headers:" to be
-  // left out in the preflight request.
-  EXPECT_EQ(g_null_atom,
-            preflight->HttpHeaderField("Access-Control-Request-Headers"));
-}
-
-TEST(DocumentThreadableLoaderCreatePreflightRequestTest,
-     ExcludeSimpleContentTypeHeader) {
-  ResourceRequest request;
-  request.AddHTTPHeaderField("Content-Type", "text/plain");
-
-  std::unique_ptr<ResourceRequest> preflight =
-      DocumentThreadableLoader::CreateAccessControlPreflightRequestForTesting(
-          request);
-
-  // Empty list also; see comment in test above.
-  EXPECT_EQ(g_null_atom,
-            preflight->HttpHeaderField("Access-Control-Request-Headers"));
-}
-
-TEST(DocumentThreadableLoaderCreatePreflightRequestTest,
-     IncludeNonSimpleHeader) {
-  ResourceRequest request;
-  request.AddHTTPHeaderField("X-Custom-Header", "foobar");
-
-  std::unique_ptr<ResourceRequest> preflight =
-      DocumentThreadableLoader::CreateAccessControlPreflightRequestForTesting(
-          request);
-
-  EXPECT_EQ("x-custom-header",
-            preflight->HttpHeaderField("Access-Control-Request-Headers"));
-}
-
-TEST(DocumentThreadableLoaderCreatePreflightRequestTest,
-     IncludeNonSimpleContentTypeHeader) {
-  ResourceRequest request;
-  request.AddHTTPHeaderField("Content-Type", "application/octet-stream");
-
-  std::unique_ptr<ResourceRequest> preflight =
-      DocumentThreadableLoader::CreateAccessControlPreflightRequestForTesting(
-          request);
-
-  EXPECT_EQ("content-type",
-            preflight->HttpHeaderField("Access-Control-Request-Headers"));
-}
-
-}  // namespace
-
-}  // namespace blink
diff --git a/third_party/blink/renderer/core/loader/interactive_detector.h b/third_party/blink/renderer/core/loader/interactive_detector.h
index 0e62b777..1e77889 100644
--- a/third_party/blink/renderer/core/loader/interactive_detector.h
+++ b/third_party/blink/renderer/core/loader/interactive_detector.h
@@ -10,10 +10,10 @@
 #include "base/time/time.h"
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/dom/context_lifecycle_observer.h"
+#include "third_party/blink/renderer/core/loader/long_task_detector.h"
 #include "third_party/blink/renderer/core/page/page_visibility_state.h"
 #include "third_party/blink/renderer/core/paint/first_meaningful_paint_detector.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
-#include "third_party/blink/renderer/platform/long_task_detector.h"
 #include "third_party/blink/renderer/platform/pod_interval.h"
 #include "third_party/blink/renderer/platform/supplementable.h"
 #include "third_party/blink/renderer/platform/timer.h"
diff --git a/third_party/blink/renderer/platform/long_task_detector.cc b/third_party/blink/renderer/core/loader/long_task_detector.cc
similarity index 95%
rename from third_party/blink/renderer/platform/long_task_detector.cc
rename to third_party/blink/renderer/core/loader/long_task_detector.cc
index c4b1dc8..fef8b5a 100644
--- a/third_party/blink/renderer/platform/long_task_detector.cc
+++ b/third_party/blink/renderer/core/loader/long_task_detector.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "third_party/blink/renderer/platform/long_task_detector.h"
+#include "third_party/blink/renderer/core/loader/long_task_detector.h"
 
 #include "third_party/blink/public/platform/platform.h"
 #include "third_party/blink/public/platform/web_thread.h"
diff --git a/third_party/blink/renderer/platform/long_task_detector.h b/third_party/blink/renderer/core/loader/long_task_detector.h
similarity index 76%
rename from third_party/blink/renderer/platform/long_task_detector.h
rename to third_party/blink/renderer/core/loader/long_task_detector.h
index 8c0a19ac..41076c7a 100644
--- a/third_party/blink/renderer/platform/long_task_detector.h
+++ b/third_party/blink/renderer/core/loader/long_task_detector.h
@@ -2,19 +2,19 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_LONG_TASK_DETECTOR_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_LONG_TASK_DETECTOR_H_
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_LONG_TASK_DETECTOR_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_LONG_TASK_DETECTOR_H_
 
+#include "base/macros.h"
 #include "base/task/sequence_manager/task_time_observer.h"
 #include "third_party/blink/public/platform/web_thread.h"
+#include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
-#include "third_party/blink/renderer/platform/platform_export.h"
-#include "third_party/blink/renderer/platform/wtf/noncopyable.h"
 #include "third_party/blink/renderer/platform/wtf/time.h"
 
 namespace blink {
 
-class PLATFORM_EXPORT LongTaskObserver : public GarbageCollectedMixin {
+class CORE_EXPORT LongTaskObserver : public GarbageCollectedMixin {
  public:
   virtual ~LongTaskObserver() = default;
 
@@ -26,11 +26,9 @@
 // TaskTimeObserver on the main thread and observes every task. When the number
 // of LongTaskObservers drop to zero it automatically removes itself as a
 // TaskTimeObserver.
-class PLATFORM_EXPORT LongTaskDetector final
+class CORE_EXPORT LongTaskDetector final
     : public GarbageCollectedFinalized<LongTaskDetector>,
       public base::sequence_manager::TaskTimeObserver {
-  WTF_MAKE_NONCOPYABLE(LongTaskDetector);
-
  public:
   static LongTaskDetector& Instance();
 
@@ -51,8 +49,10 @@
                       base::TimeTicks end_time) override;
 
   HeapHashSet<Member<LongTaskObserver>> observers_;
+
+  DISALLOW_COPY_AND_ASSIGN(LongTaskDetector);
 };
 
 }  // namespace blink
 
-#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_LONG_TASK_DETECTOR_H_
+#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_LONG_TASK_DETECTOR_H_
diff --git a/third_party/blink/renderer/platform/long_task_detector_test.cc b/third_party/blink/renderer/core/loader/long_task_detector_test.cc
similarity index 98%
rename from third_party/blink/renderer/platform/long_task_detector_test.cc
rename to third_party/blink/renderer/core/loader/long_task_detector_test.cc
index bae1d36..4e95f720 100644
--- a/third_party/blink/renderer/platform/long_task_detector_test.cc
+++ b/third_party/blink/renderer/core/loader/long_task_detector_test.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "third_party/blink/renderer/platform/long_task_detector.h"
+#include "third_party/blink/renderer/core/loader/long_task_detector.h"
 
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/renderer/platform/cross_thread_functional.h"
diff --git a/third_party/blink/renderer/core/loader/threadable_loader.cc b/third_party/blink/renderer/core/loader/threadable_loader.cc
index 44b688f..9d94425 100644
--- a/third_party/blink/renderer/core/loader/threadable_loader.cc
+++ b/third_party/blink/renderer/core/loader/threadable_loader.cc
@@ -1,5 +1,6 @@
 /*
- * Copyright (C) 2009 Google Inc. All rights reserved.
+ * Copyright (C) 2011, 2012 Google Inc. All rights reserved.
+ * Copyright (C) 2013, Intel Corporation
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
@@ -30,35 +31,1213 @@
 
 #include "third_party/blink/renderer/core/loader/threadable_loader.h"
 
-#include "third_party/blink/renderer/core/execution_context/execution_context.h"
-#include "third_party/blink/renderer/core/loader/document_threadable_loader.h"
+#include <memory>
+#include "base/memory/weak_ptr.h"
+#include "base/single_thread_task_runner.h"
+#include "services/network/public/cpp/cors/cors_error_status.h"
+#include "services/network/public/mojom/cors.mojom-blink.h"
+#include "services/network/public/mojom/fetch_api.mojom-blink.h"
+#include "third_party/blink/public/common/service_worker/service_worker_utils.h"
+#include "third_party/blink/public/platform/platform.h"
+#include "third_party/blink/public/platform/task_type.h"
+#include "third_party/blink/public/platform/web_cors.h"
+#include "third_party/blink/public/platform/web_security_origin.h"
+#include "third_party/blink/public/platform/web_url_request.h"
+#include "third_party/blink/renderer/core/dom/document.h"
+#include "third_party/blink/renderer/core/frame/frame_console.h"
+#include "third_party/blink/renderer/core/frame/local_frame.h"
+#include "third_party/blink/renderer/core/frame/local_frame_client.h"
+#include "third_party/blink/renderer/core/frame/web_feature.h"
+#include "third_party/blink/renderer/core/inspector/console_message.h"
+#include "third_party/blink/renderer/core/inspector/inspector_network_agent.h"
+#include "third_party/blink/renderer/core/inspector/inspector_trace_events.h"
+#include "third_party/blink/renderer/core/loader/base_fetch_context.h"
+#include "third_party/blink/renderer/core/loader/frame_loader.h"
+#include "third_party/blink/renderer/core/loader/threadable_loader_client.h"
 #include "third_party/blink/renderer/core/loader/threadable_loading_context.h"
-#include "third_party/blink/renderer/core/workers/worker_global_scope.h"
+#include "third_party/blink/renderer/core/probe/core_probes.h"
+#include "third_party/blink/renderer/platform/exported/wrapped_resource_request.h"
+#include "third_party/blink/renderer/platform/heap/self_keep_alive.h"
+#include "third_party/blink/renderer/platform/loader/cors/cors.h"
+#include "third_party/blink/renderer/platform/loader/cors/cors_error_string.h"
+#include "third_party/blink/renderer/platform/loader/fetch/fetch_parameters.h"
+#include "third_party/blink/renderer/platform/loader/fetch/resource.h"
+#include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h"
+#include "third_party/blink/renderer/platform/loader/fetch/resource_loader.h"
+#include "third_party/blink/renderer/platform/loader/fetch/resource_loader_options.h"
+#include "third_party/blink/renderer/platform/loader/fetch/resource_request.h"
+#include "third_party/blink/renderer/platform/shared_buffer.h"
+#include "third_party/blink/renderer/platform/weborigin/scheme_registry.h"
+#include "third_party/blink/renderer/platform/weborigin/security_origin.h"
+#include "third_party/blink/renderer/platform/weborigin/security_policy.h"
+#include "third_party/blink/renderer/platform/wtf/assertions.h"
 
 namespace blink {
 
-ThreadableLoader* ThreadableLoader::Create(
-    ExecutionContext& context,
-    ThreadableLoaderClient* client,
-    const ThreadableLoaderOptions& options,
-    const ResourceLoaderOptions& resource_loader_options) {
-  DCHECK(client);
-  if (context.IsWorkerGlobalScope())
-    ToWorkerGlobalScope(&context)->EnsureFetcher();
-  return DocumentThreadableLoader::Create(
-      *ThreadableLoadingContext::Create(context), client, options,
-      resource_loader_options);
+namespace {
+
+// Fetch API Spec: https://fetch.spec.whatwg.org/#cors-preflight-fetch-0
+AtomicString CreateAccessControlRequestHeadersHeader(
+    const HTTPHeaderMap& headers) {
+  Vector<String> filtered_headers;
+  for (const auto& header : headers) {
+    // Exclude CORS-safelisted headers.
+    if (CORS::IsCORSSafelistedHeader(header.key, header.value))
+      continue;
+    // Calling a deprecated function, but eventually this function,
+    // |CreateAccessControlRequestHeadersHeader| will be removed.
+    // When the request is from a Worker, referrer header was added by
+    // WorkerThreadableLoader. But it should not be added to
+    // Access-Control-Request-Headers header.
+    if (DeprecatedEqualIgnoringCase(header.key, "referer"))
+      continue;
+    filtered_headers.push_back(header.key.DeprecatedLower());
+  }
+  if (!filtered_headers.size())
+    return g_null_atom;
+
+  // Sort header names lexicographically.
+  std::sort(filtered_headers.begin(), filtered_headers.end(),
+            WTF::CodePointCompareLessThan);
+  StringBuilder header_buffer;
+  for (const String& header : filtered_headers) {
+    if (!header_buffer.IsEmpty())
+      header_buffer.Append(",");
+    header_buffer.Append(header);
+  }
+
+  return header_buffer.ToAtomicString();
 }
 
+class EmptyDataHandle final : public WebDataConsumerHandle {
+ private:
+  class EmptyDataReader final : public WebDataConsumerHandle::Reader {
+   public:
+    explicit EmptyDataReader(
+        WebDataConsumerHandle::Client* client,
+        scoped_refptr<base::SingleThreadTaskRunner> task_runner)
+        : factory_(this) {
+      task_runner->PostTask(
+          FROM_HERE, WTF::Bind(&EmptyDataReader::Notify, factory_.GetWeakPtr(),
+                               WTF::Unretained(client)));
+    }
+
+   private:
+    Result BeginRead(const void** buffer,
+                     WebDataConsumerHandle::Flags,
+                     size_t* available) override {
+      *available = 0;
+      *buffer = nullptr;
+      return kDone;
+    }
+    Result EndRead(size_t) override {
+      return WebDataConsumerHandle::kUnexpectedError;
+    }
+    void Notify(WebDataConsumerHandle::Client* client) {
+      client->DidGetReadable();
+    }
+    base::WeakPtrFactory<EmptyDataReader> factory_;
+  };
+
+  std::unique_ptr<Reader> ObtainReader(
+      Client* client,
+      scoped_refptr<base::SingleThreadTaskRunner> task_runner) override {
+    return std::make_unique<EmptyDataReader>(client, std::move(task_runner));
+  }
+  const char* DebugName() const override { return "EmptyDataHandle"; }
+};
+
+}  // namespace
+
+// DetachedClient is a ThreadableLoaderClient for a "detached"
+// ThreadableLoader. It's for fetch requests with keepalive set, so
+// it keeps itself alive during loading.
+class ThreadableLoader::DetachedClient final
+    : public GarbageCollectedFinalized<DetachedClient>,
+      public ThreadableLoaderClient {
+ public:
+  explicit DetachedClient(ThreadableLoader* loader)
+      : self_keep_alive_(this), loader_(loader) {}
+  ~DetachedClient() override {}
+
+  void DidFinishLoading(unsigned long identifier) override {
+    self_keep_alive_.Clear();
+  }
+  void DidFail(const ResourceError&) override { self_keep_alive_.Clear(); }
+  void DidFailRedirectCheck() override { self_keep_alive_.Clear(); }
+  void Trace(Visitor* visitor) { visitor->Trace(loader_); }
+
+ private:
+  SelfKeepAlive<DetachedClient> self_keep_alive_;
+  // Keep it alive.
+  const Member<ThreadableLoader> loader_;
+};
+
+// Max number of CORS redirects handled in ThreadableLoader. Same number
+// as net/url_request/url_request.cc, and same number as
+// https://fetch.spec.whatwg.org/#concept-http-fetch, Step 4.
+// FIXME: currently the number of redirects is counted and limited here and in
+// net/url_request/url_request.cc separately.
+static const int kMaxCORSRedirects = 20;
+
+// static
 void ThreadableLoader::LoadResourceSynchronously(
     ExecutionContext& context,
     const ResourceRequest& request,
     ThreadableLoaderClient& client,
     const ThreadableLoaderOptions& options,
     const ResourceLoaderOptions& resource_loader_options) {
-  DocumentThreadableLoader::LoadResourceSynchronously(
-      *ThreadableLoadingContext::Create(context), request, client, options,
-      resource_loader_options);
+  (new ThreadableLoader(context, &client, kLoadSynchronously, options,
+                        resource_loader_options))
+      ->Start(request);
+}
+
+// static
+std::unique_ptr<ResourceRequest>
+ThreadableLoader::CreateAccessControlPreflightRequest(
+    const ResourceRequest& request,
+    const SecurityOrigin* origin) {
+  const KURL& request_url = request.Url();
+
+  DCHECK(request_url.User().IsEmpty());
+  DCHECK(request_url.Pass().IsEmpty());
+
+  std::unique_ptr<ResourceRequest> preflight_request =
+      std::make_unique<ResourceRequest>(request_url);
+  preflight_request->SetHTTPMethod(HTTPNames::OPTIONS);
+  preflight_request->SetHTTPHeaderField(
+      HTTPNames::Access_Control_Request_Method, request.HttpMethod());
+  preflight_request->SetPriority(request.Priority());
+  preflight_request->SetRequestContext(request.GetRequestContext());
+  preflight_request->SetFetchCredentialsMode(
+      network::mojom::FetchCredentialsMode::kOmit);
+  preflight_request->SetSkipServiceWorker(true);
+  // TODO(domfarolino): Use ReferrerString() once https://crbug.com/850813 is
+  // closed and we stop storing the referrer string as a `Referer` header.
+  preflight_request->SetReferrerString(request.HttpReferrer());
+  preflight_request->SetReferrerPolicy(request.GetReferrerPolicy());
+
+  if (request.IsExternalRequest()) {
+    preflight_request->SetHTTPHeaderField(
+        HTTPNames::Access_Control_Request_External, "true");
+  }
+
+  const AtomicString request_headers =
+      CreateAccessControlRequestHeadersHeader(request.HttpHeaderFields());
+  if (request_headers != g_null_atom) {
+    preflight_request->SetHTTPHeaderField(
+        HTTPNames::Access_Control_Request_Headers, request_headers);
+  }
+
+  if (origin)
+    preflight_request->SetHTTPOrigin(origin);
+
+  return preflight_request;
+}
+
+// static
+std::unique_ptr<ResourceRequest>
+ThreadableLoader::CreateAccessControlPreflightRequestForTesting(
+    const ResourceRequest& request) {
+  return CreateAccessControlPreflightRequest(request, nullptr);
+}
+
+// static
+ThreadableLoader* ThreadableLoader::Create(
+    ExecutionContext& context,
+    ThreadableLoaderClient* client,
+    const ThreadableLoaderOptions& options,
+    const ResourceLoaderOptions& resource_loader_options) {
+  return new ThreadableLoader(context, client, kLoadAsynchronously, options,
+                              resource_loader_options);
+}
+
+ThreadableLoader::ThreadableLoader(
+    ExecutionContext& context,
+    ThreadableLoaderClient* client,
+    BlockingBehavior blocking_behavior,
+    const ThreadableLoaderOptions& options,
+    const ResourceLoaderOptions& resource_loader_options)
+    : client_(client),
+      loading_context_(ThreadableLoadingContext::Create(context)),
+      options_(options),
+      resource_loader_options_(resource_loader_options),
+      out_of_blink_cors_(RuntimeEnabledFeatures::OutOfBlinkCORSEnabled()),
+      cors_flag_(false),
+      security_origin_(resource_loader_options_.security_origin),
+      is_using_data_consumer_handle_(false),
+      async_(blocking_behavior == kLoadAsynchronously),
+      request_context_(WebURLRequest::kRequestContextUnspecified),
+      fetch_request_mode_(network::mojom::FetchRequestMode::kSameOrigin),
+      fetch_credentials_mode_(network::mojom::FetchCredentialsMode::kOmit),
+      timeout_timer_(
+          GetExecutionContext()->GetTaskRunner(TaskType::kNetworking),
+          this,
+          &ThreadableLoader::DidTimeout),
+      cors_redirect_limit_(0),
+      redirect_mode_(network::mojom::FetchRedirectMode::kFollow),
+      override_referrer_(false) {
+  DCHECK(client);
+}
+
+void ThreadableLoader::Start(const ResourceRequest& request) {
+  // Setting an outgoing referer is only supported in the async code path.
+  DCHECK(async_ || request.HttpReferrer().IsEmpty());
+
+  bool cors_enabled =
+      CORS::IsCORSEnabledRequestMode(request.GetFetchRequestMode());
+
+  // kPreventPreflight can be used only when the CORS is enabled.
+  DCHECK(request.CORSPreflightPolicy() ==
+             network::mojom::CORSPreflightPolicy::kConsiderPreflight ||
+         cors_enabled);
+
+  if (cors_enabled)
+    cors_redirect_limit_ = kMaxCORSRedirects;
+
+  request_context_ = request.GetRequestContext();
+  fetch_request_mode_ = request.GetFetchRequestMode();
+  fetch_credentials_mode_ = request.GetFetchCredentialsMode();
+  redirect_mode_ = request.GetFetchRedirectMode();
+
+  if (request.GetFetchRequestMode() ==
+      network::mojom::FetchRequestMode::kNoCORS) {
+    SECURITY_CHECK(WebCORS::IsNoCORSAllowedContext(request_context_));
+  } else {
+    cors_flag_ = !GetSecurityOrigin()->CanRequest(request.Url());
+  }
+
+  // The CORS flag variable is not yet used at the step in the spec that
+  // corresponds to this line, but divert |cors_flag_| here for convenience.
+  if (cors_flag_ && request.GetFetchRequestMode() ==
+                        network::mojom::FetchRequestMode::kSameOrigin) {
+    ThreadableLoaderClient* client = client_;
+    Clear();
+    ResourceError error = ResourceError::CancelledDueToAccessCheckError(
+        request.Url(), ResourceRequestBlockedReason::kOther,
+        CORS::GetErrorString(
+            CORS::ErrorParameter::CreateForDisallowedByMode(request.Url())));
+    GetExecutionContext()->AddConsoleMessage(ConsoleMessage::Create(
+        kJSMessageSource, kErrorMessageLevel, error.LocalizedDescription()));
+    client->DidFail(error);
+    return;
+  }
+
+  request_started_ = CurrentTimeTicks();
+
+  // Save any headers on the request here. If this request redirects
+  // cross-origin, we cancel the old request create a new one, and copy these
+  // headers.
+  request_headers_ = request.HttpHeaderFields();
+
+  ResourceRequest new_request(request);
+
+  // Set the service worker mode to none if "bypass for network" in DevTools is
+  // enabled.
+  bool should_bypass_service_worker = false;
+  probe::shouldBypassServiceWorker(GetExecutionContext(),
+                                   &should_bypass_service_worker);
+  if (should_bypass_service_worker)
+    new_request.SetSkipServiceWorker(true);
+
+  // In S13nServiceWorker, if the controller service worker has no fetch event
+  // handler, it's skipped entirely, so we should treat that case the same as
+  // having no controller. In non-S13nServiceWorker, we can't do that since we
+  // don't know which service worker will handle the request since it's
+  // determined on the browser process and skipWaiting() can happen in the
+  // meantime.
+  //
+  // TODO(crbug.com/715640): When non-S13nServiceWorker is removed,
+  // is_controlled_by_service_worker is the same as
+  // ControllerServiceWorkerMode::kControlled, so this code can be simplified.
+  bool is_controlled_by_service_worker = false;
+  switch (
+      loading_context_->GetResourceFetcher()->IsControlledByServiceWorker()) {
+    case blink::mojom::ControllerServiceWorkerMode::kControlled:
+      is_controlled_by_service_worker = true;
+      break;
+    case blink::mojom::ControllerServiceWorkerMode::kNoFetchEventHandler:
+      if (ServiceWorkerUtils::IsServicificationEnabled())
+        is_controlled_by_service_worker = false;
+      else
+        is_controlled_by_service_worker = true;
+      break;
+    case blink::mojom::ControllerServiceWorkerMode::kNoController:
+      is_controlled_by_service_worker = false;
+      break;
+  }
+
+  // Process the CORS protocol inside the ThreadableLoader for the
+  // following cases:
+  //
+  // - When the request is sync or the protocol is unsupported since we can
+  //   assume that any service worker (SW) is skipped for such requests by
+  //   content/ code.
+  // - When |skip_service_worker| is true, any SW will be skipped.
+  // - If we're not yet controlled by a SW, then we're sure that this
+  //   request won't be intercepted by a SW. In case we end up with
+  //   sending a CORS preflight request, the actual request to be sent later
+  //   may be intercepted. This is taken care of in LoadPreflightRequest() by
+  //   setting |skip_service_worker| to true.
+  //
+  // From the above analysis, you can see that the request can never be
+  // intercepted by a SW inside this if-block. It's because:
+  // - |skip_service_worker| needs to be false, and
+  // - we're controlled by a SW at this point
+  // to allow a SW to intercept the request. Even when the request gets issued
+  // asynchronously after performing the CORS preflight, it doesn't get
+  // intercepted since LoadPreflightRequest() sets the flag to kNone in advance.
+  if (!async_ || new_request.GetSkipServiceWorker() ||
+      !SchemeRegistry::ShouldTreatURLSchemeAsAllowingServiceWorkers(
+          new_request.Url().Protocol()) ||
+      !is_controlled_by_service_worker) {
+    DispatchInitialRequest(new_request);
+    return;
+  }
+
+  if (CORS::IsCORSEnabledRequestMode(request.GetFetchRequestMode())) {
+    // Save the request to fallback_request_for_service_worker to use when the
+    // service worker doesn't handle (call respondWith()) a CORS enabled
+    // request.
+    fallback_request_for_service_worker_ = ResourceRequest(request);
+    // Skip the service worker for the fallback request.
+    fallback_request_for_service_worker_.SetSkipServiceWorker(true);
+  }
+
+  LoadRequest(new_request, resource_loader_options_);
+}
+
+void ThreadableLoader::DispatchInitialRequest(ResourceRequest& request) {
+  if (out_of_blink_cors_ || (!request.IsExternalRequest() && !cors_flag_)) {
+    LoadRequest(request, resource_loader_options_);
+    return;
+  }
+
+  DCHECK(CORS::IsCORSEnabledRequestMode(request.GetFetchRequestMode()) ||
+         request.IsExternalRequest());
+
+  MakeCrossOriginAccessRequest(request);
+}
+
+void ThreadableLoader::PrepareCrossOriginRequest(
+    ResourceRequest& request) const {
+  if (GetSecurityOrigin())
+    request.SetHTTPOrigin(GetSecurityOrigin());
+
+  // TODO(domfarolino): Stop setting the HTTPReferrer header, and instead use
+  // ResourceRequest::referrer_. See https://crbug.com/850813.
+  if (override_referrer_)
+    request.SetHTTPReferrer(referrer_after_redirect_);
+}
+
+void ThreadableLoader::LoadPreflightRequest(
+    const ResourceRequest& actual_request,
+    const ResourceLoaderOptions& actual_options) {
+  std::unique_ptr<ResourceRequest> preflight_request =
+      CreateAccessControlPreflightRequest(actual_request, GetSecurityOrigin());
+
+  actual_request_ = actual_request;
+  actual_options_ = actual_options;
+
+  // Explicitly set |skip_service_worker| to true here. Although the page is
+  // not controlled by a SW at this point, a new SW may be controlling the
+  // page when this actual request gets sent later. We should not send the
+  // actual request to the SW. See https://crbug.com/604583.
+  actual_request_.SetSkipServiceWorker(true);
+
+  // Create a ResourceLoaderOptions for preflight.
+  ResourceLoaderOptions preflight_options = actual_options;
+
+  LoadRequest(*preflight_request, preflight_options);
+}
+
+void ThreadableLoader::MakeCrossOriginAccessRequest(
+    const ResourceRequest& request) {
+  DCHECK(CORS::IsCORSEnabledRequestMode(request.GetFetchRequestMode()) ||
+         request.IsExternalRequest());
+  DCHECK(client_);
+  DCHECK(!GetResource());
+
+  // Cross-origin requests are only allowed certain registered schemes. We would
+  // catch this when checking response headers later, but there is no reason to
+  // send a request, preflighted or not, that's guaranteed to be denied.
+  if (!SchemeRegistry::ShouldTreatURLSchemeAsCORSEnabled(
+          request.Url().Protocol())) {
+    DispatchDidFailAccessControlCheck(
+        ResourceError::CancelledDueToAccessCheckError(
+            request.Url(), ResourceRequestBlockedReason::kOther,
+            String::Format(
+                "Cross origin requests are only supported for protocol "
+                "schemes: %s.",
+                SchemeRegistry::ListOfCORSEnabledURLSchemes().Ascii().data())));
+    return;
+  }
+
+  // Non-secure origins may not make "external requests":
+  // https://wicg.github.io/cors-rfc1918/#integration-fetch
+  String error_message;
+  if (!GetExecutionContext()->IsSecureContext(error_message) &&
+      request.IsExternalRequest()) {
+    DispatchDidFailAccessControlCheck(
+        ResourceError::CancelledDueToAccessCheckError(
+            request.Url(), ResourceRequestBlockedReason::kOrigin,
+            "Requests to internal network resources are not allowed "
+            "from non-secure contexts (see https://goo.gl/Y0ZkNV). "
+            "This is an experimental restriction which is part of "
+            "'https://mikewest.github.io/cors-rfc1918/'."));
+    return;
+  }
+
+  ResourceRequest cross_origin_request(request);
+  ResourceLoaderOptions cross_origin_options(resource_loader_options_);
+
+  cross_origin_request.RemoveUserAndPassFromURL();
+
+  // Enforce the CORS preflight for checking the Access-Control-Allow-External
+  // header. The CORS preflight cache doesn't help for this purpose.
+  if (request.IsExternalRequest()) {
+    LoadPreflightRequest(cross_origin_request, cross_origin_options);
+    return;
+  }
+
+  if (request.GetFetchRequestMode() !=
+      network::mojom::FetchRequestMode::kCORSWithForcedPreflight) {
+    if (request.CORSPreflightPolicy() ==
+        network::mojom::CORSPreflightPolicy::kPreventPreflight) {
+      PrepareCrossOriginRequest(cross_origin_request);
+      LoadRequest(cross_origin_request, cross_origin_options);
+      return;
+    }
+
+    DCHECK_EQ(request.CORSPreflightPolicy(),
+              network::mojom::CORSPreflightPolicy::kConsiderPreflight);
+
+    // We use ContainsOnlyCORSSafelistedOrForbiddenHeaders() here since
+    // |request| may have been modified in the process of loading (not from
+    // the user's input). For example, referrer. We need to accept them. For
+    // security, we must reject forbidden headers/methods at the point we
+    // accept user's input. Not here.
+    if (CORS::IsCORSSafelistedMethod(request.HttpMethod()) &&
+        CORS::ContainsOnlyCORSSafelistedOrForbiddenHeaders(
+            request.HttpHeaderFields())) {
+      PrepareCrossOriginRequest(cross_origin_request);
+      LoadRequest(cross_origin_request, cross_origin_options);
+      return;
+    }
+  }
+
+  // Now, we need to check that the request passes the CORS preflight either by
+  // issuing a CORS preflight or based on an entry in the CORS preflight cache.
+
+  bool should_ignore_preflight_cache = false;
+  // Prevent use of the CORS preflight cache when instructed by the DevTools
+  // not to use caches.
+  probe::shouldForceCORSPreflight(GetExecutionContext(),
+                                  &should_ignore_preflight_cache);
+  if (should_ignore_preflight_cache ||
+      !CORS::CheckIfRequestCanSkipPreflight(
+          GetSecurityOrigin()->ToString(), cross_origin_request.Url(),
+          cross_origin_request.GetFetchCredentialsMode(),
+          cross_origin_request.HttpMethod(),
+          cross_origin_request.HttpHeaderFields())) {
+    LoadPreflightRequest(cross_origin_request, cross_origin_options);
+    return;
+  }
+
+  // We don't want any requests that could involve a CORS preflight to get
+  // intercepted by a foreign SW, even if we have the result of the preflight
+  // cached already. See https://crbug.com/674370.
+  cross_origin_request.SetSkipServiceWorker(true);
+
+  PrepareCrossOriginRequest(cross_origin_request);
+  LoadRequest(cross_origin_request, cross_origin_options);
+}
+
+ThreadableLoader::~ThreadableLoader() {
+  // |client_| is a raw pointer and having a non-null |client_| here probably
+  // means UaF.
+  // In the detached case, |this| is held by DetachedClient defined above, but
+  // SelfKeepAlive in DetachedClient is forcibly cancelled on worker thread
+  // termination. We can safely ignore this case.
+  CHECK(!client_ || detached_);
+  DCHECK(!GetResource());
+}
+
+void ThreadableLoader::OverrideTimeout(unsigned long timeout_milliseconds) {
+  DCHECK(async_);
+
+  // |m_requestStartedSeconds| == 0.0 indicates loading is already finished and
+  // |m_timeoutTimer| is already stopped, and thus we do nothing for such cases.
+  // See https://crbug.com/551663 for details.
+  if (request_started_ <= TimeTicks())
+    return;
+
+  timeout_timer_.Stop();
+  // At the time of this method's implementation, it is only ever called by
+  // XMLHttpRequest, when the timeout attribute is set after sending the
+  // request.
+  //
+  // The XHR request says to resolve the time relative to when the request
+  // was initially sent, however other uses of this method may need to
+  // behave differently, in which case this should be re-arranged somehow.
+  if (timeout_milliseconds) {
+    TimeDelta elapsed_time = CurrentTimeTicks() - request_started_;
+    TimeDelta next_fire = TimeDelta::FromMilliseconds(timeout_milliseconds);
+    TimeDelta resolved_time = std::max(next_fire - elapsed_time, TimeDelta());
+    timeout_timer_.StartOneShot(resolved_time, FROM_HERE);
+  }
+}
+
+void ThreadableLoader::Cancel() {
+  // Cancel can re-enter, and therefore |resource()| might be null here as a
+  // result.
+  if (!client_ || !GetResource()) {
+    Clear();
+    return;
+  }
+
+  DispatchDidFail(ResourceError::CancelledError(GetResource()->Url()));
+}
+
+void ThreadableLoader::Detach() {
+  Resource* resource = GetResource();
+  if (!resource)
+    return;
+  detached_ = true;
+  client_ = new DetachedClient(this);
+}
+
+void ThreadableLoader::SetDefersLoading(bool value) {
+  if (GetResource() && GetResource()->Loader())
+    GetResource()->Loader()->SetDefersLoading(value);
+}
+
+void ThreadableLoader::Clear() {
+  client_ = nullptr;
+  timeout_timer_.Stop();
+  request_started_ = TimeTicks();
+  if (GetResource())
+    checker_.WillRemoveClient();
+  ClearResource();
+}
+
+// In this method, we can clear |request| to tell content::WebURLLoaderImpl of
+// Chromium not to follow the redirect. This works only when this method is
+// called by RawResource::willSendRequest(). If called by
+// RawResource::didAddClient(), clearing |request| won't be propagated to
+// content::WebURLLoaderImpl. So, this loader must also get detached from the
+// resource by calling clearResource().
+// TODO(toyoshim): Implement OOR-CORS mode specific redirect code.
+bool ThreadableLoader::RedirectReceived(
+    Resource* resource,
+    const ResourceRequest& new_request,
+    const ResourceResponse& redirect_response) {
+  DCHECK(client_);
+  DCHECK_EQ(resource, GetResource());
+
+  checker_.RedirectReceived();
+
+  const KURL& new_url = new_request.Url();
+  const KURL& original_url = redirect_response.Url();
+
+  if (!actual_request_.IsNull()) {
+    DCHECK(!out_of_blink_cors_);
+    ReportResponseReceived(resource->Identifier(), redirect_response);
+
+    HandlePreflightFailure(
+        original_url, CORS::GetErrorString(
+                          CORS::ErrorParameter::CreateForDisallowedRedirect()));
+
+    return false;
+  }
+
+  if (redirect_mode_ == network::mojom::FetchRedirectMode::kManual) {
+    // We use |redirect_mode_| to check the original redirect mode.
+    // |new_request| is a new request for redirect. So we don't set the
+    // redirect mode of it in WebURLLoaderImpl::Context::OnReceivedRedirect().
+    DCHECK(new_request.UseStreamOnResponse());
+    // There is no need to read the body of redirect response because there is
+    // no way to read the body of opaque-redirect filtered response's internal
+    // response.
+    // TODO(horo): If we support any API which expose the internal body, we will
+    // have to read the body. And also HTTPCache changes will be needed because
+    // it doesn't store the body of redirect responses.
+    ResponseReceived(resource, redirect_response,
+                     std::make_unique<EmptyDataHandle>());
+
+    if (client_) {
+      DCHECK(actual_request_.IsNull());
+      NotifyFinished(resource);
+    }
+
+    return false;
+  }
+
+  if (redirect_mode_ == network::mojom::FetchRedirectMode::kError) {
+    ThreadableLoaderClient* client = client_;
+    Clear();
+    client->DidFailRedirectCheck();
+
+    return false;
+  }
+
+  if (out_of_blink_cors_) {
+    client_->DidReceiveRedirectTo(new_url);
+    return client_->WillFollowRedirect(new_url, redirect_response);
+  }
+
+  // Allow same origin requests to continue after allowing clients to audit the
+  // redirect.
+  if (IsAllowedRedirect(new_request.GetFetchRequestMode(), new_url)) {
+    client_->DidReceiveRedirectTo(new_url);
+    return client_->WillFollowRedirect(new_url, redirect_response);
+  }
+
+  if (cors_redirect_limit_ <= 0) {
+    ThreadableLoaderClient* client = client_;
+    Clear();
+    client->DidFailRedirectCheck();
+    return false;
+  }
+
+  --cors_redirect_limit_;
+
+  probe::didReceiveCORSRedirectResponse(
+      GetExecutionContext(), resource->Identifier(),
+      GetDocument() && GetDocument()->GetFrame()
+          ? GetDocument()->GetFrame()->Loader().GetDocumentLoader()
+          : nullptr,
+      redirect_response, resource);
+
+  base::Optional<network::mojom::CORSError> redirect_error =
+      CORS::CheckRedirectLocation(new_url);
+  if (redirect_error) {
+    DispatchDidFailAccessControlCheck(
+        ResourceError::CancelledDueToAccessCheckError(
+            original_url, ResourceRequestBlockedReason::kOther,
+            CORS::GetErrorString(CORS::ErrorParameter::CreateForRedirectCheck(
+                *redirect_error, original_url, new_url))));
+    return false;
+  }
+
+  if (cors_flag_) {
+    // The redirect response must pass the access control check if the CORS
+    // flag is set.
+    base::Optional<network::CORSErrorStatus> access_error = CORS::CheckAccess(
+        original_url, redirect_response.HttpStatusCode(),
+        redirect_response.HttpHeaderFields(),
+        new_request.GetFetchCredentialsMode(), *GetSecurityOrigin());
+    if (access_error) {
+      DispatchDidFailAccessControlCheck(
+          ResourceError::CancelledDueToAccessCheckError(
+              original_url, ResourceRequestBlockedReason::kOther,
+              CORS::GetErrorString(CORS::ErrorParameter::CreateForAccessCheck(
+                  *access_error, original_url,
+                  redirect_response.HttpStatusCode(), *GetSecurityOrigin(),
+                  request_context_, new_url))));
+      return false;
+    }
+  }
+
+  client_->DidReceiveRedirectTo(new_url);
+
+  // FIXME: consider combining this with CORS redirect handling performed by
+  // CrossOriginAccessControl::handleRedirect().
+  if (GetResource())
+    checker_.WillRemoveClient();
+  ClearResource();
+
+  // If
+  // - CORS flag is set, and
+  // - the origin of the redirect target URL is not same origin with the origin
+  //   of the current request's URL
+  // set the source origin to a unique opaque origin.
+  //
+  // See https://fetch.spec.whatwg.org/#http-redirect-fetch.
+  if (cors_flag_) {
+    scoped_refptr<const SecurityOrigin> original_origin =
+        SecurityOrigin::Create(original_url);
+    scoped_refptr<const SecurityOrigin> new_origin =
+        SecurityOrigin::Create(new_url);
+    if (!original_origin->IsSameSchemeHostPort(new_origin.get()))
+      security_origin_ = SecurityOrigin::CreateUniqueOpaque();
+  }
+
+  // Set |cors_flag_| so that further logic (corresponds to the main fetch in
+  // the spec) will be performed with CORS flag set.
+  // See https://fetch.spec.whatwg.org/#http-redirect-fetch.
+  cors_flag_ = true;
+
+  // Save the referrer to use when following the redirect.
+  override_referrer_ = true;
+  // TODO(domfarolino): Use ReferrerString() once https://crbug.com/850813 is
+  // closed and we stop storing the referrer string as a `Referer` header.
+  referrer_after_redirect_ =
+      Referrer(new_request.HttpReferrer(), new_request.GetReferrerPolicy());
+
+  ResourceRequest cross_origin_request(new_request);
+
+  // Remove any headers that may have been added by the network layer that cause
+  // access control to fail.
+  cross_origin_request.ClearHTTPReferrer();
+  cross_origin_request.ClearHTTPOrigin();
+  cross_origin_request.ClearHTTPUserAgent();
+  // Add any request headers which we previously saved from the
+  // original request.
+  for (const auto& header : request_headers_)
+    cross_origin_request.SetHTTPHeaderField(header.key, header.value);
+  MakeCrossOriginAccessRequest(cross_origin_request);
+
+  return false;
+}
+
+void ThreadableLoader::RedirectBlocked() {
+  checker_.RedirectBlocked();
+
+  // Tells the client that a redirect was received but not followed (for an
+  // unknown reason).
+  ThreadableLoaderClient* client = client_;
+  Clear();
+  client->DidFailRedirectCheck();
+}
+
+void ThreadableLoader::DataSent(Resource* resource,
+                                unsigned long long bytes_sent,
+                                unsigned long long total_bytes_to_be_sent) {
+  DCHECK(client_);
+  DCHECK_EQ(resource, GetResource());
+  DCHECK(async_);
+
+  checker_.DataSent();
+  client_->DidSendData(bytes_sent, total_bytes_to_be_sent);
+}
+
+void ThreadableLoader::DataDownloaded(Resource* resource, int data_length) {
+  DCHECK(client_);
+  DCHECK_EQ(resource, GetResource());
+  DCHECK(actual_request_.IsNull());
+
+  checker_.DataDownloaded();
+  client_->DidDownloadData(data_length);
+}
+
+void ThreadableLoader::DidReceiveResourceTiming(
+    Resource* resource,
+    const ResourceTimingInfo& info) {
+  DCHECK(client_);
+  DCHECK_EQ(resource, GetResource());
+
+  client_->DidReceiveResourceTiming(info);
+}
+
+void ThreadableLoader::DidDownloadToBlob(Resource* resource,
+                                         scoped_refptr<BlobDataHandle> blob) {
+  DCHECK(client_);
+  DCHECK_EQ(resource, GetResource());
+
+  checker_.DidDownloadToBlob();
+  client_->DidDownloadToBlob(std::move(blob));
+}
+
+void ThreadableLoader::HandlePreflightResponse(
+    const ResourceResponse& response) {
+  base::Optional<network::CORSErrorStatus> cors_error_status =
+      CORS::CheckPreflightAccess(response.Url(), response.HttpStatusCode(),
+                                 response.HttpHeaderFields(),
+                                 actual_request_.GetFetchCredentialsMode(),
+                                 *GetSecurityOrigin());
+  if (cors_error_status) {
+    HandlePreflightFailure(
+        response.Url(),
+        CORS::GetErrorString(CORS::ErrorParameter::CreateForAccessCheck(
+            *cors_error_status, response.Url(), 0 /* status_code */,
+            *GetSecurityOrigin(), request_context_)));
+    return;
+  }
+
+  base::Optional<network::mojom::CORSError> preflight_error =
+      CORS::CheckPreflight(response.HttpStatusCode());
+  if (preflight_error) {
+    HandlePreflightFailure(
+        response.Url(), CORS::GetErrorString(
+                            CORS::ErrorParameter::CreateForPreflightStatusCheck(
+                                response.HttpStatusCode())));
+    return;
+  }
+
+  if (actual_request_.IsExternalRequest()) {
+    base::Optional<network::CORSErrorStatus> external_preflight_status =
+        CORS::CheckExternalPreflight(response.HttpHeaderFields());
+    if (external_preflight_status) {
+      HandlePreflightFailure(
+          response.Url(),
+          CORS::GetErrorString(
+              CORS::ErrorParameter::CreateForExternalPreflightCheck(
+                  *external_preflight_status)));
+      return;
+    }
+  }
+
+  String access_control_error_description;
+  if (!CORS::EnsurePreflightResultAndCacheOnSuccess(
+          response.HttpHeaderFields(), GetSecurityOrigin()->ToString(),
+          actual_request_.Url(), actual_request_.HttpMethod(),
+          actual_request_.HttpHeaderFields(),
+          actual_request_.GetFetchCredentialsMode(),
+          &access_control_error_description)) {
+    HandlePreflightFailure(response.Url(), access_control_error_description);
+  }
+}
+
+void ThreadableLoader::ReportResponseReceived(
+    unsigned long identifier,
+    const ResourceResponse& response) {
+  LocalFrame* frame = GetDocument() ? GetDocument()->GetFrame() : nullptr;
+  if (!frame)
+    return;
+  DocumentLoader* loader = frame->Loader().GetDocumentLoader();
+  probe::didReceiveResourceResponse(GetExecutionContext(), identifier, loader,
+                                    response, GetResource());
+  frame->Console().ReportResourceResponseReceived(loader, identifier, response);
+}
+
+void ThreadableLoader::ResponseReceived(
+    Resource* resource,
+    const ResourceResponse& response,
+    std::unique_ptr<WebDataConsumerHandle> handle) {
+  DCHECK_EQ(resource, GetResource());
+  DCHECK(client_);
+
+  checker_.ResponseReceived();
+
+  if (handle)
+    is_using_data_consumer_handle_ = true;
+
+  // TODO(toyoshim): Support OOR-CORS preflight and Service Worker case.
+  // Note that CORS-preflight is usually handled in the Network Service side,
+  // but still done in Blink side when it is needed on redirects.
+  // https://crbug.com/736308.
+  if (out_of_blink_cors_ && !response.WasFetchedViaServiceWorker()) {
+    DCHECK(actual_request_.IsNull());
+    fallback_request_for_service_worker_ = ResourceRequest();
+    client_->DidReceiveResponse(resource->Identifier(), response,
+                                std::move(handle));
+    return;
+  }
+
+  // Code path for legacy Blink CORS.
+  if (!actual_request_.IsNull()) {
+    ReportResponseReceived(resource->Identifier(), response);
+    HandlePreflightResponse(response);
+    return;
+  }
+
+  if (response.WasFetchedViaServiceWorker()) {
+    if (response.WasFallbackRequiredByServiceWorker()) {
+      // At this point we must have m_fallbackRequestForServiceWorker. (For
+      // SharedWorker the request won't be CORS or CORS-with-preflight,
+      // therefore fallback-to-network is handled in the browser process when
+      // the ServiceWorker does not call respondWith().)
+      DCHECK(!fallback_request_for_service_worker_.IsNull());
+      ReportResponseReceived(resource->Identifier(), response);
+      LoadFallbackRequestForServiceWorker();
+      return;
+    }
+
+    // It's possible that we issue a fetch with request with non "no-cors"
+    // mode but get an opaque filtered response if a service worker is involved.
+    // We dispatch a CORS failure for the case.
+    // TODO(yhirano): This is probably not spec conformant. Fix it after
+    // https://github.com/w3c/preload/issues/100 is addressed.
+    if (fetch_request_mode_ != network::mojom::FetchRequestMode::kNoCORS &&
+        response.ResponseTypeViaServiceWorker() ==
+            network::mojom::FetchResponseType::kOpaque) {
+      DispatchDidFailAccessControlCheck(
+          ResourceError::CancelledDueToAccessCheckError(
+              response.Url(), ResourceRequestBlockedReason::kOther,
+              CORS::GetErrorString(
+                  CORS::ErrorParameter::CreateForInvalidResponse(
+                      response.Url(), *GetSecurityOrigin()))));
+      return;
+    }
+
+    fallback_request_for_service_worker_ = ResourceRequest();
+    client_->DidReceiveResponse(resource->Identifier(), response,
+                                std::move(handle));
+    return;
+  }
+
+  // Even if the request met the conditions to get handled by a Service Worker
+  // in the constructor of this class (and therefore
+  // |m_fallbackRequestForServiceWorker| is set), the Service Worker may skip
+  // processing the request. Only if the request is same origin, the skipped
+  // response may come here (wasFetchedViaServiceWorker() returns false) since
+  // such a request doesn't have to go through the CORS algorithm by calling
+  // loadFallbackRequestForServiceWorker().
+  DCHECK(fallback_request_for_service_worker_.IsNull() ||
+         GetSecurityOrigin()->CanRequest(
+             fallback_request_for_service_worker_.Url()));
+  fallback_request_for_service_worker_ = ResourceRequest();
+
+  if (CORS::IsCORSEnabledRequestMode(fetch_request_mode_) && cors_flag_) {
+    base::Optional<network::CORSErrorStatus> access_error = CORS::CheckAccess(
+        response.Url(), response.HttpStatusCode(), response.HttpHeaderFields(),
+        fetch_credentials_mode_, *GetSecurityOrigin());
+    if (access_error) {
+      ReportResponseReceived(resource->Identifier(), response);
+      DispatchDidFailAccessControlCheck(
+          ResourceError::CancelledDueToAccessCheckError(
+              response.Url(), ResourceRequestBlockedReason::kOther,
+              CORS::GetErrorString(CORS::ErrorParameter::CreateForAccessCheck(
+                  *access_error, response.Url(), response.HttpStatusCode(),
+                  *GetSecurityOrigin(), request_context_))));
+      return;
+    }
+  }
+
+  client_->DidReceiveResponse(resource->Identifier(), response,
+                              std::move(handle));
+}
+
+void ThreadableLoader::SetSerializedCachedMetadata(Resource*,
+                                                   const char* data,
+                                                   size_t size) {
+  checker_.SetSerializedCachedMetadata();
+
+  if (!actual_request_.IsNull())
+    return;
+  client_->DidReceiveCachedMetadata(data, size);
+}
+
+void ThreadableLoader::DataReceived(Resource* resource,
+                                    const char* data,
+                                    size_t data_length) {
+  DCHECK_EQ(resource, GetResource());
+  DCHECK(client_);
+
+  checker_.DataReceived();
+
+  if (is_using_data_consumer_handle_)
+    return;
+
+  // Preflight data should be invisible to clients.
+  if (!actual_request_.IsNull())
+    return;
+
+  DCHECK(fallback_request_for_service_worker_.IsNull());
+
+  // TODO(junov): Fix the ThreadableLoader ecosystem to use size_t. Until then,
+  // we use safeCast to trap potential overflows.
+  client_->DidReceiveData(data, SafeCast<unsigned>(data_length));
+}
+
+void ThreadableLoader::NotifyFinished(Resource* resource) {
+  DCHECK(client_);
+  DCHECK_EQ(resource, GetResource());
+
+  checker_.NotifyFinished(resource);
+
+  // Don't throw an exception for failed sync local file loads.
+  // TODO(japhet): This logic has been moved around but unchanged since 2007.
+  // Tested by fast/xmlhttprequest/xmlhttprequest-missing-file-exception.html
+  // Do we still need this?
+  bool is_sync_to_local_file = resource->Url().IsLocalFile() && !async_;
+
+  if (resource->ErrorOccurred() && !is_sync_to_local_file) {
+    DispatchDidFail(resource->GetResourceError());
+    return;
+  }
+
+  DCHECK(fallback_request_for_service_worker_.IsNull());
+
+  if (!actual_request_.IsNull()) {
+    DCHECK(actual_request_.IsExternalRequest() || cors_flag_);
+    LoadActualRequest();
+    return;
+  }
+
+  ThreadableLoaderClient* client = client_;
+  // Protect the resource in |didFinishLoading| in order not to release the
+  // downloaded file.
+  Persistent<Resource> protect = GetResource();
+  Clear();
+  client->DidFinishLoading(resource->Identifier());
+}
+
+void ThreadableLoader::DidTimeout(TimerBase* timer) {
+  DCHECK(async_);
+  DCHECK_EQ(timer, &timeout_timer_);
+  // clearResource() may be called in clear() and some other places. clear()
+  // calls stop() on |m_timeoutTimer|. In the other places, the resource is set
+  // again. If the creation fails, clear() is called. So, here, resource() is
+  // always non-nullptr.
+  DCHECK(GetResource());
+  // When |m_client| is set to nullptr only in clear() where |m_timeoutTimer|
+  // is stopped. So, |m_client| is always non-nullptr here.
+  DCHECK(client_);
+
+  DispatchDidFail(ResourceError::TimeoutError(GetResource()->Url()));
+}
+
+void ThreadableLoader::LoadFallbackRequestForServiceWorker() {
+  if (GetResource())
+    checker_.WillRemoveClient();
+  ClearResource();
+  ResourceRequest fallback_request(fallback_request_for_service_worker_);
+  fallback_request_for_service_worker_ = ResourceRequest();
+  DispatchInitialRequest(fallback_request);
+}
+
+void ThreadableLoader::LoadActualRequest() {
+  ResourceRequest actual_request = actual_request_;
+  ResourceLoaderOptions actual_options = actual_options_;
+  actual_request_ = ResourceRequest();
+  actual_options_ = ResourceLoaderOptions();
+
+  if (GetResource())
+    checker_.WillRemoveClient();
+  ClearResource();
+
+  PrepareCrossOriginRequest(actual_request);
+  LoadRequest(actual_request, actual_options);
+}
+
+void ThreadableLoader::HandlePreflightFailure(const KURL& url,
+                                              const String& error_description) {
+  // Prevent NotifyFinished() from bypassing access check.
+  actual_request_ = ResourceRequest();
+
+  DispatchDidFailAccessControlCheck(
+      ResourceError::CancelledDueToAccessCheckError(
+          url, ResourceRequestBlockedReason::kOther, error_description));
+}
+
+void ThreadableLoader::DispatchDidFailAccessControlCheck(
+    const ResourceError& error) {
+  const String message = "Failed to load " + error.FailingURL() + ": " +
+                         error.LocalizedDescription();
+  GetExecutionContext()->AddConsoleMessage(
+      ConsoleMessage::Create(kJSMessageSource, kErrorMessageLevel, message));
+
+  ThreadableLoaderClient* client = client_;
+  Clear();
+  client->DidFail(error);
+}
+
+void ThreadableLoader::DispatchDidFail(const ResourceError& error) {
+  if (error.CORSErrorStatus()) {
+    DCHECK(out_of_blink_cors_);
+    // TODO(toyoshim): Should consider to pass correct arguments instead of
+    // KURL(), and 0 to GetErrorString().
+    // We still need plumbing some more information.
+    GetExecutionContext()->AddConsoleMessage(ConsoleMessage::Create(
+        kJSMessageSource, kErrorMessageLevel,
+        "Failed to load " + error.FailingURL() + ": " +
+            CORS::GetErrorString(CORS::ErrorParameter::Create(
+                                     *error.CORSErrorStatus(),
+                                     KURL(error.FailingURL()), KURL(), 0,
+                                     *GetSecurityOrigin(), request_context_))
+                .Utf8()
+                .data()));
+  }
+  ThreadableLoaderClient* client = client_;
+  Clear();
+  client->DidFail(error);
+}
+
+void ThreadableLoader::LoadRequest(
+    ResourceRequest& request,
+    ResourceLoaderOptions resource_loader_options) {
+  resource_loader_options.cors_handling_by_resource_fetcher =
+      kDisableCORSHandlingByResourceFetcher;
+
+  bool allow_stored_credentials = false;
+  switch (request.GetFetchCredentialsMode()) {
+    case network::mojom::FetchCredentialsMode::kOmit:
+      break;
+    case network::mojom::FetchCredentialsMode::kSameOrigin:
+      // TODO(toyoshim): It's wrong to use |cors_flag| here. Fix it to use the
+      // response tainting.
+      //
+      // TODO(toyoshim): The credentials mode must work even when the "no-cors"
+      // mode is in use. See the following issues:
+      // - https://github.com/whatwg/fetch/issues/130
+      // - https://github.com/whatwg/fetch/issues/169
+      allow_stored_credentials = !cors_flag_;
+      break;
+    case network::mojom::FetchCredentialsMode::kInclude:
+      allow_stored_credentials = true;
+      break;
+  }
+  request.SetAllowStoredCredentials(allow_stored_credentials);
+
+  resource_loader_options.security_origin = security_origin_;
+
+  if (!actual_request_.IsNull())
+    resource_loader_options.data_buffering_policy = kBufferData;
+
+  TimeDelta timeout =
+      TimeDelta::FromMilliseconds(options_.timeout_milliseconds);
+  if (options_.timeout_milliseconds > 0) {
+    if (!async_) {
+      request.SetTimeoutInterval(timeout);
+    } else if (!timeout_timer_.IsActive()) {
+      // The timer can be active if this is the actual request of a
+      // CORS-with-preflight request.
+      timeout_timer_.StartOneShot(timeout, FROM_HERE);
+    }
+  }
+
+  FetchParameters new_params(request, resource_loader_options);
+  DCHECK(!GetResource());
+
+  checker_.WillAddClient();
+  ResourceFetcher* fetcher = loading_context_->GetResourceFetcher();
+  if (request.GetRequestContext() == WebURLRequest::kRequestContextVideo ||
+      request.GetRequestContext() == WebURLRequest::kRequestContextAudio) {
+    DCHECK(async_);
+    RawResource::FetchMedia(new_params, fetcher, this);
+  } else if (request.GetRequestContext() ==
+             WebURLRequest::kRequestContextManifest) {
+    DCHECK(async_);
+    RawResource::FetchManifest(new_params, fetcher, this);
+  } else if (async_) {
+    RawResource::Fetch(new_params, fetcher, this);
+  } else {
+    RawResource::FetchSynchronously(new_params, fetcher, this);
+  }
+}
+
+bool ThreadableLoader::IsAllowedRedirect(
+    network::mojom::FetchRequestMode fetch_request_mode,
+    const KURL& url) const {
+  if (fetch_request_mode == network::mojom::FetchRequestMode::kNoCORS)
+    return true;
+
+  return !cors_flag_ && GetSecurityOrigin()->CanRequest(url);
+}
+
+const SecurityOrigin* ThreadableLoader::GetSecurityOrigin() const {
+  return security_origin_
+             ? security_origin_.get()
+             : loading_context_->GetFetchContext()->GetSecurityOrigin();
+}
+
+Document* ThreadableLoader::GetDocument() const {
+  ExecutionContext* context = GetExecutionContext();
+  if (context->IsDocument())
+    return ToDocument(context);
+  return nullptr;
+}
+
+ExecutionContext* ThreadableLoader::GetExecutionContext() const {
+  DCHECK(loading_context_);
+  return loading_context_->GetExecutionContext();
+}
+
+void ThreadableLoader::Trace(blink::Visitor* visitor) {
+  visitor->Trace(loading_context_);
+  RawResourceClient::Trace(visitor);
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/loader/threadable_loader.h b/third_party/blink/renderer/core/loader/threadable_loader.h
index c0f81603..e64dee1 100644
--- a/third_party/blink/renderer/core/loader/threadable_loader.h
+++ b/third_party/blink/renderer/core/loader/threadable_loader.h
@@ -1,5 +1,6 @@
 /*
- * Copyright (C) 2009 Google Inc. All rights reserved.
+ * Copyright (C) 2009, 2012 Google Inc. All rights reserved.
+ * Copyright (C) 2013, Intel Corporation
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
@@ -34,52 +35,41 @@
 #include <memory>
 
 #include "base/macros.h"
+#include "services/network/public/mojom/fetch_api.mojom-blink.h"
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/platform/cross_thread_copier.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
+#include "third_party/blink/renderer/platform/loader/fetch/raw_resource.h"
+#include "third_party/blink/renderer/platform/loader/fetch/resource_error.h"
 #include "third_party/blink/renderer/platform/loader/fetch/resource_loader_options.h"
+#include "third_party/blink/renderer/platform/network/http_header_map.h"
+#include "third_party/blink/renderer/platform/timer.h"
+#include "third_party/blink/renderer/platform/weborigin/referrer.h"
 #include "third_party/blink/renderer/platform/wtf/allocator.h"
+#include "third_party/blink/renderer/platform/wtf/forward.h"
+#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
+#include "third_party/blink/renderer/platform/wtf/time.h"
 
 namespace blink {
 
-class ResourceRequest;
 class ExecutionContext;
+class Document;
+class KURL;
+class ResourceRequest;
+class SecurityOrigin;
+class ThreadableLoadingContext;
 class ThreadableLoaderClient;
 
+// TODO(japhet): This appears unnecessary. Just take a timout_milliseconds
+// optional param in constructor?
 struct ThreadableLoaderOptions {
   DISALLOW_NEW();
   ThreadableLoaderOptions() : timeout_milliseconds(0) {}
-
   // When adding members, CrossThreadThreadableLoaderOptionsData should
   // be updated.
-
   unsigned long timeout_milliseconds;
 };
 
-// Encode AtomicString as String to cross threads.
-struct CrossThreadThreadableLoaderOptionsData {
-  STACK_ALLOCATED();
-  explicit CrossThreadThreadableLoaderOptionsData(
-      const ThreadableLoaderOptions& options)
-      : timeout_milliseconds(options.timeout_milliseconds) {}
-
-  operator ThreadableLoaderOptions() const {
-    ThreadableLoaderOptions options;
-    options.timeout_milliseconds = timeout_milliseconds;
-    return options;
-  }
-
-  unsigned long timeout_milliseconds;
-};
-
-template <>
-struct CrossThreadCopier<ThreadableLoaderOptions> {
-  typedef CrossThreadThreadableLoaderOptionsData Type;
-  static Type Copy(const ThreadableLoaderOptions& options) {
-    return CrossThreadThreadableLoaderOptionsData(options);
-  }
-};
-
 // Useful for doing loader operations from any thread (not threadsafe, just able
 // to run on threads other than the main thread).
 //
@@ -92,7 +82,10 @@
 //   that this ThreadableLoader creates. It can be altered e.g. when
 //   redirect happens.
 class CORE_EXPORT ThreadableLoader
-    : public GarbageCollectedFinalized<ThreadableLoader> {
+    : public GarbageCollectedFinalized<ThreadableLoader>,
+      private RawResourceClient {
+  USING_GARBAGE_COLLECTED_MIXIN(ThreadableLoader);
+
  public:
   static void LoadResourceSynchronously(ExecutionContext&,
                                         const ResourceRequest&,
@@ -100,6 +93,10 @@
                                         const ThreadableLoaderOptions&,
                                         const ResourceLoaderOptions&);
 
+  // Exposed for testing. Code outside this class should not call this function.
+  static std::unique_ptr<ResourceRequest>
+  CreateAccessControlPreflightRequestForTesting(const ResourceRequest&);
+
   // This method never returns nullptr.
   //
   // This method must always be followed by start() call.
@@ -136,9 +133,9 @@
                                   const ThreadableLoaderOptions&,
                                   const ResourceLoaderOptions&);
 
-  // The methods on the ThreadableLoaderClient passed on create() call
-  // may be called synchronous to start() call.
-  virtual void Start(const ResourceRequest&) = 0;
+  ~ThreadableLoader() override;
+
+  void Start(const ResourceRequest&);
 
   // A ThreadableLoader may have a timeout specified. It is possible, in some
   // cases, for the timeout to be overridden after the request is sent (for
@@ -146,22 +143,166 @@
   //
   // Set a new timeout relative to the time the request started, in
   // milliseconds.
-  virtual void OverrideTimeout(unsigned long timeout_milliseconds) = 0;
+  void OverrideTimeout(unsigned long timeout_milliseconds);
 
-  // Cancel the request.
-  virtual void Cancel() = 0;
+  void Cancel();
 
-  // Detach the loader from the request. This function is for "keepalive"
+  // Detach the loader from the request. This ffunction is for "keepalive"
   // requests. No notification will be sent to the client, but the request
   // will be processed.
-  virtual void Detach() = 0;
+  void Detach();
 
-  virtual ~ThreadableLoader() = default;
+  void SetDefersLoading(bool);
 
-  virtual void Trace(blink::Visitor* visitor) {}
+  void Trace(blink::Visitor* visitor) override;
 
- protected:
-  ThreadableLoader() = default;
+ private:
+  class DetachedClient;
+  enum BlockingBehavior { kLoadSynchronously, kLoadAsynchronously };
+
+  ThreadableLoader(ExecutionContext&,
+                   ThreadableLoaderClient*,
+                   BlockingBehavior,
+                   const ThreadableLoaderOptions&,
+                   const ResourceLoaderOptions&);
+
+  static std::unique_ptr<ResourceRequest> CreateAccessControlPreflightRequest(
+      const ResourceRequest&,
+      const SecurityOrigin*);
+
+  void Clear();
+
+  // ResourceClient
+  void NotifyFinished(Resource*) override;
+
+  String DebugName() const override { return "ThreadableLoader"; }
+
+  // RawResourceClient
+  void DataSent(Resource*,
+                unsigned long long bytes_sent,
+                unsigned long long total_bytes_to_be_sent) override;
+  void ResponseReceived(Resource*,
+                        const ResourceResponse&,
+                        std::unique_ptr<WebDataConsumerHandle>) override;
+  void SetSerializedCachedMetadata(Resource*, const char*, size_t) override;
+  void DataReceived(Resource*, const char* data, size_t data_length) override;
+  bool RedirectReceived(Resource*,
+                        const ResourceRequest&,
+                        const ResourceResponse&) override;
+  void RedirectBlocked() override;
+  void DataDownloaded(Resource*, int) override;
+  void DidReceiveResourceTiming(Resource*, const ResourceTimingInfo&) override;
+  void DidDownloadToBlob(Resource*, scoped_refptr<BlobDataHandle>) override;
+
+  // Notify Inspector and log to console about resource response. Use this
+  // method if response is not going to be finished normally.
+  void ReportResponseReceived(unsigned long identifier,
+                              const ResourceResponse&);
+
+  void DidTimeout(TimerBase*);
+  // Calls the appropriate loading method according to policy and data about
+  // origin. Only for handling the initial load (including fallback after
+  // consulting ServiceWorker).
+  void DispatchInitialRequest(ResourceRequest&);
+  void MakeCrossOriginAccessRequest(const ResourceRequest&);
+
+  // Loads m_fallbackRequestForServiceWorker.
+  void LoadFallbackRequestForServiceWorker();
+  // Issues a CORS preflight.
+  void LoadPreflightRequest(const ResourceRequest&,
+                            const ResourceLoaderOptions&);
+  // Loads actual_request_.
+  void LoadActualRequest();
+  // Clears actual_request_ and reports access control check failure to
+  // m_client.
+  void HandlePreflightFailure(const KURL&, const String& error_description);
+  // Investigates the response for the preflight request. If successful,
+  // the actual request will be made later in NotifyFinished().
+  void HandlePreflightResponse(const ResourceResponse&);
+
+  void DispatchDidFailAccessControlCheck(const ResourceError&);
+  void DispatchDidFail(const ResourceError&);
+
+  void PrepareCrossOriginRequest(ResourceRequest&) const;
+
+  // This method modifies the ResourceRequest by calling
+  // SetAllowStoredCredentials() on it based on same-origin-ness and the
+  // credentials mode.
+  //
+  // This method configures the ResourceLoaderOptions so that the underlying
+  // ResourceFetcher doesn't perform some part of the CORS logic since this
+  // class performs it by itself.
+  void LoadRequest(ResourceRequest&, ResourceLoaderOptions);
+  bool IsAllowedRedirect(network::mojom::FetchRequestMode, const KURL&) const;
+
+  const SecurityOrigin* GetSecurityOrigin() const;
+
+  // Returns null if the loader is not associated with Document.
+  // TODO(kinuko): Remove dependency to document.
+  Document* GetDocument() const;
+  ExecutionContext* GetExecutionContext() const;
+
+  ThreadableLoaderClient* client_;
+  Member<ThreadableLoadingContext> loading_context_;
+
+  const ThreadableLoaderOptions options_;
+  // Some items may be overridden by m_forceDoNotAllowStoredCredentials and
+  // m_securityOrigin. In such a case, build a ResourceLoaderOptions with
+  // up-to-date values from them and this variable, and use it.
+  const ResourceLoaderOptions resource_loader_options_;
+
+  // True when feature OutOfBlinkCORS is enabled (https://crbug.com/736308).
+  bool out_of_blink_cors_;
+
+  // Corresponds to the CORS flag in the Fetch spec.
+  bool cors_flag_;
+  scoped_refptr<const SecurityOrigin> security_origin_;
+
+  // Set to true when the response data is given to a data consumer handle.
+  bool is_using_data_consumer_handle_;
+
+  const bool async_;
+
+  // Holds the original request context (used for sanity checks).
+  WebURLRequest::RequestContext request_context_;
+
+  // Saved so that we can use the original value for the modes in
+  // ResponseReceived() where |resource| might be a reused one (e.g. preloaded
+  // resource) which can have different modes.
+  network::mojom::FetchRequestMode fetch_request_mode_;
+  network::mojom::FetchCredentialsMode fetch_credentials_mode_;
+
+  // Holds the original request for fallback in case the Service Worker
+  // does not respond.
+  ResourceRequest fallback_request_for_service_worker_;
+
+  // Holds the original request and options for it during preflight request
+  // handling phase.
+  ResourceRequest actual_request_;
+  ResourceLoaderOptions actual_options_;
+
+  // stores request headers in case of a cross-origin redirect.
+  HTTPHeaderMap request_headers_;
+
+  TaskRunnerTimer<ThreadableLoader> timeout_timer_;
+  TimeTicks request_started_;  // Time an asynchronous fetch request is started
+
+  // Max number of times that this ThreadableLoader can follow
+  // cross-origin redirects. This is used to limit the number of redirects. But
+  // this value is not the max number of total redirects allowed, because
+  // same-origin redirects are not counted here.
+  int cors_redirect_limit_;
+
+  network::mojom::FetchRedirectMode redirect_mode_;
+
+  // Holds the referrer after a redirect response was received. This referrer is
+  // used to populate the HTTP Referer header when following the redirect.
+  bool override_referrer_;
+  Referrer referrer_after_redirect_;
+
+  bool detached_ = false;
+
+  RawResourceClientStateChecker checker_;
 
   DISALLOW_COPY_AND_ASSIGN(ThreadableLoader);
 };
diff --git a/third_party/blink/renderer/core/loader/threadable_loader_client.h b/third_party/blink/renderer/core/loader/threadable_loader_client.h
index ed55b27..a5404ed7 100644
--- a/third_party/blink/renderer/core/loader/threadable_loader_client.h
+++ b/third_party/blink/renderer/core/loader/threadable_loader_client.h
@@ -50,7 +50,12 @@
  public:
   virtual void DidSendData(unsigned long long /*bytesSent*/,
                            unsigned long long /*totalBytesToBeSent*/) {}
+  // TODO(japhet?): Merge these redirect callbacks.
   virtual void DidReceiveRedirectTo(const KURL&) {}
+  virtual bool WillFollowRedirect(const KURL& new_url,
+                                  const ResourceResponse&) {
+    return true;
+  }
   virtual void DidReceiveResponse(unsigned long /*identifier*/,
                                   const ResourceResponse&,
                                   std::unique_ptr<WebDataConsumerHandle>) {}
@@ -61,8 +66,6 @@
   virtual void DidFailRedirectCheck() {}
   virtual void DidReceiveResourceTiming(const ResourceTimingInfo&) {}
 
-  virtual bool IsDocumentThreadableLoaderClient() { return false; }
-
   virtual void DidDownloadData(int /*dataLength*/) {}
   // Called for requests that had DownloadToBlob set to true. Can be called with
   // null if creating the blob failed for some reason (but the download itself
diff --git a/third_party/blink/renderer/core/loader/threadable_loader_test.cc b/third_party/blink/renderer/core/loader/threadable_loader_test.cc
index 0638411..07fc4f1 100644
--- a/third_party/blink/renderer/core/loader/threadable_loader_test.cc
+++ b/third_party/blink/renderer/core/loader/threadable_loader_test.cc
@@ -17,11 +17,10 @@
 #include "third_party/blink/public/platform/web_url_request.h"
 #include "third_party/blink/public/platform/web_url_response.h"
 #include "third_party/blink/public/platform/web_worker_fetch_context.h"
-#include "third_party/blink/renderer/core/loader/document_threadable_loader.h"
+#include "third_party/blink/renderer/core/loader/threadable_loader.h"
 #include "third_party/blink/renderer/core/loader/threadable_loader_client.h"
 #include "third_party/blink/renderer/core/loader/threadable_loading_context.h"
 #include "third_party/blink/renderer/core/loader/worker_fetch_context.h"
-#include "third_party/blink/renderer/core/loader/worker_threadable_loader.h"
 #include "third_party/blink/renderer/core/testing/dummy_page_holder.h"
 #include "third_party/blink/renderer/core/workers/worker_reporting_proxy.h"
 #include "third_party/blink/renderer/core/workers/worker_thread_test_helper.h"
@@ -198,9 +197,8 @@
   void CreateLoader(ThreadableLoaderClient* client) override {
     ThreadableLoaderOptions options;
     ResourceLoaderOptions resource_loader_options;
-    loader_ = DocumentThreadableLoader::Create(
-        *ThreadableLoadingContext::Create(GetDocument()), client, options,
-        resource_loader_options);
+    loader_ = ThreadableLoader::Create(GetDocument(), client, options,
+                                       resource_loader_options);
   }
 
   void StartLoader(const ResourceRequest& request) override {
@@ -233,7 +231,7 @@
 
   std::unique_ptr<DummyPageHolder> dummy_page_holder_;
   Checkpoint checkpoint_;
-  Persistent<DocumentThreadableLoader> loader_;
+  Persistent<ThreadableLoader> loader_;
 };
 
 class WebWorkerFetchContextForTest : public WebWorkerFetchContext {
@@ -394,10 +392,7 @@
     ThreadableLoaderOptions options;
     ResourceLoaderOptions resource_loader_options;
 
-    // Ensure that WorkerThreadableLoader is created.
-    // ThreadableLoader::create() determines whether it should create
-    // a DocumentThreadableLoader or WorkerThreadableLoader based on
-    // isWorkerGlobalScope().
+    // Ensure that ThreadableLoader is created.
     DCHECK(worker_thread_->GlobalScope()->IsWorkerGlobalScope());
 
     loader_ = ThreadableLoader::Create(*worker_thread_->GlobalScope(), client,
@@ -623,9 +618,7 @@
   EXPECT_CALL(GetCheckpoint(), Call(2));
   EXPECT_CALL(*Client(), DidReceiveResponseMock(_, _, _));
   EXPECT_CALL(*Client(), DidReceiveData(StrEq("fox"), 4));
-  // We expect didReceiveResourceTiming() calls in DocumentThreadableLoader;
-  // it's used to connect DocumentThreadableLoader to WorkerThreadableLoader,
-  // not to ThreadableLoaderClient.
+  // We expect didReceiveResourceTiming() calls in ThreadableLoader.
   EXPECT_CALL(*Client(), DidReceiveResourceTiming(_));
   EXPECT_CALL(*Client(), DidFinishLoading(_));
 
@@ -903,6 +896,74 @@
   CallCheckpoint(2);
 }
 
+TEST(ThreadableLoaderCreatePreflightRequestTest, LexicographicalOrder) {
+  ResourceRequest request;
+  request.AddHTTPHeaderField("Orange", "Orange");
+  request.AddHTTPHeaderField("Apple", "Red");
+  request.AddHTTPHeaderField("Kiwifruit", "Green");
+  request.AddHTTPHeaderField("Content-Type", "application/octet-stream");
+  request.AddHTTPHeaderField("Strawberry", "Red");
+
+  std::unique_ptr<ResourceRequest> preflight =
+      ThreadableLoader::CreateAccessControlPreflightRequestForTesting(request);
+
+  EXPECT_EQ("apple,content-type,kiwifruit,orange,strawberry",
+            preflight->HttpHeaderField("Access-Control-Request-Headers"));
+}
+
+TEST(ThreadableLoaderCreatePreflightRequestTest, ExcludeSimpleHeaders) {
+  ResourceRequest request;
+  request.AddHTTPHeaderField("Accept", "everything");
+  request.AddHTTPHeaderField("Accept-Language", "everything");
+  request.AddHTTPHeaderField("Content-Language", "everything");
+  request.AddHTTPHeaderField("Save-Data", "on");
+
+  std::unique_ptr<ResourceRequest> preflight =
+      ThreadableLoader::CreateAccessControlPreflightRequestForTesting(request);
+
+  // Do not emit empty-valued headers; an empty list of non-"CORS safelisted"
+  // request headers should cause "Access-Control-Request-Headers:" to be
+  // left out in the preflight request.
+  EXPECT_EQ(g_null_atom,
+            preflight->HttpHeaderField("Access-Control-Request-Headers"));
+}
+
+TEST(ThreadableLoaderCreatePreflightRequestTest,
+     ExcludeSimpleContentTypeHeader) {
+  ResourceRequest request;
+  request.AddHTTPHeaderField("Content-Type", "text/plain");
+
+  std::unique_ptr<ResourceRequest> preflight =
+      ThreadableLoader::CreateAccessControlPreflightRequestForTesting(request);
+
+  // Empty list also; see comment in test above.
+  EXPECT_EQ(g_null_atom,
+            preflight->HttpHeaderField("Access-Control-Request-Headers"));
+}
+
+TEST(ThreadableLoaderCreatePreflightRequestTest, IncludeNonSimpleHeader) {
+  ResourceRequest request;
+  request.AddHTTPHeaderField("X-Custom-Header", "foobar");
+
+  std::unique_ptr<ResourceRequest> preflight =
+      ThreadableLoader::CreateAccessControlPreflightRequestForTesting(request);
+
+  EXPECT_EQ("x-custom-header",
+            preflight->HttpHeaderField("Access-Control-Request-Headers"));
+}
+
+TEST(ThreadableLoaderCreatePreflightRequestTest,
+     IncludeNonSimpleContentTypeHeader) {
+  ResourceRequest request;
+  request.AddHTTPHeaderField("Content-Type", "application/octet-stream");
+
+  std::unique_ptr<ResourceRequest> preflight =
+      ThreadableLoader::CreateAccessControlPreflightRequestForTesting(request);
+
+  EXPECT_EQ("content-type",
+            preflight->HttpHeaderField("Access-Control-Request-Headers"));
+}
+
 }  // namespace
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/loader/worker_threadable_loader.cc b/third_party/blink/renderer/core/loader/worker_threadable_loader.cc
deleted file mode 100644
index 7fe7bf5..0000000
--- a/third_party/blink/renderer/core/loader/worker_threadable_loader.cc
+++ /dev/null
@@ -1,680 +0,0 @@
-/*
- * Copyright (C) 2009, 2010 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "third_party/blink/renderer/core/loader/worker_threadable_loader.h"
-
-#include <memory>
-
-#include "base/debug/alias.h"
-#include "third_party/blink/public/platform/task_type.h"
-#include "third_party/blink/renderer/core/loader/document_threadable_loader.h"
-#include "third_party/blink/renderer/core/loader/threadable_loading_context.h"
-#include "third_party/blink/renderer/core/timing/worker_global_scope_performance.h"
-#include "third_party/blink/renderer/core/workers/worker_global_scope.h"
-#include "third_party/blink/renderer/core/workers/worker_thread.h"
-#include "third_party/blink/renderer/core/workers/worker_thread_lifecycle_context.h"
-#include "third_party/blink/renderer/platform/cross_thread_functional.h"
-#include "third_party/blink/renderer/platform/heap/safe_point.h"
-#include "third_party/blink/renderer/platform/loader/fetch/resource_error.h"
-#include "third_party/blink/renderer/platform/loader/fetch/resource_request.h"
-#include "third_party/blink/renderer/platform/loader/fetch/resource_response.h"
-#include "third_party/blink/renderer/platform/loader/fetch/resource_timing_info.h"
-#include "third_party/blink/renderer/platform/weborigin/kurl.h"
-#include "third_party/blink/renderer/platform/weborigin/security_policy.h"
-#include "third_party/blink/renderer/platform/wtf/functional.h"
-
-namespace blink {
-
-namespace {
-
-std::unique_ptr<Vector<char>> CreateVectorFromMemoryRegion(
-    const char* data,
-    unsigned data_length) {
-  std::unique_ptr<Vector<char>> buffer =
-      std::make_unique<Vector<char>>(data_length);
-  memcpy(buffer->data(), data, data_length);
-  return buffer;
-}
-
-}  // namespace
-
-struct WorkerThreadableLoader::TaskWithLocation final {
-  TaskWithLocation(const base::Location& location, CrossThreadClosure task)
-      : location_(location), task_(std::move(task)) {}
-  TaskWithLocation(TaskWithLocation&& task)
-      : TaskWithLocation(task.location_, std::move(task.task_)) {}
-  ~TaskWithLocation() = default;
-
-  base::Location location_;
-  CrossThreadClosure task_;
-};
-
-// Observing functions and wait() need to be called on the worker thread.
-// Setting functions and signal() need to be called on the parent thread.
-// All observing functions must be called after wait() returns, and all
-// setting functions must be called before signal() is called.
-class WorkerThreadableLoader::WaitableEventWithTasks final
-    : public ThreadSafeRefCounted<WaitableEventWithTasks> {
- public:
-  static scoped_refptr<WaitableEventWithTasks> Create(
-      scoped_refptr<base::SingleThreadTaskRunner> worker_loading_task_runner) {
-    return base::AdoptRef(
-        new WaitableEventWithTasks(worker_loading_task_runner));
-  }
-
-  void Signal() {
-#if DCHECK_IS_ON()
-    DCHECK(!worker_loading_task_runner_->BelongsToCurrentThread());
-#endif
-    CHECK(!is_signal_called_);
-    is_signal_called_ = true;
-    event_.Signal();
-  }
-  void Wait() {
-#if DCHECK_IS_ON()
-    DCHECK(worker_loading_task_runner_->BelongsToCurrentThread());
-#endif
-    CHECK(!is_wait_done_);
-    event_.Wait();
-    is_wait_done_ = true;
-  }
-
-  // Observing functions
-  bool IsAborted() const {
-#if DCHECK_IS_ON()
-    DCHECK(worker_loading_task_runner_->BelongsToCurrentThread());
-#endif
-    CHECK(is_wait_done_);
-    return is_aborted_;
-  }
-  Vector<TaskWithLocation> Take() {
-#if DCHECK_IS_ON()
-    DCHECK(worker_loading_task_runner_->BelongsToCurrentThread());
-#endif
-    CHECK(is_wait_done_);
-    return std::move(tasks_);
-  }
-
-  // Setting functions
-  void Append(TaskWithLocation task) {
-#if DCHECK_IS_ON()
-    DCHECK(!worker_loading_task_runner_->BelongsToCurrentThread());
-#endif
-    CHECK(!is_signal_called_);
-    tasks_.push_back(std::move(task));
-  }
-  void SetIsAborted() {
-#if DCHECK_IS_ON()
-    DCHECK(!worker_loading_task_runner_->BelongsToCurrentThread());
-#endif
-    CHECK(!is_signal_called_);
-    is_aborted_ = true;
-  }
-
-#if DCHECK_IS_ON()
-  // A task runner from the WorkerGlobalScope that requested the fetch.
-  // Used for thread correctness DCHECKs.
-  scoped_refptr<base::SingleThreadTaskRunner> worker_loading_task_runner_;
-#endif
-
- private:
-  explicit WaitableEventWithTasks(
-      scoped_refptr<base::SingleThreadTaskRunner> worker_loading_task_runner) {
-#if DCHECK_IS_ON()
-    worker_loading_task_runner_ = worker_loading_task_runner;
-#endif
-  }
-
-  WaitableEvent event_;
-  Vector<TaskWithLocation> tasks_;
-  bool is_aborted_ = false;
-  bool is_signal_called_ = false;
-  bool is_wait_done_ = false;
-};
-
-WorkerThreadableLoader::TaskForwarder::TaskForwarder(
-    scoped_refptr<WaitableEventWithTasks> event_with_tasks)
-    : event_with_tasks_(std::move(event_with_tasks)) {
-#if DCHECK_IS_ON()
-  DCHECK(!event_with_tasks_->worker_loading_task_runner_
-              ->BelongsToCurrentThread());
-#endif
-}
-
-void WorkerThreadableLoader::TaskForwarder::ForwardTask(
-    const base::Location& location,
-    CrossThreadClosure task) {
-#if DCHECK_IS_ON()
-  DCHECK(!event_with_tasks_->worker_loading_task_runner_
-              ->BelongsToCurrentThread());
-#endif
-  event_with_tasks_->Append(TaskWithLocation(location, std::move(task)));
-}
-
-void WorkerThreadableLoader::TaskForwarder::ForwardTaskWithDoneSignal(
-    const base::Location& location,
-    CrossThreadClosure task) {
-#if DCHECK_IS_ON()
-  DCHECK(!event_with_tasks_->worker_loading_task_runner_
-              ->BelongsToCurrentThread());
-#endif
-  event_with_tasks_->Append(TaskWithLocation(location, std::move(task)));
-  event_with_tasks_->Signal();
-}
-
-void WorkerThreadableLoader::TaskForwarder::Abort() {
-#if DCHECK_IS_ON()
-  DCHECK(!event_with_tasks_->worker_loading_task_runner_
-              ->BelongsToCurrentThread());
-#endif
-  event_with_tasks_->SetIsAborted();
-  event_with_tasks_->Signal();
-}
-
-WorkerThreadableLoader::WorkerThreadableLoader(
-    WorkerGlobalScope& worker_global_scope,
-    ThreadableLoaderClient* client,
-    const ThreadableLoaderOptions& options,
-    const ResourceLoaderOptions& resource_loader_options)
-    : worker_global_scope_(&worker_global_scope),
-      parent_execution_context_task_runners_(
-          worker_global_scope.GetThread()
-              ->GetParentExecutionContextTaskRunners()),
-      client_(client),
-      threadable_loader_options_(options),
-      resource_loader_options_(resource_loader_options) {
-  DCHECK(client);
-}
-
-void WorkerThreadableLoader::LoadResourceSynchronously(
-    WorkerGlobalScope& worker_global_scope,
-    const ResourceRequest& request,
-    ThreadableLoaderClient& client,
-    const ThreadableLoaderOptions& options,
-    const ResourceLoaderOptions& resource_loader_options) {
-  (new WorkerThreadableLoader(worker_global_scope, &client, options,
-                              resource_loader_options))
-      ->Start(request);
-}
-
-WorkerThreadableLoader::~WorkerThreadableLoader() {
-  DCHECK(!parent_thread_loader_holder_);
-  DCHECK(!client_);
-}
-
-void WorkerThreadableLoader::Start(const ResourceRequest& original_request) {
-  DCHECK(worker_global_scope_->IsContextThread());
-  ResourceRequest request(original_request);
-  if (!request.DidSetHTTPReferrer()) {
-    request.SetHTTPReferrer(SecurityPolicy::GenerateReferrer(
-        worker_global_scope_->GetReferrerPolicy(), request.Url(),
-        worker_global_scope_->OutgoingReferrer()));
-  }
-
-
-  WorkerThread* worker_thread = worker_global_scope_->GetThread();
-  scoped_refptr<base::SingleThreadTaskRunner> worker_loading_task_runner =
-      worker_global_scope_->GetTaskRunner(TaskType::kInternalLoading);
-  scoped_refptr<WaitableEventWithTasks> event_with_tasks =
-      WaitableEventWithTasks::Create(worker_loading_task_runner);
-  PostCrossThreadTask(
-      *parent_execution_context_task_runners_->Get(TaskType::kInternalLoading),
-      FROM_HERE,
-      CrossThreadBind(
-          &ParentThreadLoaderHolder::CreateAndStart,
-          WrapCrossThreadPersistent(this),
-          WrapCrossThreadPersistent(worker_thread->GetLoadingContext()),
-          std::move(worker_loading_task_runner),
-          WrapCrossThreadPersistent(
-              worker_thread->GetWorkerThreadLifecycleContext()),
-          request, threadable_loader_options_, resource_loader_options_,
-          event_with_tasks));
-
-  event_with_tasks->Wait();
-
-  if (event_with_tasks->IsAborted()) {
-    // This thread is going to terminate.
-    Cancel();
-    return;
-  }
-
-  for (auto& task : event_with_tasks->Take()) {
-    // Store the program counter where the task is posted from, and alias
-    // it to ensure it is stored in the crash dump.
-    const void* program_counter = task.location_.program_counter();
-    base::debug::Alias(&program_counter);
-
-    std::move(task.task_).Run();
-  }
-}
-
-void WorkerThreadableLoader::OverrideTimeout(
-    unsigned long timeout_milliseconds) {
-  DCHECK(worker_global_scope_->IsContextThread());
-  if (!parent_thread_loader_holder_)
-    return;
-  PostCrossThreadTask(
-      *parent_execution_context_task_runners_->Get(TaskType::kInternalLoading),
-      FROM_HERE,
-      CrossThreadBind(&ParentThreadLoaderHolder::OverrideTimeout,
-                      parent_thread_loader_holder_, timeout_milliseconds));
-}
-
-void WorkerThreadableLoader::Cancel() {
-  DCHECK(worker_global_scope_->IsContextThread());
-  if (parent_thread_loader_holder_) {
-    PostCrossThreadTask(*parent_execution_context_task_runners_->Get(
-                            TaskType::kInternalLoading),
-                        FROM_HERE,
-                        CrossThreadBind(&ParentThreadLoaderHolder::Cancel,
-                                        parent_thread_loader_holder_));
-    parent_thread_loader_holder_ = nullptr;
-  }
-
-  if (!client_)
-    return;
-
-  // If the client hasn't reached a termination state, then transition it
-  // by sending a cancellation error.
-  // Note: no more client callbacks will be done after this method -- the
-  // clearClient() call ensures that.
-  DidFail(ResourceError::CancelledError(KURL()));
-  DCHECK(!client_);
-}
-
-void WorkerThreadableLoader::Detach() {
-  // NOTREACHED
-  // Currently only "synchronous" requests are using this class and we will
-  // deprecate it in the future. As this method cannot be called for such
-  // requests, we don't implement it.
-  CHECK(false);
-}
-
-void WorkerThreadableLoader::DidStart(
-    ParentThreadLoaderHolder* parent_thread_loader_holder) {
-  DCHECK(worker_global_scope_->IsContextThread());
-  DCHECK(!parent_thread_loader_holder_);
-  DCHECK(parent_thread_loader_holder);
-  if (!client_) {
-    // The thread is terminating.
-    PostCrossThreadTask(*parent_execution_context_task_runners_->Get(
-                            TaskType::kInternalLoading),
-                        FROM_HERE,
-                        CrossThreadBind(&ParentThreadLoaderHolder::Cancel,
-                                        WrapCrossThreadPersistent(
-                                            parent_thread_loader_holder)));
-    return;
-  }
-
-  parent_thread_loader_holder_ = parent_thread_loader_holder;
-}
-
-void WorkerThreadableLoader::DidSendData(
-    unsigned long long bytes_sent,
-    unsigned long long total_bytes_to_be_sent) {
-  DCHECK(worker_global_scope_->IsContextThread());
-  if (!client_)
-    return;
-  client_->DidSendData(bytes_sent, total_bytes_to_be_sent);
-}
-
-void WorkerThreadableLoader::DidReceiveRedirectTo(const KURL& url) {
-  DCHECK(worker_global_scope_->IsContextThread());
-  if (!client_)
-    return;
-  client_->DidReceiveRedirectTo(url);
-}
-
-void WorkerThreadableLoader::DidReceiveResponse(
-    unsigned long identifier,
-    std::unique_ptr<CrossThreadResourceResponseData> response_data,
-    std::unique_ptr<WebDataConsumerHandle> handle) {
-  DCHECK(worker_global_scope_->IsContextThread());
-  if (!client_)
-    return;
-  ResourceResponse response(response_data.get());
-  client_->DidReceiveResponse(identifier, response, std::move(handle));
-}
-
-void WorkerThreadableLoader::DidReceiveData(
-    std::unique_ptr<Vector<char>> data) {
-  DCHECK(worker_global_scope_->IsContextThread());
-  CHECK_LE(data->size(), std::numeric_limits<unsigned>::max());
-  if (!client_)
-    return;
-  client_->DidReceiveData(data->data(), data->size());
-}
-
-void WorkerThreadableLoader::DidReceiveCachedMetadata(
-    std::unique_ptr<Vector<char>> data) {
-  DCHECK(worker_global_scope_->IsContextThread());
-  if (!client_)
-    return;
-  client_->DidReceiveCachedMetadata(data->data(), data->size());
-}
-
-void WorkerThreadableLoader::DidFinishLoading(unsigned long identifier) {
-  DCHECK(worker_global_scope_->IsContextThread());
-  if (!client_)
-    return;
-  auto* client = client_;
-  client_ = nullptr;
-  parent_thread_loader_holder_ = nullptr;
-  client->DidFinishLoading(identifier);
-}
-
-void WorkerThreadableLoader::DidFail(const ResourceError& error) {
-  DCHECK(worker_global_scope_->IsContextThread());
-  if (!client_)
-    return;
-  auto* client = client_;
-  client_ = nullptr;
-  parent_thread_loader_holder_ = nullptr;
-  client->DidFail(error);
-}
-
-void WorkerThreadableLoader::DidFailRedirectCheck() {
-  DCHECK(worker_global_scope_->IsContextThread());
-  if (!client_)
-    return;
-  auto* client = client_;
-  client_ = nullptr;
-  parent_thread_loader_holder_ = nullptr;
-  client->DidFailRedirectCheck();
-}
-
-void WorkerThreadableLoader::DidDownloadData(int data_length) {
-  DCHECK(worker_global_scope_->IsContextThread());
-  if (!client_)
-    return;
-  client_->DidDownloadData(data_length);
-}
-
-void WorkerThreadableLoader::DidDownloadToBlob(
-    scoped_refptr<BlobDataHandle> blob) {
-  DCHECK(worker_global_scope_->IsContextThread());
-  if (!client_)
-    return;
-  client_->DidDownloadToBlob(std::move(blob));
-}
-
-void WorkerThreadableLoader::DidReceiveResourceTiming(
-    std::unique_ptr<CrossThreadResourceTimingInfoData> timing_data) {
-  DCHECK(worker_global_scope_->IsContextThread());
-  if (!client_)
-    return;
-  scoped_refptr<ResourceTimingInfo> info(
-      ResourceTimingInfo::Adopt(std::move(timing_data)));
-  WorkerGlobalScopePerformance::performance(*worker_global_scope_)
-      ->GenerateAndAddResourceTiming(*info);
-  client_->DidReceiveResourceTiming(*info);
-}
-
-void WorkerThreadableLoader::Trace(blink::Visitor* visitor) {
-  visitor->Trace(worker_global_scope_);
-  ThreadableLoader::Trace(visitor);
-}
-
-void WorkerThreadableLoader::ParentThreadLoaderHolder::CreateAndStart(
-    WorkerThreadableLoader* worker_loader,
-    ThreadableLoadingContext* loading_context,
-    scoped_refptr<base::SingleThreadTaskRunner> worker_loading_task_runner,
-    WorkerThreadLifecycleContext* worker_thread_lifecycle_context,
-    std::unique_ptr<CrossThreadResourceRequestData> request,
-    const ThreadableLoaderOptions& options,
-    const ResourceLoaderOptions& resource_loader_options,
-    scoped_refptr<WaitableEventWithTasks> event_with_tasks) {
-  DCHECK(loading_context->GetExecutionContext()->IsContextThread());
-  DCHECK(event_with_tasks);
-  TaskForwarder* forwarder = new TaskForwarder(std::move(event_with_tasks));
-
-  ParentThreadLoaderHolder* parent_thread_loader_holder =
-      new ParentThreadLoaderHolder(forwarder, worker_thread_lifecycle_context);
-  if (parent_thread_loader_holder
-          ->WasContextDestroyedBeforeObserverCreation()) {
-    // The thread is already terminating.
-    forwarder->Abort();
-    parent_thread_loader_holder->forwarder_ = nullptr;
-    return;
-  }
-  parent_thread_loader_holder->worker_loader_ = worker_loader;
-  forwarder->ForwardTask(
-      FROM_HERE,
-      CrossThreadBind(&WorkerThreadableLoader::DidStart,
-                      WrapCrossThreadPersistent(worker_loader),
-                      WrapCrossThreadPersistent(parent_thread_loader_holder)));
-  parent_thread_loader_holder->Start(*loading_context, std::move(request),
-                                     options, resource_loader_options);
-}
-
-WorkerThreadableLoader::ParentThreadLoaderHolder::~ParentThreadLoaderHolder() {
-  DCHECK(!worker_loader_);
-}
-
-void WorkerThreadableLoader::ParentThreadLoaderHolder::OverrideTimeout(
-    unsigned long timeout_milliseconds) {
-  if (!parent_thread_loader_)
-    return;
-  DCHECK(parent_thread_loader_->GetExecutionContext()->IsContextThread());
-  parent_thread_loader_->OverrideTimeout(timeout_milliseconds);
-}
-
-void WorkerThreadableLoader::ParentThreadLoaderHolder::Cancel() {
-  worker_loader_ = nullptr;
-  if (!parent_thread_loader_)
-    return;
-  DCHECK(parent_thread_loader_->GetExecutionContext()->IsContextThread());
-  parent_thread_loader_->Cancel();
-  parent_thread_loader_ = nullptr;
-}
-
-void WorkerThreadableLoader::ParentThreadLoaderHolder::DidSendData(
-    unsigned long long bytes_sent,
-    unsigned long long total_bytes_to_be_sent) {
-  DCHECK(parent_thread_loader_->GetExecutionContext()->IsContextThread());
-  CrossThreadPersistent<WorkerThreadableLoader> worker_loader =
-      worker_loader_.Get();
-  if (!worker_loader || !forwarder_)
-    return;
-  forwarder_->ForwardTask(
-      FROM_HERE,
-      CrossThreadBind(&WorkerThreadableLoader::DidSendData, worker_loader,
-                      bytes_sent, total_bytes_to_be_sent));
-}
-
-void WorkerThreadableLoader::ParentThreadLoaderHolder::DidReceiveRedirectTo(
-    const KURL& url) {
-  DCHECK(parent_thread_loader_->GetExecutionContext()->IsContextThread());
-  CrossThreadPersistent<WorkerThreadableLoader> worker_loader =
-      worker_loader_.Get();
-  if (!worker_loader || !forwarder_)
-    return;
-  forwarder_->ForwardTask(
-      FROM_HERE, CrossThreadBind(&WorkerThreadableLoader::DidReceiveRedirectTo,
-                                 worker_loader, url));
-}
-
-void WorkerThreadableLoader::ParentThreadLoaderHolder::DidReceiveResponse(
-    unsigned long identifier,
-    const ResourceResponse& response,
-    std::unique_ptr<WebDataConsumerHandle> handle) {
-  DCHECK(parent_thread_loader_->GetExecutionContext()->IsContextThread());
-  CrossThreadPersistent<WorkerThreadableLoader> worker_loader =
-      worker_loader_.Get();
-  if (!worker_loader || !forwarder_)
-    return;
-  forwarder_->ForwardTask(
-      FROM_HERE, CrossThreadBind(&WorkerThreadableLoader::DidReceiveResponse,
-                                 worker_loader, identifier, response,
-                                 WTF::Passed(std::move(handle))));
-}
-
-void WorkerThreadableLoader::ParentThreadLoaderHolder::DidReceiveData(
-    const char* data,
-    unsigned data_length) {
-  DCHECK(parent_thread_loader_->GetExecutionContext()->IsContextThread());
-  CrossThreadPersistent<WorkerThreadableLoader> worker_loader =
-      worker_loader_.Get();
-  if (!worker_loader || !forwarder_)
-    return;
-  forwarder_->ForwardTask(
-      FROM_HERE,
-      CrossThreadBind(
-          &WorkerThreadableLoader::DidReceiveData, worker_loader,
-          WTF::Passed(CreateVectorFromMemoryRegion(data, data_length))));
-}
-
-void WorkerThreadableLoader::ParentThreadLoaderHolder::DidDownloadData(
-    int data_length) {
-  DCHECK(parent_thread_loader_->GetExecutionContext()->IsContextThread());
-  CrossThreadPersistent<WorkerThreadableLoader> worker_loader =
-      worker_loader_.Get();
-  if (!worker_loader || !forwarder_)
-    return;
-  forwarder_->ForwardTask(
-      FROM_HERE, CrossThreadBind(&WorkerThreadableLoader::DidDownloadData,
-                                 worker_loader, data_length));
-}
-
-void WorkerThreadableLoader::ParentThreadLoaderHolder::DidDownloadToBlob(
-    scoped_refptr<BlobDataHandle> blob) {
-  DCHECK(parent_thread_loader_->GetExecutionContext()->IsContextThread());
-  CrossThreadPersistent<WorkerThreadableLoader> worker_loader =
-      worker_loader_.Get();
-  if (!worker_loader || !forwarder_)
-    return;
-  forwarder_->ForwardTask(
-      FROM_HERE, CrossThreadBind(&WorkerThreadableLoader::DidDownloadToBlob,
-                                 worker_loader, std::move(blob)));
-}
-
-void WorkerThreadableLoader::ParentThreadLoaderHolder::DidReceiveCachedMetadata(
-    const char* data,
-    int data_length) {
-  DCHECK(parent_thread_loader_->GetExecutionContext()->IsContextThread());
-  CrossThreadPersistent<WorkerThreadableLoader> worker_loader =
-      worker_loader_.Get();
-  if (!worker_loader || !forwarder_)
-    return;
-  forwarder_->ForwardTask(
-      FROM_HERE,
-      CrossThreadBind(
-          &WorkerThreadableLoader::DidReceiveCachedMetadata, worker_loader,
-          WTF::Passed(CreateVectorFromMemoryRegion(data, data_length))));
-}
-
-void WorkerThreadableLoader::ParentThreadLoaderHolder::DidFinishLoading(
-    unsigned long identifier) {
-  DCHECK(parent_thread_loader_->GetExecutionContext()->IsContextThread());
-  CrossThreadPersistent<WorkerThreadableLoader> worker_loader =
-      worker_loader_.Release();
-  if (!worker_loader || !forwarder_)
-    return;
-  forwarder_->ForwardTaskWithDoneSignal(
-      FROM_HERE, CrossThreadBind(&WorkerThreadableLoader::DidFinishLoading,
-                                 worker_loader, identifier));
-  forwarder_ = nullptr;
-}
-
-void WorkerThreadableLoader::ParentThreadLoaderHolder::DidFail(
-    const ResourceError& error) {
-  DCHECK(parent_thread_loader_->GetExecutionContext()->IsContextThread());
-  CrossThreadPersistent<WorkerThreadableLoader> worker_loader =
-      worker_loader_.Release();
-  if (!worker_loader || !forwarder_)
-    return;
-  forwarder_->ForwardTaskWithDoneSignal(
-      FROM_HERE,
-      CrossThreadBind(&WorkerThreadableLoader::DidFail, worker_loader, error));
-  forwarder_ = nullptr;
-}
-
-void WorkerThreadableLoader::ParentThreadLoaderHolder::DidFailRedirectCheck() {
-  DCHECK(parent_thread_loader_->GetExecutionContext()->IsContextThread());
-  CrossThreadPersistent<WorkerThreadableLoader> worker_loader =
-      worker_loader_.Release();
-  if (!worker_loader || !forwarder_)
-    return;
-  forwarder_->ForwardTaskWithDoneSignal(
-      FROM_HERE, CrossThreadBind(&WorkerThreadableLoader::DidFailRedirectCheck,
-                                 worker_loader));
-  forwarder_ = nullptr;
-}
-
-void WorkerThreadableLoader::ParentThreadLoaderHolder::DidReceiveResourceTiming(
-    const ResourceTimingInfo& info) {
-  DCHECK(parent_thread_loader_->GetExecutionContext()->IsContextThread());
-  CrossThreadPersistent<WorkerThreadableLoader> worker_loader =
-      worker_loader_.Get();
-  if (!worker_loader || !forwarder_)
-    return;
-  forwarder_->ForwardTask(
-      FROM_HERE,
-      CrossThreadBind(&WorkerThreadableLoader::DidReceiveResourceTiming,
-                      worker_loader, info));
-}
-
-void WorkerThreadableLoader::ParentThreadLoaderHolder::ContextDestroyed(
-    WorkerThreadLifecycleContext*) {
-  DCHECK(parent_thread_loader_->GetExecutionContext()->IsContextThread());
-  if (forwarder_) {
-    forwarder_->Abort();
-    forwarder_ = nullptr;
-  }
-  Cancel();
-}
-
-void WorkerThreadableLoader::ParentThreadLoaderHolder::Trace(
-    blink::Visitor* visitor) {
-  visitor->Trace(forwarder_);
-  visitor->Trace(parent_thread_loader_);
-  WorkerThreadLifecycleObserver::Trace(visitor);
-}
-
-WorkerThreadableLoader::ParentThreadLoaderHolder::ParentThreadLoaderHolder(
-    TaskForwarder* forwarder,
-    WorkerThreadLifecycleContext* context)
-    : WorkerThreadLifecycleObserver(context), forwarder_(forwarder) {}
-
-void WorkerThreadableLoader::ParentThreadLoaderHolder::Start(
-    ThreadableLoadingContext& loading_context,
-    std::unique_ptr<CrossThreadResourceRequestData> request,
-    const ThreadableLoaderOptions& options,
-    const ResourceLoaderOptions& original_resource_loader_options) {
-  DCHECK(loading_context.GetExecutionContext()->IsContextThread());
-  ResourceLoaderOptions resource_loader_options =
-      original_resource_loader_options;
-  resource_loader_options.request_initiator_context = kWorkerContext;
-  parent_thread_loader_ = DocumentThreadableLoader::Create(
-      loading_context, this, options, resource_loader_options);
-  parent_thread_loader_->Start(ResourceRequest(request.get()));
-}
-
-}  // namespace blink
diff --git a/third_party/blink/renderer/core/loader/worker_threadable_loader.h b/third_party/blink/renderer/core/loader/worker_threadable_loader.h
deleted file mode 100644
index 25a6b5f..0000000
--- a/third_party/blink/renderer/core/loader/worker_threadable_loader.h
+++ /dev/null
@@ -1,215 +0,0 @@
-/*
- * Copyright (C) 2009 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_WORKER_THREADABLE_LOADER_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_WORKER_THREADABLE_LOADER_H_
-
-#include <memory>
-#include "base/location.h"
-#include "base/memory/scoped_refptr.h"
-#include "base/single_thread_task_runner.h"
-#include "third_party/blink/renderer/core/loader/threadable_loader.h"
-#include "third_party/blink/renderer/core/loader/threadable_loader_client.h"
-#include "third_party/blink/renderer/core/workers/worker_thread.h"
-#include "third_party/blink/renderer/core/workers/worker_thread_lifecycle_observer.h"
-#include "third_party/blink/renderer/platform/heap/handle.h"
-#include "third_party/blink/renderer/platform/waitable_event.h"
-#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
-#include "third_party/blink/renderer/platform/wtf/threading.h"
-#include "third_party/blink/renderer/platform/wtf/vector.h"
-
-namespace blink {
-
-class DocumentThreadableLoader;
-class ThreadableLoadingContext;
-class ResourceError;
-class ResourceRequest;
-class ResourceResponse;
-class WorkerGlobalScope;
-class WorkerThreadLifecycleContext;
-struct CrossThreadResourceRequestData;
-struct CrossThreadResourceTimingInfoData;
-
-// A WorkerThreadableLoader is a ThreadableLoader implementation intended to
-// be used in a WebWorker thread. Because redirect handling doesn't perform CORS
-// checks for sync requests, a WorkerThreadableLoader holds a ThreadableLoader
-// in the parent thread and delegates tasks asynchronously to the loader.
-// The parent thread may be the main thread, or in the case of nested workers,
-// a different worker thread.
-//
-// CTP: CrossThreadPersistent
-// CTWP: CrossThreadWeakPersistent
-//
-// ----------------------------------------------------------------
-//                 +------------------------+
-//       raw ptr   | ThreadableLoaderClient |
-//      +--------> | worker thread          |
-//      |          +------------------------+
-//      |
-// +----+------------------+    CTP  +------------------------+
-// + WorkerThreadableLoader|<--------+ ParentThreadLoaderHolder |
-// | worker thread         +-------->| parent thread            |
-// +-----------------------+   CTWP  +----------------------+-+
-//                                                          |
-//                                 +------------------+     | Member
-//                                 | ThreadableLoader | <---+
-//                                 | parent thread    |
-//                                 +------------------+
-//
-class WorkerThreadableLoader final : public ThreadableLoader {
- public:
-  static void LoadResourceSynchronously(WorkerGlobalScope&,
-                                        const ResourceRequest&,
-                                        ThreadableLoaderClient&,
-                                        const ThreadableLoaderOptions&,
-                                        const ResourceLoaderOptions&);
-  ~WorkerThreadableLoader() override;
-
-  // ThreadableLoader functions
-  void Start(const ResourceRequest&) override;
-  void OverrideTimeout(unsigned long timeout) override;
-  void Cancel() override;
-  void Detach() override;
-
-  void Trace(blink::Visitor*) override;
-
- private:
-  struct TaskWithLocation;
-  class WaitableEventWithTasks;
-  // A TaskForwarder forwards a task to the worker thread.
-  class TaskForwarder final : public GarbageCollectedFinalized<TaskForwarder> {
-   public:
-    explicit TaskForwarder(
-        scoped_refptr<WaitableEventWithTasks> event_with_tasks);
-    ~TaskForwarder() = default;
-    void ForwardTask(const base::Location&, CrossThreadClosure);
-    void ForwardTaskWithDoneSignal(const base::Location&, CrossThreadClosure);
-    void Abort();
-    void Trace(blink::Visitor* visitor) {}
-
-   private:
-    scoped_refptr<WaitableEventWithTasks> event_with_tasks_;
-  };
-
-  // An instance of this class lives in the parent thread. It is a
-  // ThreadableLoaderClient for a DocumentThreadableLoader and forward
-  // notifications to the associated WorkerThreadableLoader living in the
-  // worker thread.
-  class ParentThreadLoaderHolder final
-      : public GarbageCollectedFinalized<ParentThreadLoaderHolder>,
-        public ThreadableLoaderClient,
-        public WorkerThreadLifecycleObserver {
-    USING_GARBAGE_COLLECTED_MIXIN(ParentThreadLoaderHolder);
-    USING_PRE_FINALIZER(ParentThreadLoaderHolder, Cancel);
-
-   public:
-    static void CreateAndStart(WorkerThreadableLoader*,
-                               ThreadableLoadingContext*,
-                               scoped_refptr<base::SingleThreadTaskRunner>,
-                               WorkerThreadLifecycleContext*,
-                               std::unique_ptr<CrossThreadResourceRequestData>,
-                               const ThreadableLoaderOptions&,
-                               const ResourceLoaderOptions&,
-                               scoped_refptr<WaitableEventWithTasks>);
-    ~ParentThreadLoaderHolder() override;
-
-    void OverrideTimeout(unsigned long timeout_millisecond);
-    void Cancel();
-
-    void DidSendData(unsigned long long bytes_sent,
-                     unsigned long long total_bytes_to_be_sent) override;
-    void DidReceiveRedirectTo(const KURL&) override;
-    void DidReceiveResponse(unsigned long identifier,
-                            const ResourceResponse&,
-                            std::unique_ptr<WebDataConsumerHandle>) override;
-    void DidReceiveData(const char*, unsigned data_length) override;
-    void DidDownloadData(int data_length) override;
-    void DidDownloadToBlob(scoped_refptr<BlobDataHandle>) override;
-    void DidReceiveCachedMetadata(const char*, int data_length) override;
-    void DidFinishLoading(unsigned long identifier) override;
-    void DidFail(const ResourceError&) override;
-    void DidFailRedirectCheck() override;
-    void DidReceiveResourceTiming(const ResourceTimingInfo&) override;
-
-    void ContextDestroyed(WorkerThreadLifecycleContext*) override;
-
-    void Trace(blink::Visitor*) override;
-
-   private:
-    ParentThreadLoaderHolder(TaskForwarder*, WorkerThreadLifecycleContext*);
-    void Start(ThreadableLoadingContext&,
-               std::unique_ptr<CrossThreadResourceRequestData>,
-               const ThreadableLoaderOptions&,
-               const ResourceLoaderOptions&);
-
-    Member<TaskForwarder> forwarder_;
-    Member<DocumentThreadableLoader> parent_thread_loader_;
-
-    // |*m_workerLoader| lives in the worker thread.
-    CrossThreadWeakPersistent<WorkerThreadableLoader> worker_loader_;
-  };
-
-  WorkerThreadableLoader(WorkerGlobalScope&,
-                         ThreadableLoaderClient*,
-                         const ThreadableLoaderOptions&,
-                         const ResourceLoaderOptions&);
-  void DidStart(ParentThreadLoaderHolder*);
-
-  void DidSendData(unsigned long long bytes_sent,
-                   unsigned long long total_bytes_to_be_sent);
-  void DidReceiveRedirectTo(const KURL&);
-  void DidReceiveResponse(unsigned long identifier,
-                          std::unique_ptr<CrossThreadResourceResponseData>,
-                          std::unique_ptr<WebDataConsumerHandle>);
-  void DidReceiveData(std::unique_ptr<Vector<char>> data);
-  void DidReceiveCachedMetadata(std::unique_ptr<Vector<char>> data);
-  void DidFinishLoading(unsigned long identifier);
-  void DidFail(const ResourceError&);
-  void DidFailRedirectCheck();
-  void DidDownloadData(int data_length);
-  void DidDownloadToBlob(scoped_refptr<BlobDataHandle>);
-  void DidReceiveResourceTiming(
-      std::unique_ptr<CrossThreadResourceTimingInfoData>);
-
-  Member<WorkerGlobalScope> worker_global_scope_;
-  CrossThreadPersistent<ParentExecutionContextTaskRunners>
-      parent_execution_context_task_runners_;
-  ThreadableLoaderClient* client_;
-
-  ThreadableLoaderOptions threadable_loader_options_;
-  ResourceLoaderOptions resource_loader_options_;
-
-  // |parent_thread_loader_holder_| lives in the parent thread.
-  CrossThreadPersistent<ParentThreadLoaderHolder> parent_thread_loader_holder_;
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_WORKER_THREADABLE_LOADER_H_
diff --git a/third_party/blink/renderer/core/paint/background_image_geometry.cc b/third_party/blink/renderer/core/paint/background_image_geometry.cc
index 1c4c1db2..86da0e1 100644
--- a/third_party/blink/renderer/core/paint/background_image_geometry.cc
+++ b/third_party/blink/renderer/core/paint/background_image_geometry.cc
@@ -795,7 +795,6 @@
       // positioning_area_size in that dimension, so that rounding of floating
       // point approximation to LayoutUnit do not shrink the image to smaller
       // than the positioning_area_size.
-      LayoutSize tile_size;
       if (type == EFillSizeType::kContain) {
         // Snap the dependent dimension to avoid bleeding/blending artifacts
         // at the edge of the image when we paint it.
diff --git a/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.cc b/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.cc
index c900e89..008beae4 100644
--- a/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.cc
+++ b/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.cc
@@ -102,7 +102,6 @@
   if (!layout_object.IsBox())
     return IntRect();
 
-  LayoutRect rect;
   const LayoutBox& box = ToLayoutBox(layout_object);
   return PixelSnappedIntRect(box.BackgroundRect(kBackgroundClipRect));
 }
@@ -1342,6 +1341,7 @@
     IntSize scroll_offset = layout_box.ScrolledContentOffset();
     IntPoint scroll_origin =
         compositing_container->GetScrollableArea()->ScrollOrigin();
+    scroll_origin.Move(-layout_box.OriginAdjustmentForScrollbars());
     scroll_origin.Move(-layout_box.BorderLeft().ToInt(),
                        -layout_box.BorderTop().ToInt());
     graphics_layer_parent_location = -(scroll_origin + scroll_offset);
diff --git a/third_party/blink/renderer/core/paint/ng/ng_text_fragment_painter.cc b/third_party/blink/renderer/core/paint/ng/ng_text_fragment_painter.cc
index 17085010..5dd25cad 100644
--- a/third_party/blink/renderer/core/paint/ng/ng_text_fragment_painter.cc
+++ b/third_party/blink/renderer/core/paint/ng/ng_text_fragment_painter.cc
@@ -275,9 +275,6 @@
   if (!ShouldPaintTextFragment(text_fragment, style))
     return;
 
-  NGPhysicalSize size_;
-  NGPhysicalOffset offset_;
-
   // We round the y-axis to ensure consistent line heights.
   LayoutPoint adjusted_paint_offset =
       LayoutPoint(paint_offset.X(), LayoutUnit(paint_offset.Y().Round()));
diff --git a/third_party/blink/renderer/core/paint/nine_piece_image_grid_test.cc b/third_party/blink/renderer/core/paint/nine_piece_image_grid_test.cc
index 3aaa55a..ca9f272 100644
--- a/third_party/blink/renderer/core/paint/nine_piece_image_grid_test.cc
+++ b/third_party/blink/renderer/core/paint/nine_piece_image_grid_test.cc
@@ -93,7 +93,6 @@
 
   IntSize image_size(100, 100);
   IntRect border_image_area(0, 0, 100, 100);
-  IntRectOutsets border_widths(10, 10, 10, 10);
 
   const struct {
     IntRectOutsets border_widths;
diff --git a/third_party/blink/renderer/core/script/dynamic_module_resolver_test.cc b/third_party/blink/renderer/core/script/dynamic_module_resolver_test.cc
index 555574a..b6e5237 100644
--- a/third_party/blink/renderer/core/script/dynamic_module_resolver_test.cc
+++ b/third_party/blink/renderer/core/script/dynamic_module_resolver_test.cc
@@ -131,7 +131,7 @@
     v8::Local<v8::Value> exported_value =
         module_namespace->Get(context, V8String(isolate, export_name_))
             .ToLocalChecked();
-    captured_value_ = ToCoreString(exported_value->ToString());
+    captured_value_ = ToCoreString(exported_value->ToString(isolate));
 
     return ScriptValue();
   }
@@ -165,11 +165,11 @@
 
     v8::Local<v8::Value> name =
         error_object->Get(context, V8String(isolate, "name")).ToLocalChecked();
-    name_ = ToCoreString(name->ToString());
+    name_ = ToCoreString(name->ToString(isolate));
     v8::Local<v8::Value> message =
         error_object->Get(context, V8String(isolate, "message"))
             .ToLocalChecked();
-    message_ = ToCoreString(message->ToString());
+    message_ = ToCoreString(message->ToString(isolate));
 
     return ScriptValue();
   }
diff --git a/third_party/blink/renderer/core/streams/readable_stream_operations_test.cc b/third_party/blink/renderer/core/streams/readable_stream_operations_test.cc
index 33154781..17abd69 100644
--- a/third_party/blink/renderer/core/streams/readable_stream_operations_test.cc
+++ b/third_party/blink/renderer/core/streams/readable_stream_operations_test.cc
@@ -62,7 +62,7 @@
       is_valid_ = false;
       return;
     }
-    value_ = ToCoreString(value->ToString());
+    value_ = ToCoreString(value->ToString(v.GetScriptState()->GetIsolate()));
   }
 
   bool IsSet() const { return is_set_; }
diff --git a/third_party/blink/renderer/core/testing/dictionary_test.cc b/third_party/blink/renderer/core/testing/dictionary_test.cc
index 0c32750..9eafb7c 100644
--- a/third_party/blink/renderer/core/testing/dictionary_test.cc
+++ b/third_party/blink/renderer/core/testing/dictionary_test.cc
@@ -221,7 +221,7 @@
 
     v8::Local<v8::Value> value;
     if (iterator.GetValue().ToLocal(&value))
-      result.Append(ToCoreString(value->ToString()));
+      result.Append(ToCoreString(value->ToString(script_state->GetIsolate())));
   }
 
   return result.ToString();
diff --git a/third_party/blink/renderer/core/testing/dummy_page_holder.h b/third_party/blink/renderer/core/testing/dummy_page_holder.h
index c9df0aa..edb29e145 100644
--- a/third_party/blink/renderer/core/testing/dummy_page_holder.h
+++ b/third_party/blink/renderer/core/testing/dummy_page_holder.h
@@ -87,7 +87,7 @@
   Persistent<Page> page_;
 
   // The LocalFrame is accessed from worker threads by unit tests
-  // (WorkerThreadableLoaderTest), hence we need to allow cross-thread
+  // (ThreadableLoaderTest), hence we need to allow cross-thread
   // usage of |m_frame|.
   //
   // TODO: rework the tests to not require cross-thread access.
diff --git a/third_party/blink/renderer/core/workers/worker_classic_script_loader.cc b/third_party/blink/renderer/core/workers/worker_classic_script_loader.cc
index 6e803af..29686dd 100644
--- a/third_party/blink/renderer/core/workers/worker_classic_script_loader.cc
+++ b/third_party/blink/renderer/core/workers/worker_classic_script_loader.cc
@@ -52,8 +52,8 @@
 
 WorkerClassicScriptLoader::~WorkerClassicScriptLoader() {
   // If |m_threadableLoader| is still working, we have to cancel it here.
-  // Otherwise didFail() of the deleted |this| will be called from
-  // DocumentThreadableLoader::notifyFinished() when the frame will be
+  // Otherwise DidFail() of the deleted |this| will be called from
+  // ThreadableLoader::NotifyFinished() when the frame will be
   // destroyed.
   if (need_to_cancel_)
     Cancel();
diff --git a/third_party/blink/renderer/core/workers/worker_global_scope.cc b/third_party/blink/renderer/core/workers/worker_global_scope.cc
index e5fe2f5..615a282 100644
--- a/third_party/blink/renderer/core/workers/worker_global_scope.cc
+++ b/third_party/blink/renderer/core/workers/worker_global_scope.cc
@@ -44,7 +44,7 @@
 #include "third_party/blink/renderer/core/inspector/console_message_storage.h"
 #include "third_party/blink/renderer/core/inspector/worker_inspector_controller.h"
 #include "third_party/blink/renderer/core/inspector/worker_thread_debugger.h"
-#include "third_party/blink/renderer/core/loader/worker_threadable_loader.h"
+#include "third_party/blink/renderer/core/loader/threadable_loader.h"
 #include "third_party/blink/renderer/core/origin_trials/origin_trial_context.h"
 #include "third_party/blink/renderer/core/probe/core_probes.h"
 #include "third_party/blink/renderer/core/workers/global_scope_creation_params.h"
diff --git a/third_party/blink/renderer/modules/background_fetch/background_fetch_update_event.idl b/third_party/blink/renderer/modules/background_fetch/background_fetch_update_event.idl
index f4faa5c..42273030d 100644
--- a/third_party/blink/renderer/modules/background_fetch/background_fetch_update_event.idl
+++ b/third_party/blink/renderer/modules/background_fetch/background_fetch_update_event.idl
@@ -10,5 +10,5 @@
     RuntimeEnabled=BackgroundFetch
 ]
 interface BackgroundFetchUpdateEvent : BackgroundFetchSettledEvent {
-    [CallWith=ScriptState] Promise<void> updateUI(BackgroundFetchUpdateUIOptions title);
+    [CallWith=ScriptState] Promise<void> updateUI(BackgroundFetchUpdateUIOptions options);
 };
\ No newline at end of file
diff --git a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_test.cc b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_test.cc
index 208ff8c..eada762 100644
--- a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_test.cc
+++ b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_test.cc
@@ -123,7 +123,7 @@
     CanvasElement().DidDraw();
     CanvasElement().FinalizeFrame();
     // Grabbing an image forces a flush
-    CanvasElement().CopiedImage(kBackBuffer, kPreferAcceleration);
+    CanvasElement().Snapshot(kBackBuffer, kPreferAcceleration);
   }
 
   enum LatencyMode { kNormalLatency, kLowLatency };
diff --git a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc
index d22b722..ab53b3f 100644
--- a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc
+++ b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc
@@ -1543,8 +1543,6 @@
   if (!marked_canvas_dirty_ && !must_clear_now)
     return false;
 
-  if (canvas())
-    canvas()->ClearCopiedImage();
   marked_canvas_dirty_ = false;
 
   if (!Host()->GetOrCreateCanvasResourceProvider(kPreferAcceleration))
@@ -5240,7 +5238,7 @@
     if (!canvas->IsAccelerated() || !CanUseTexImageByGPU(format, type)) {
       TexImageImpl(function_id, target, level, internalformat, xoffset, yoffset,
                    zoffset, format, type,
-                   canvas->CopiedImage(kBackBuffer, kPreferAcceleration).get(),
+                   canvas->Snapshot(kBackBuffer, kPreferAcceleration).get(),
                    WebGLImageConversion::kHtmlDomCanvas, unpack_flip_y_,
                    unpack_premultiply_alpha_, source_sub_rectangle, 1, 0);
       return;
@@ -5271,7 +5269,7 @@
     // textures, and elements of 2D texture arrays.
     TexImageImpl(function_id, target, level, internalformat, xoffset, yoffset,
                  zoffset, format, type,
-                 canvas->CopiedImage(kBackBuffer, kPreferAcceleration).get(),
+                 canvas->Snapshot(kBackBuffer, kPreferAcceleration).get(),
                  WebGLImageConversion::kHtmlDomCanvas, unpack_flip_y_,
                  unpack_premultiply_alpha_, source_sub_rectangle, depth,
                  unpack_image_height);
diff --git a/third_party/blink/renderer/platform/BUILD.gn b/third_party/blink/renderer/platform/BUILD.gn
index 41efb00..916a81f 100644
--- a/third_party/blink/renderer/platform/BUILD.gn
+++ b/third_party/blink/renderer/platform/BUILD.gn
@@ -1164,8 +1164,6 @@
     "lifecycle_observer.h",
     "link_hash.cc",
     "link_hash.h",
-    "long_task_detector.cc",
-    "long_task_detector.h",
     "mac/block_exceptions.h",
     "mac/block_exceptions.mm",
     "mac/color_mac.h",
@@ -1823,7 +1821,6 @@
     "json/json_values_test.cc",
     "layout_unit_test.cc",
     "lifecycle_context_test.cc",
-    "long_task_detector_test.cc",
     "mac/graphics_context_canvas_test.mm",
     "mac/version_util_mac_test.mm",
     "mhtml/mhtml_parser_test.cc",
diff --git a/third_party/blink/renderer/platform/animation/DEPS b/third_party/blink/renderer/platform/animation/DEPS
index 26f742b27..d15d7b3 100644
--- a/third_party/blink/renderer/platform/animation/DEPS
+++ b/third_party/blink/renderer/platform/animation/DEPS
@@ -10,7 +10,6 @@
     "+third_party/blink/renderer/platform/geometry",
     "+third_party/blink/renderer/platform/graphics",
     "+third_party/blink/renderer/platform/heap",
-    "+third_party/blink/renderer/platform/instrumentation",
     "+third_party/blink/renderer/platform/layout_unit.h",
     "+third_party/blink/renderer/platform/platform_export.h",
     "+third_party/blink/renderer/platform/runtime_enabled_features.h",
diff --git a/third_party/blink/renderer/platform/animation/compositor_scroll_offset_animation_curve.cc b/third_party/blink/renderer/platform/animation/compositor_scroll_offset_animation_curve.cc
index 8e727fd6..1b339b18 100644
--- a/third_party/blink/renderer/platform/animation/compositor_scroll_offset_animation_curve.cc
+++ b/third_party/blink/renderer/platform/animation/compositor_scroll_offset_animation_curve.cc
@@ -72,7 +72,7 @@
   return FloatPoint(target.x(), target.y());
 }
 
-void CompositorScrollOffsetAnimationCurve::UpdateTarget(double time,
+void CompositorScrollOffsetAnimationCurve::UpdateTarget(TimeDelta time,
                                                         FloatPoint new_target) {
   curve_->UpdateTarget(time, gfx::ScrollOffset(new_target.X(), new_target.Y()));
 }
diff --git a/third_party/blink/renderer/platform/animation/compositor_scroll_offset_animation_curve.h b/third_party/blink/renderer/platform/animation/compositor_scroll_offset_animation_curve.h
index a4c0291..7b2dec4d 100644
--- a/third_party/blink/renderer/platform/animation/compositor_scroll_offset_animation_curve.h
+++ b/third_party/blink/renderer/platform/animation/compositor_scroll_offset_animation_curve.h
@@ -12,6 +12,7 @@
 #include "third_party/blink/renderer/platform/geometry/float_point.h"
 #include "third_party/blink/renderer/platform/platform_export.h"
 #include "third_party/blink/renderer/platform/wtf/noncopyable.h"
+#include "third_party/blink/renderer/platform/wtf/time.h"
 
 namespace cc {
 class ScrollOffsetAnimationCurve;
@@ -49,7 +50,7 @@
   double Duration() const;
   FloatPoint TargetValue() const;
   void ApplyAdjustment(IntSize);
-  void UpdateTarget(double time, FloatPoint new_target);
+  void UpdateTarget(TimeDelta time, FloatPoint new_target);
 
   // CompositorAnimationCurve implementation.
   std::unique_ptr<cc::AnimationCurve> CloneToAnimationCurve() const override;
diff --git a/third_party/blink/renderer/platform/bindings/DEPS b/third_party/blink/renderer/platform/bindings/DEPS
index f59246c..87cfbf26 100644
--- a/third_party/blink/renderer/platform/bindings/DEPS
+++ b/third_party/blink/renderer/platform/bindings/DEPS
@@ -13,7 +13,6 @@
     "+third_party/blink/renderer/platform/platform_export.h",
     "+third_party/blink/renderer/platform/runtime_enabled_features.h",
     "+third_party/blink/renderer/platform/scheduler",
-    "+third_party/blink/renderer/platform/supplementable.h",
     "+third_party/blink/renderer/platform/testing",
     "+third_party/blink/renderer/platform/weborigin",
     "+third_party/blink/renderer/platform/wtf",
diff --git a/third_party/blink/renderer/platform/bindings/script_wrappable_marking_visitor.cc b/third_party/blink/renderer/platform/bindings/script_wrappable_marking_visitor.cc
index 2ab286e..2f343483 100644
--- a/third_party/blink/renderer/platform/bindings/script_wrappable_marking_visitor.cc
+++ b/third_party/blink/renderer/platform/bindings/script_wrappable_marking_visitor.cc
@@ -19,7 +19,6 @@
 #include "third_party/blink/renderer/platform/heap/heap_page.h"
 #include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h"
 #include "third_party/blink/renderer/platform/scheduler/public/thread_scheduler.h"
-#include "third_party/blink/renderer/platform/supplementable.h"
 #include "third_party/blink/renderer/platform/wtf/time.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/platform/bindings/trace_wrapper_v8_string.cc b/third_party/blink/renderer/platform/bindings/trace_wrapper_v8_string.cc
index af5b491..af72ecc 100644
--- a/third_party/blink/renderer/platform/bindings/trace_wrapper_v8_string.cc
+++ b/third_party/blink/renderer/platform/bindings/trace_wrapper_v8_string.cc
@@ -12,9 +12,10 @@
   DCHECK(isolate);
   v8::HandleScope handle_scope(isolate);
   v8::Local<v8::String> target_string =
-      (string_.IsEmpty()) ? V8String(isolate, string)
-                          : v8::String::Concat(string_.NewLocal(isolate),
-                                               V8String(isolate, string));
+      (string_.IsEmpty())
+          ? V8String(isolate, string)
+          : v8::String::Concat(isolate, string_.NewLocal(isolate),
+                               V8String(isolate, string));
   string_.Set(isolate, target_string);
 }
 
diff --git a/third_party/blink/renderer/platform/blob/DEPS b/third_party/blink/renderer/platform/blob/DEPS
index 24f7593..299df734 100644
--- a/third_party/blink/renderer/platform/blob/DEPS
+++ b/third_party/blink/renderer/platform/blob/DEPS
@@ -7,11 +7,9 @@
 
     # Dependencies.
     "+third_party/blink/renderer/platform/cross_thread_functional.h",
-    "+third_party/blink/renderer/platform/file_metadata.h",
     "+third_party/blink/renderer/platform/histogram.h",
     "+third_party/blink/renderer/platform/instrumentation",
     "+third_party/blink/renderer/platform/platform_export.h",
-    "+third_party/blink/renderer/platform/runtime_enabled_features.h",
     "+third_party/blink/renderer/platform/testing",
     "+third_party/blink/renderer/platform/text/line_ending.h",
     "+third_party/blink/renderer/platform/uuid.h",
diff --git a/third_party/blink/renderer/platform/blob/blob_data.cc b/third_party/blink/renderer/platform/blob/blob_data.cc
index 543574f..678cee04 100644
--- a/third_party/blink/renderer/platform/blob/blob_data.cc
+++ b/third_party/blink/renderer/platform/blob/blob_data.cc
@@ -46,7 +46,6 @@
 #include "third_party/blink/renderer/platform/cross_thread_functional.h"
 #include "third_party/blink/renderer/platform/histogram.h"
 #include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h"
-#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
 #include "third_party/blink/renderer/platform/text/line_ending.h"
 #include "third_party/blink/renderer/platform/uuid.h"
 #include "third_party/blink/renderer/platform/web_task_runner.h"
diff --git a/third_party/blink/renderer/platform/blob/blob_data.h b/third_party/blink/renderer/platform/blob/blob_data.h
index e51d4c05..1afc9f231 100644
--- a/third_party/blink/renderer/platform/blob/blob_data.h
+++ b/third_party/blink/renderer/platform/blob/blob_data.h
@@ -36,7 +36,6 @@
 #include "base/thread_annotations.h"
 #include "third_party/blink/public/mojom/blob/blob.mojom-blink.h"
 #include "third_party/blink/public/mojom/blob/data_element.mojom-blink.h"
-#include "third_party/blink/renderer/platform/file_metadata.h"
 #include "third_party/blink/renderer/platform/weborigin/kurl.h"
 #include "third_party/blink/renderer/platform/wtf/forward.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
diff --git a/third_party/blink/renderer/platform/exported/DEPS b/third_party/blink/renderer/platform/exported/DEPS
index 7e486bb..53f699c 100644
--- a/third_party/blink/renderer/platform/exported/DEPS
+++ b/third_party/blink/renderer/platform/exported/DEPS
@@ -2,6 +2,4 @@
 include_rules = [
     "+net/cookies/canonical_cookie.h",
     "+net/cookies/cookie_constants.h",
-    "+net/cookies/canonical_cookie.h",
-    "+net/cookies/cookie_constants.h",
 ]
diff --git a/third_party/blink/renderer/platform/fonts/DEPS b/third_party/blink/renderer/platform/fonts/DEPS
index 98ddf83..d6d83677 100644
--- a/third_party/blink/renderer/platform/fonts/DEPS
+++ b/third_party/blink/renderer/platform/fonts/DEPS
@@ -9,7 +9,6 @@
     "+third_party/blink/renderer/platform/font_family_names.h",
     "+third_party/blink/renderer/platform/geometry",
     "+third_party/blink/renderer/platform/graphics",
-    "+third_party/blink/renderer/platform/heap/handle.h",
     "+third_party/blink/renderer/platform/heap",
     "+third_party/blink/renderer/platform/histogram.h",
     "+third_party/blink/renderer/platform/instrumentation",
@@ -23,6 +22,5 @@
     "+third_party/blink/renderer/platform/shared_buffer.h",
     "+third_party/blink/renderer/platform/testing",
     "+third_party/blink/renderer/platform/text",
-    "+third_party/blink/renderer/platform/transforms/affine_transform.h",
     "+third_party/blink/renderer/platform/wtf",
 ]
diff --git a/third_party/blink/renderer/platform/fonts/font.cc b/third_party/blink/renderer/platform/fonts/font.cc
index 140c9e34..a67e4393 100644
--- a/third_party/blink/renderer/platform/fonts/font.cc
+++ b/third_party/blink/renderer/platform/fonts/font.cc
@@ -37,13 +37,11 @@
 #include "third_party/blink/renderer/platform/graphics/paint/paint_canvas.h"
 #include "third_party/blink/renderer/platform/graphics/paint/paint_flags.h"
 #include "third_party/blink/renderer/platform/graphics/paint/paint_text_blob.h"
-#include "third_party/blink/renderer/platform/layout_test_support.h"
 #include "third_party/blink/renderer/platform/layout_unit.h"
 #include "third_party/blink/renderer/platform/text/bidi_resolver.h"
 #include "third_party/blink/renderer/platform/text/character.h"
 #include "third_party/blink/renderer/platform/text/text_run.h"
 #include "third_party/blink/renderer/platform/text/text_run_iterator.h"
-#include "third_party/blink/renderer/platform/transforms/affine_transform.h"
 #include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
 #include "third_party/blink/renderer/platform/wtf/text/character_names.h"
 #include "third_party/blink/renderer/platform/wtf/text/unicode.h"
diff --git a/third_party/blink/renderer/platform/fonts/font_custom_platform_data.cc b/third_party/blink/renderer/platform/fonts/font_custom_platform_data.cc
index b02c8ac..b37971a9 100644
--- a/third_party/blink/renderer/platform/fonts/font_custom_platform_data.cc
+++ b/third_party/blink/renderer/platform/fonts/font_custom_platform_data.cc
@@ -40,7 +40,6 @@
 #include "third_party/blink/renderer/platform/fonts/web_font_decoder.h"
 #include "third_party/blink/renderer/platform/fonts/web_font_typeface_factory.h"
 #include "third_party/blink/renderer/platform/graphics/paint/paint_typeface.h"
-#include "third_party/blink/renderer/platform/layout_test_support.h"
 #include "third_party/blink/renderer/platform/shared_buffer.h"
 #include "third_party/skia/include/core/SkStream.h"
 #include "third_party/skia/include/core/SkTypeface.h"
diff --git a/third_party/blink/renderer/platform/fonts/mac/font_family_matcher_mac.mm b/third_party/blink/renderer/platform/fonts/mac/font_family_matcher_mac.mm
index 63b185c..0c0a983 100644
--- a/third_party/blink/renderer/platform/fonts/mac/font_family_matcher_mac.mm
+++ b/third_party/blink/renderer/platform/fonts/mac/font_family_matcher_mac.mm
@@ -33,7 +33,6 @@
 #import <Foundation/Foundation.h>
 #import <math.h>
 #include "third_party/blink/renderer/platform/fonts/font_cache.h"
-#include "third_party/blink/renderer/platform/layout_test_support.h"
 #include "third_party/blink/renderer/platform/mac/version_util_mac.h"
 #import "third_party/blink/renderer/platform/wtf/hash_set.h"
 #import "third_party/blink/renderer/platform/wtf/text/atomic_string_hash.h"
diff --git a/third_party/blink/renderer/platform/geometry/double_point.h b/third_party/blink/renderer/platform/geometry/double_point.h
index 9b25148..ece8413 100644
--- a/third_party/blink/renderer/platform/geometry/double_point.h
+++ b/third_party/blink/renderer/platform/geometry/double_point.h
@@ -20,27 +20,27 @@
   DISALLOW_NEW();
 
  public:
-  DoublePoint() : x_(0), y_(0) {}
-  DoublePoint(double x, double y) : x_(x), y_(y) {}
-  DoublePoint(const IntPoint& p) : x_(p.X()), y_(p.Y()) {}
-  DoublePoint(const FloatPoint& p) : x_(p.X()), y_(p.Y()) {}
+  constexpr DoublePoint() : x_(0), y_(0) {}
+  constexpr DoublePoint(double x, double y) : x_(x), y_(y) {}
+  constexpr DoublePoint(const IntPoint& p) : x_(p.X()), y_(p.Y()) {}
+  constexpr DoublePoint(const FloatPoint& p) : x_(p.X()), y_(p.Y()) {}
   explicit DoublePoint(const LayoutPoint&);
 
-  explicit DoublePoint(const IntSize& size)
+  constexpr explicit DoublePoint(const IntSize& size)
       : x_(size.Width()), y_(size.Height()) {}
 
   explicit DoublePoint(const FloatSize&);
 
-  explicit DoublePoint(const DoubleSize& size)
+  constexpr explicit DoublePoint(const DoubleSize& size)
       : x_(size.Width()), y_(size.Height()) {}
 
-  static DoublePoint Zero() { return DoublePoint(); }
+  static constexpr DoublePoint Zero() { return DoublePoint(); }
 
   DoublePoint ExpandedTo(const DoublePoint&) const;
   DoublePoint ShrunkTo(const DoublePoint&) const;
 
-  double X() const { return x_; }
-  double Y() const { return y_; }
+  constexpr double X() const { return x_; }
+  constexpr double Y() const { return y_; }
   void SetX(double x) { x_ = x; }
   void SetY(double y) { y_ = y; }
 
@@ -74,12 +74,12 @@
   double x_, y_;
 };
 
-inline bool operator==(const DoublePoint& a, const DoublePoint& b) {
+constexpr bool operator==(const DoublePoint& a, const DoublePoint& b) {
   return a.X() == b.X() && a.Y() == b.Y();
 }
 
-inline bool operator!=(const DoublePoint& a, const DoublePoint& b) {
-  return a.X() != b.X() || a.Y() != b.Y();
+constexpr bool operator!=(const DoublePoint& a, const DoublePoint& b) {
+  return !(a == b);
 }
 
 inline DoublePoint& operator+=(DoublePoint& a, const DoubleSize& b) {
@@ -94,19 +94,19 @@
   return a;
 }
 
-inline DoublePoint operator+(const DoublePoint& a, const DoubleSize& b) {
+constexpr DoublePoint operator+(const DoublePoint& a, const DoubleSize& b) {
   return DoublePoint(a.X() + b.Width(), a.Y() + b.Height());
 }
 
-inline DoubleSize operator-(const DoublePoint& a, const DoublePoint& b) {
+constexpr DoubleSize operator-(const DoublePoint& a, const DoublePoint& b) {
   return DoubleSize(a.X() - b.X(), a.Y() - b.Y());
 }
 
-inline DoublePoint operator-(const DoublePoint& a) {
+constexpr DoublePoint operator-(const DoublePoint& a) {
   return DoublePoint(-a.X(), -a.Y());
 }
 
-inline DoublePoint operator-(const DoublePoint& a, const DoubleSize& b) {
+constexpr DoublePoint operator-(const DoublePoint& a, const DoubleSize& b) {
   return DoublePoint(a.X() - b.Width(), a.Y() - b.Height());
 }
 
@@ -122,11 +122,11 @@
   return IntPoint(clampTo<int>(floor(p.X())), clampTo<int>(floor(p.Y())));
 }
 
-inline FloatPoint ToFloatPoint(const DoublePoint& a) {
+constexpr FloatPoint ToFloatPoint(const DoublePoint& a) {
   return FloatPoint(a.X(), a.Y());
 }
 
-inline DoubleSize ToDoubleSize(const DoublePoint& a) {
+constexpr DoubleSize ToDoubleSize(const DoublePoint& a) {
   return DoubleSize(a.X(), a.Y());
 }
 
diff --git a/third_party/blink/renderer/platform/geometry/double_rect.h b/third_party/blink/renderer/platform/geometry/double_rect.h
index c8f8b92e..d0560dae 100644
--- a/third_party/blink/renderer/platform/geometry/double_rect.h
+++ b/third_party/blink/renderer/platform/geometry/double_rect.h
@@ -20,35 +20,35 @@
   STACK_ALLOCATED();
 
  public:
-  DoubleRect() = default;
-  DoubleRect(const DoublePoint& location, const DoubleSize& size)
+  constexpr DoubleRect() = default;
+  constexpr DoubleRect(const DoublePoint& location, const DoubleSize& size)
       : location_(location), size_(size) {}
-  DoubleRect(double x, double y, double width, double height)
+  constexpr DoubleRect(double x, double y, double width, double height)
       : location_(DoublePoint(x, y)), size_(DoubleSize(width, height)) {}
   DoubleRect(const IntRect&);
   DoubleRect(const FloatRect&);
   DoubleRect(const LayoutRect&);
 
-  DoublePoint Location() const { return location_; }
-  DoubleSize Size() const { return size_; }
+  constexpr DoublePoint Location() const { return location_; }
+  constexpr DoubleSize Size() const { return size_; }
 
   void SetLocation(const DoublePoint& location) { location_ = location; }
   void SetSize(const DoubleSize& size) { size_ = size; }
 
-  double X() const { return location_.X(); }
-  double Y() const { return location_.Y(); }
-  double MaxX() const { return X() + Width(); }
-  double MaxY() const { return Y() + Height(); }
-  double Width() const { return size_.Width(); }
-  double Height() const { return size_.Height(); }
+  constexpr double X() const { return location_.X(); }
+  constexpr double Y() const { return location_.Y(); }
+  constexpr double MaxX() const { return X() + Width(); }
+  constexpr double MaxY() const { return Y() + Height(); }
+  constexpr double Width() const { return size_.Width(); }
+  constexpr double Height() const { return size_.Height(); }
 
   void SetX(double x) { location_.SetX(x); }
   void SetY(double y) { location_.SetY(y); }
   void SetWidth(double width) { size_.SetWidth(width); }
   void SetHeight(double height) { size_.SetHeight(height); }
 
-  bool IsEmpty() const { return size_.IsEmpty(); }
-  bool IsZero() const { return size_.IsZero(); }
+  constexpr bool IsEmpty() const { return size_.IsEmpty(); }
+  constexpr bool IsZero() const { return size_.IsZero(); }
 
   void Move(const DoubleSize& delta) { location_ += delta; }
   void Move(double dx, double dy) { location_.Move(dx, dy); }
@@ -56,14 +56,16 @@
     location_.Move(delta.X(), delta.Y());
   }
 
-  DoublePoint MinXMinYCorner() const { return location_; }  // typically topLeft
-  DoublePoint MaxXMinYCorner() const {
+  constexpr DoublePoint MinXMinYCorner() const {
+    return location_;
+  }  // typically topLeft
+  constexpr DoublePoint MaxXMinYCorner() const {
     return DoublePoint(location_.X() + size_.Width(), location_.Y());
   }  // typically topRight
-  DoublePoint MinXMaxYCorner() const {
+  constexpr DoublePoint MinXMaxYCorner() const {
     return DoublePoint(location_.X(), location_.Y() + size_.Height());
   }  // typically bottomLeft
-  DoublePoint MaxXMaxYCorner() const {
+  constexpr DoublePoint MaxXMaxYCorner() const {
     return DoublePoint(location_.X() + size_.Width(),
                        location_.Y() + size_.Height());
   }  // typically bottomRight
diff --git a/third_party/blink/renderer/platform/geometry/double_size.h b/third_party/blink/renderer/platform/geometry/double_size.h
index 917c81c4c..a5ce8eb 100644
--- a/third_party/blink/renderer/platform/geometry/double_size.h
+++ b/third_party/blink/renderer/platform/geometry/double_size.h
@@ -19,20 +19,22 @@
   DISALLOW_NEW();
 
  public:
-  DoubleSize() : width_(0), height_(0) {}
-  DoubleSize(double width, double height) : width_(width), height_(height) {}
-  explicit DoubleSize(const IntSize& p)
+  constexpr DoubleSize() : width_(0), height_(0) {}
+  constexpr DoubleSize(double width, double height)
+      : width_(width), height_(height) {}
+  constexpr explicit DoubleSize(const IntSize& p)
       : width_(p.Width()), height_(p.Height()) {}
-  DoubleSize(const FloatSize& s) : width_(s.Width()), height_(s.Height()) {}
+  constexpr DoubleSize(const FloatSize& s)
+      : width_(s.Width()), height_(s.Height()) {}
   explicit DoubleSize(const LayoutSize&);
 
-  double Width() const { return width_; }
-  double Height() const { return height_; }
+  constexpr double Width() const { return width_; }
+  constexpr double Height() const { return height_; }
 
   void SetWidth(double width) { width_ = width; }
   void SetHeight(double height) { height_ = height; }
 
-  bool IsEmpty() const { return width_ <= 0 || height_ <= 0; }
+  constexpr bool IsEmpty() const { return width_ <= 0 || height_ <= 0; }
 
   bool IsZero() const;
 
@@ -66,19 +68,19 @@
   return a;
 }
 
-inline DoubleSize operator+(const DoubleSize& a, const DoubleSize& b) {
+constexpr DoubleSize operator+(const DoubleSize& a, const DoubleSize& b) {
   return DoubleSize(a.Width() + b.Width(), a.Height() + b.Height());
 }
 
-inline DoubleSize operator-(const DoubleSize& a, const DoubleSize& b) {
+constexpr DoubleSize operator-(const DoubleSize& a, const DoubleSize& b) {
   return DoubleSize(a.Width() - b.Width(), a.Height() - b.Height());
 }
 
-inline bool operator==(const DoubleSize& a, const DoubleSize& b) {
+constexpr bool operator==(const DoubleSize& a, const DoubleSize& b) {
   return a.Width() == b.Width() && a.Height() == b.Height();
 }
 
-inline bool operator!=(const DoubleSize& a, const DoubleSize& b) {
+constexpr bool operator!=(const DoubleSize& a, const DoubleSize& b) {
   return a.Width() != b.Width() || a.Height() != b.Height();
 }
 
@@ -96,7 +98,7 @@
   return IntSize(clampTo<int>(ceil(p.Width())), clampTo<int>(ceil(p.Height())));
 }
 
-inline FloatSize ToFloatSize(const DoubleSize& p) {
+constexpr FloatSize ToFloatSize(const DoubleSize& p) {
   return FloatSize(p.Width(), p.Height());
 }
 
diff --git a/third_party/blink/renderer/platform/geometry/float_box.h b/third_party/blink/renderer/platform/geometry/float_box.h
index 8365088b..24bc3c43 100644
--- a/third_party/blink/renderer/platform/geometry/float_box.h
+++ b/third_party/blink/renderer/platform/geometry/float_box.h
@@ -42,12 +42,18 @@
   DISALLOW_NEW();
 
  public:
-  FloatBox() : x_(0), y_(0), z_(0), width_(0), height_(0), depth_(0) {}
+  constexpr FloatBox()
+      : x_(0), y_(0), z_(0), width_(0), height_(0), depth_(0) {}
 
-  FloatBox(float x, float y, float z, float width, float height, float depth)
+  constexpr FloatBox(float x,
+                     float y,
+                     float z,
+                     float width,
+                     float height,
+                     float depth)
       : x_(x), y_(y), z_(z), width_(width), height_(height), depth_(depth) {}
 
-  FloatBox(const FloatBox& box)
+  constexpr FloatBox(const FloatBox& box)
       : x_(box.X()),
         y_(box.Y()),
         z_(box.Z()),
@@ -102,20 +108,20 @@
     ExpandTo(box);
   }
 
-  bool IsEmpty() const {
+  constexpr bool IsEmpty() const {
     return (width_ <= 0 && height_ <= 0) || (width_ <= 0 && depth_ <= 0) ||
            (height_ <= 0 && depth_ <= 0);
   }
 
-  float Right() const { return x_ + width_; }
-  float Bottom() const { return y_ + height_; }
-  float front() const { return z_ + depth_; }
-  float X() const { return x_; }
-  float Y() const { return y_; }
-  float Z() const { return z_; }
-  float Width() const { return width_; }
-  float Height() const { return height_; }
-  float Depth() const { return depth_; }
+  constexpr float Right() const { return x_ + width_; }
+  constexpr float Bottom() const { return y_ + height_; }
+  constexpr float front() const { return z_ + depth_; }
+  constexpr float X() const { return x_; }
+  constexpr float Y() const { return y_; }
+  constexpr float Z() const { return z_; }
+  constexpr float Width() const { return width_; }
+  constexpr float Height() const { return height_; }
+  constexpr float Depth() const { return depth_; }
 
   String ToString() const;
 
@@ -128,13 +134,13 @@
   float depth_;
 };
 
-inline bool operator==(const FloatBox& a, const FloatBox& b) {
+constexpr bool operator==(const FloatBox& a, const FloatBox& b) {
   return a.X() == b.X() && a.Y() == b.Y() && a.Z() == b.Z() &&
          a.Width() == b.Width() && a.Height() == b.Height() &&
          a.Depth() == b.Depth();
 }
 
-inline bool operator!=(const FloatBox& a, const FloatBox& b) {
+constexpr bool operator!=(const FloatBox& a, const FloatBox& b) {
   return !(a == b);
 }
 
diff --git a/third_party/blink/renderer/platform/geometry/float_point.h b/third_party/blink/renderer/platform/geometry/float_point.h
index e2f0565..6aaa4ef 100644
--- a/third_party/blink/renderer/platform/geometry/float_point.h
+++ b/third_party/blink/renderer/platform/geometry/float_point.h
@@ -62,24 +62,24 @@
   DISALLOW_NEW_EXCEPT_PLACEMENT_NEW();
 
  public:
-  FloatPoint() : x_(0), y_(0) {}
-  FloatPoint(float x, float y) : x_(x), y_(y) {}
+  constexpr FloatPoint() : x_(0), y_(0) {}
+  constexpr FloatPoint(float x, float y) : x_(x), y_(y) {}
   explicit FloatPoint(const IntPoint&);
   explicit FloatPoint(const SkPoint&);
   explicit FloatPoint(const DoublePoint&);
   explicit FloatPoint(const LayoutPoint&);
-  explicit FloatPoint(const FloatSize& size)
+  constexpr explicit FloatPoint(const FloatSize& size)
       : x_(size.Width()), y_(size.Height()) {}
   explicit FloatPoint(const LayoutSize&);
-  explicit FloatPoint(const IntSize& size)
+  constexpr explicit FloatPoint(const IntSize& size)
       : x_(size.Width()), y_(size.Height()) {}
 
-  static FloatPoint Zero() { return FloatPoint(); }
+  static constexpr FloatPoint Zero() { return FloatPoint(); }
 
   static FloatPoint NarrowPrecision(double x, double y);
 
-  float X() const { return x_; }
-  float Y() const { return y_; }
+  constexpr float X() const { return x_; }
+  constexpr float Y() const { return y_; }
 
   void SetX(float x) { x_ = x; }
   void SetY(float y) { y_ = y; }
@@ -159,48 +159,48 @@
   return a;
 }
 
-inline FloatPoint operator+(const FloatPoint& a, const FloatSize& b) {
+constexpr FloatPoint operator+(const FloatPoint& a, const FloatSize& b) {
   return FloatPoint(a.X() + b.Width(), a.Y() + b.Height());
 }
 
-inline FloatPoint operator+(const FloatPoint& a, const IntSize& b) {
+constexpr FloatPoint operator+(const FloatPoint& a, const IntSize& b) {
   return FloatPoint(a.X() + b.Width(), a.Y() + b.Height());
 }
 
-inline FloatPoint operator+(const IntPoint& a, const FloatSize& b) {
+constexpr FloatPoint operator+(const IntPoint& a, const FloatSize& b) {
   return FloatPoint(a.X() + b.Width(), a.Y() + b.Height());
 }
 
-inline FloatPoint operator+(const FloatPoint& a, const FloatPoint& b) {
+constexpr FloatPoint operator+(const FloatPoint& a, const FloatPoint& b) {
   return FloatPoint(a.X() + b.X(), a.Y() + b.Y());
 }
 
-inline FloatPoint operator+(const FloatPoint& a, const IntPoint& b) {
+constexpr FloatPoint operator+(const FloatPoint& a, const IntPoint& b) {
   return FloatPoint(a.X() + b.X(), a.Y() + b.Y());
 }
 
-inline FloatSize operator-(const FloatPoint& a, const FloatPoint& b) {
+constexpr FloatSize operator-(const FloatPoint& a, const FloatPoint& b) {
   return FloatSize(a.X() - b.X(), a.Y() - b.Y());
 }
 
-inline FloatSize operator-(const FloatPoint& a, const IntPoint& b) {
+constexpr FloatSize operator-(const FloatPoint& a, const IntPoint& b) {
   return FloatSize(a.X() - b.X(), a.Y() - b.Y());
 }
 
-inline FloatPoint operator-(const FloatPoint& a, const FloatSize& b) {
+constexpr FloatPoint operator-(const FloatPoint& a, const FloatSize& b) {
   return FloatPoint(a.X() - b.Width(), a.Y() - b.Height());
 }
 
-inline FloatPoint operator-(const FloatPoint& a) {
+constexpr FloatPoint operator-(const FloatPoint& a) {
   return FloatPoint(-a.X(), -a.Y());
 }
 
-inline bool operator==(const FloatPoint& a, const FloatPoint& b) {
+constexpr bool operator==(const FloatPoint& a, const FloatPoint& b) {
   return a.X() == b.X() && a.Y() == b.Y();
 }
 
-inline bool operator!=(const FloatPoint& a, const FloatPoint& b) {
-  return a.X() != b.X() || a.Y() != b.Y();
+constexpr bool operator!=(const FloatPoint& a, const FloatPoint& b) {
+  return !(a == b);
 }
 
 inline float operator*(const FloatPoint& a, const FloatPoint& b) {
diff --git a/third_party/blink/renderer/platform/geometry/float_point_3d.h b/third_party/blink/renderer/platform/geometry/float_point_3d.h
index 6717f3f1..9083de7 100644
--- a/third_party/blink/renderer/platform/geometry/float_point_3d.h
+++ b/third_party/blink/renderer/platform/geometry/float_point_3d.h
@@ -38,21 +38,22 @@
   DISALLOW_NEW();
 
  public:
-  FloatPoint3D() : x_(0), y_(0), z_(0) {}
+  constexpr FloatPoint3D() : x_(0), y_(0), z_(0) {}
 
-  FloatPoint3D(float x, float y, float z) : x_(x), y_(y), z_(z) {}
+  constexpr FloatPoint3D(float x, float y, float z) : x_(x), y_(y), z_(z) {}
 
-  FloatPoint3D(const FloatPoint& p) : x_(p.X()), y_(p.Y()), z_(0) {}
+  constexpr FloatPoint3D(const FloatPoint& p) : x_(p.X()), y_(p.Y()), z_(0) {}
 
-  FloatPoint3D(const FloatPoint3D& p) : x_(p.X()), y_(p.Y()), z_(p.Z()) {}
+  constexpr FloatPoint3D(const FloatPoint3D& p)
+      : x_(p.X()), y_(p.Y()), z_(p.Z()) {}
 
-  float X() const { return x_; }
+  constexpr float X() const { return x_; }
   void SetX(float x) { x_ = x; }
 
-  float Y() const { return y_; }
+  constexpr float Y() const { return y_; }
   void SetY(float y) { y_ = y; }
 
-  float Z() const { return z_; }
+  constexpr float Z() const { return z_; }
   void SetZ(float z) { z_ = z; }
   void Set(float x, float y, float z) {
     x_ = x;
@@ -70,7 +71,7 @@
     z_ *= sz;
   }
 
-  bool IsZero() const { return !x_ && !y_ && !z_; }
+  constexpr bool IsZero() const { return !x_ && !y_ && !z_; }
 
   void Normalize();
 
@@ -128,20 +129,20 @@
   return a;
 }
 
-inline FloatPoint3D operator+(const FloatPoint3D& a, const FloatPoint3D& b) {
+constexpr FloatPoint3D operator+(const FloatPoint3D& a, const FloatPoint3D& b) {
   return FloatPoint3D(a.X() + b.X(), a.Y() + b.Y(), a.Z() + b.Z());
 }
 
-inline FloatPoint3D operator-(const FloatPoint3D& a, const FloatPoint3D& b) {
+constexpr FloatPoint3D operator-(const FloatPoint3D& a, const FloatPoint3D& b) {
   return FloatPoint3D(a.X() - b.X(), a.Y() - b.Y(), a.Z() - b.Z());
 }
 
-inline bool operator==(const FloatPoint3D& a, const FloatPoint3D& b) {
+constexpr bool operator==(const FloatPoint3D& a, const FloatPoint3D& b) {
   return a.X() == b.X() && a.Y() == b.Y() && a.Z() == b.Z();
 }
 
-inline bool operator!=(const FloatPoint3D& a, const FloatPoint3D& b) {
-  return a.X() != b.X() || a.Y() != b.Y() || a.Z() != b.Z();
+constexpr bool operator!=(const FloatPoint3D& a, const FloatPoint3D& b) {
+  return !(a == b);
 }
 
 inline float operator*(const FloatPoint3D& a, const FloatPoint3D& b) {
diff --git a/third_party/blink/renderer/platform/geometry/float_quad.h b/third_party/blink/renderer/platform/geometry/float_quad.h
index 26922ce..a2e632e 100644
--- a/third_party/blink/renderer/platform/geometry/float_quad.h
+++ b/third_party/blink/renderer/platform/geometry/float_quad.h
@@ -47,15 +47,15 @@
   USING_FAST_MALLOC(FloatQuad);
 
  public:
-  FloatQuad() = default;
+  constexpr FloatQuad() = default;
 
-  FloatQuad(const FloatPoint& p1,
-            const FloatPoint& p2,
-            const FloatPoint& p3,
-            const FloatPoint& p4)
+  constexpr FloatQuad(const FloatPoint& p1,
+                      const FloatPoint& p2,
+                      const FloatPoint& p3,
+                      const FloatPoint& p4)
       : p1_(p1), p2_(p2), p3_(p3), p4_(p4) {}
 
-  FloatQuad(const FloatRect& in_rect)
+  constexpr FloatQuad(const FloatRect& in_rect)
       : p1_(in_rect.Location()),
         p2_(in_rect.MaxX(), in_rect.Y()),
         p3_(in_rect.MaxX(), in_rect.MaxY()),
@@ -174,14 +174,13 @@
   return a;
 }
 
-inline bool operator==(const FloatQuad& a, const FloatQuad& b) {
+constexpr bool operator==(const FloatQuad& a, const FloatQuad& b) {
   return a.P1() == b.P1() && a.P2() == b.P2() && a.P3() == b.P3() &&
          a.P4() == b.P4();
 }
 
-inline bool operator!=(const FloatQuad& a, const FloatQuad& b) {
-  return a.P1() != b.P1() || a.P2() != b.P2() || a.P3() != b.P3() ||
-         a.P4() != b.P4();
+constexpr bool operator!=(const FloatQuad& a, const FloatQuad& b) {
+  return !(a == b);
 }
 
 PLATFORM_EXPORT std::ostream& operator<<(std::ostream&, const FloatQuad&);
diff --git a/third_party/blink/renderer/platform/geometry/float_rect.h b/third_party/blink/renderer/platform/geometry/float_rect.h
index 3434286..b677554 100644
--- a/third_party/blink/renderer/platform/geometry/float_rect.h
+++ b/third_party/blink/renderer/platform/geometry/float_rect.h
@@ -62,10 +62,10 @@
  public:
   enum ContainsMode { kInsideOrOnStroke, kInsideButNotOnStroke };
 
-  FloatRect() = default;
-  FloatRect(const FloatPoint& location, const FloatSize& size)
+  constexpr FloatRect() = default;
+  constexpr FloatRect(const FloatPoint& location, const FloatSize& size)
       : location_(location), size_(size) {}
-  FloatRect(float x, float y, float width, float height)
+  constexpr FloatRect(float x, float y, float width, float height)
       : location_(FloatPoint(x, y)), size_(FloatSize(width, height)) {}
   explicit FloatRect(const IntRect&);
   explicit FloatRect(const LayoutRect&);
@@ -76,26 +76,26 @@
                                    double width,
                                    double height);
 
-  FloatPoint Location() const { return location_; }
-  FloatSize Size() const { return size_; }
+  constexpr FloatPoint Location() const { return location_; }
+  constexpr FloatSize Size() const { return size_; }
 
   void SetLocation(const FloatPoint& location) { location_ = location; }
   void SetSize(const FloatSize& size) { size_ = size; }
 
-  float X() const { return location_.X(); }
-  float Y() const { return location_.Y(); }
-  float MaxX() const { return X() + Width(); }
-  float MaxY() const { return Y() + Height(); }
-  float Width() const { return size_.Width(); }
-  float Height() const { return size_.Height(); }
+  constexpr float X() const { return location_.X(); }
+  constexpr float Y() const { return location_.Y(); }
+  constexpr float MaxX() const { return X() + Width(); }
+  constexpr float MaxY() const { return Y() + Height(); }
+  constexpr float Width() const { return size_.Width(); }
+  constexpr float Height() const { return size_.Height(); }
 
   void SetX(float x) { location_.SetX(x); }
   void SetY(float y) { location_.SetY(y); }
   void SetWidth(float width) { size_.SetWidth(width); }
   void SetHeight(float height) { size_.SetHeight(height); }
 
-  bool IsEmpty() const { return size_.IsEmpty(); }
-  bool IsZero() const { return size_.IsZero(); }
+  constexpr bool IsEmpty() const { return size_.IsEmpty(); }
+  constexpr bool IsZero() const { return size_.IsZero(); }
   bool IsExpressibleAsIntRect() const;
 
   FloatPoint Center() const {
@@ -235,18 +235,16 @@
   return a;
 }
 
-inline FloatRect operator+(const FloatRect& a, const FloatRect& b) {
-  FloatRect c = a;
-  c += b;
-  return c;
+constexpr FloatRect operator+(const FloatRect& a, const FloatRect& b) {
+  return FloatRect(a.Location() + b.Location(), a.Size() + b.Size());
 }
 
-inline bool operator==(const FloatRect& a, const FloatRect& b) {
+constexpr bool operator==(const FloatRect& a, const FloatRect& b) {
   return a.Location() == b.Location() && a.Size() == b.Size();
 }
 
-inline bool operator!=(const FloatRect& a, const FloatRect& b) {
-  return a.Location() != b.Location() || a.Size() != b.Size();
+constexpr bool operator!=(const FloatRect& a, const FloatRect& b) {
+  return !(a == b);
 }
 
 // Returns a IntRect containing the given FloatRect.
diff --git a/third_party/blink/renderer/platform/geometry/float_rect_outsets.h b/third_party/blink/renderer/platform/geometry/float_rect_outsets.h
index 6d809ad..ef8c31a9 100644
--- a/third_party/blink/renderer/platform/geometry/float_rect_outsets.h
+++ b/third_party/blink/renderer/platform/geometry/float_rect_outsets.h
@@ -19,15 +19,15 @@
   STACK_ALLOCATED();
 
  public:
-  FloatRectOutsets() : top_(0), right_(0), bottom_(0), left_(0) {}
+  constexpr FloatRectOutsets() : top_(0), right_(0), bottom_(0), left_(0) {}
 
-  FloatRectOutsets(float top, float right, float bottom, float left)
+  constexpr FloatRectOutsets(float top, float right, float bottom, float left)
       : top_(top), right_(right), bottom_(bottom), left_(left) {}
 
-  float Top() const { return top_; }
-  float Right() const { return right_; }
-  float Bottom() const { return bottom_; }
-  float Left() const { return left_; }
+  constexpr float Top() const { return top_; }
+  constexpr float Right() const { return right_; }
+  constexpr float Bottom() const { return bottom_; }
+  constexpr float Left() const { return left_; }
 
   void SetTop(float top) { top_ = top; }
   void SetRight(float right) { right_ = right; }
diff --git a/third_party/blink/renderer/platform/geometry/float_rounded_rect.h b/third_party/blink/renderer/platform/geometry/float_rounded_rect.h
index edd2c53..877f9f6 100644
--- a/third_party/blink/renderer/platform/geometry/float_rounded_rect.h
+++ b/third_party/blink/renderer/platform/geometry/float_rounded_rect.h
@@ -48,17 +48,17 @@
     DISALLOW_NEW();
 
    public:
-    Radii() = default;
-    Radii(const FloatSize& top_left,
-          const FloatSize& top_right,
-          const FloatSize& bottom_left,
-          const FloatSize& bottom_right)
+    constexpr Radii() = default;
+    constexpr Radii(const FloatSize& top_left,
+                    const FloatSize& top_right,
+                    const FloatSize& bottom_left,
+                    const FloatSize& bottom_right)
         : top_left_(top_left),
           top_right_(top_right),
           bottom_left_(bottom_left),
           bottom_right_(bottom_right) {}
 
-    Radii(const FloatRoundedRect::Radii& int_radii)
+    constexpr Radii(const FloatRoundedRect::Radii& int_radii)
         : top_left_(int_radii.TopLeft()),
           top_right_(int_radii.TopRight()),
           bottom_left_(int_radii.BottomLeft()),
@@ -68,12 +68,12 @@
     void SetTopRight(const FloatSize& size) { top_right_ = size; }
     void SetBottomLeft(const FloatSize& size) { bottom_left_ = size; }
     void SetBottomRight(const FloatSize& size) { bottom_right_ = size; }
-    const FloatSize& TopLeft() const { return top_left_; }
-    const FloatSize& TopRight() const { return top_right_; }
-    const FloatSize& BottomLeft() const { return bottom_left_; }
-    const FloatSize& BottomRight() const { return bottom_right_; }
+    constexpr const FloatSize& TopLeft() const { return top_left_; }
+    constexpr const FloatSize& TopRight() const { return top_right_; }
+    constexpr const FloatSize& BottomLeft() const { return bottom_left_; }
+    constexpr const FloatSize& BottomRight() const { return bottom_right_; }
 
-    bool IsZero() const {
+    constexpr bool IsZero() const {
       return top_left_.IsZero() && top_right_.IsZero() &&
              bottom_left_.IsZero() && bottom_right_.IsZero();
     }
@@ -109,7 +109,7 @@
     FloatSize bottom_right_;
   };
 
-  FloatRoundedRect() = default;
+  constexpr FloatRoundedRect() = default;
   explicit FloatRoundedRect(const FloatRect&, const Radii& = Radii());
   explicit FloatRoundedRect(const IntRect&, const Radii& = Radii());
   FloatRoundedRect(float x, float y, float width, float height);
@@ -119,10 +119,10 @@
                    const FloatSize& bottom_left,
                    const FloatSize& bottom_right);
 
-  const FloatRect& Rect() const { return rect_; }
-  const Radii& GetRadii() const { return radii_; }
-  bool IsRounded() const { return !radii_.IsZero(); }
-  bool IsEmpty() const { return rect_.IsEmpty(); }
+  constexpr const FloatRect& Rect() const { return rect_; }
+  constexpr const Radii& GetRadii() const { return radii_; }
+  constexpr bool IsRounded() const { return !radii_.IsZero(); }
+  constexpr bool IsEmpty() const { return rect_.IsEmpty(); }
 
   void SetRect(const FloatRect& rect) { rect_ = rect; }
   void SetRadii(const Radii& radii) { radii_ = radii; }
@@ -141,19 +141,19 @@
   // Returns a quickly computed rect enclosed by the rounded rect.
   FloatRect RadiusCenterRect() const;
 
-  FloatRect TopLeftCorner() const {
+  constexpr FloatRect TopLeftCorner() const {
     return FloatRect(rect_.X(), rect_.Y(), radii_.TopLeft().Width(),
                      radii_.TopLeft().Height());
   }
-  FloatRect TopRightCorner() const {
+  constexpr FloatRect TopRightCorner() const {
     return FloatRect(rect_.MaxX() - radii_.TopRight().Width(), rect_.Y(),
                      radii_.TopRight().Width(), radii_.TopRight().Height());
   }
-  FloatRect BottomLeftCorner() const {
+  constexpr FloatRect BottomLeftCorner() const {
     return FloatRect(rect_.X(), rect_.MaxY() - radii_.BottomLeft().Height(),
                      radii_.BottomLeft().Width(), radii_.BottomLeft().Height());
   }
-  FloatRect BottomRightCorner() const {
+  constexpr FloatRect BottomRightCorner() const {
     return FloatRect(rect_.MaxX() - radii_.BottomRight().Width(),
                      rect_.MaxY() - radii_.BottomRight().Height(),
                      radii_.BottomRight().Width(),
@@ -218,22 +218,24 @@
   return rrect;
 }
 
-inline bool operator==(const FloatRoundedRect::Radii& a,
-                       const FloatRoundedRect::Radii& b) {
+constexpr bool operator==(const FloatRoundedRect::Radii& a,
+                          const FloatRoundedRect::Radii& b) {
   return a.TopLeft() == b.TopLeft() && a.TopRight() == b.TopRight() &&
          a.BottomLeft() == b.BottomLeft() && a.BottomRight() == b.BottomRight();
 }
 
-inline bool operator!=(const FloatRoundedRect::Radii& a,
-                       const FloatRoundedRect::Radii& b) {
+constexpr bool operator!=(const FloatRoundedRect::Radii& a,
+                          const FloatRoundedRect::Radii& b) {
   return !(a == b);
 }
 
-inline bool operator==(const FloatRoundedRect& a, const FloatRoundedRect& b) {
+constexpr bool operator==(const FloatRoundedRect& a,
+                          const FloatRoundedRect& b) {
   return a.Rect() == b.Rect() && a.GetRadii() == b.GetRadii();
 }
 
-inline bool operator!=(const FloatRoundedRect& a, const FloatRoundedRect& b) {
+constexpr bool operator!=(const FloatRoundedRect& a,
+                          const FloatRoundedRect& b) {
   return !(a == b);
 }
 
diff --git a/third_party/blink/renderer/platform/geometry/float_size.h b/third_party/blink/renderer/platform/geometry/float_size.h
index faf4827..d8e53d6 100644
--- a/third_party/blink/renderer/platform/geometry/float_size.h
+++ b/third_party/blink/renderer/platform/geometry/float_size.h
@@ -34,6 +34,7 @@
 #include "third_party/blink/renderer/platform/geometry/int_point.h"
 #include "third_party/blink/renderer/platform/wtf/allocator.h"
 #include "third_party/blink/renderer/platform/wtf/forward.h"
+#include "third_party/blink/renderer/platform/wtf/math_extras.h"
 
 #if defined(OS_MACOSX)
 typedef struct CGSize CGSize;
@@ -59,8 +60,9 @@
   DISALLOW_NEW();
 
  public:
-  FloatSize() : width_(0), height_(0) {}
-  FloatSize(float width, float height) : width_(width), height_(height) {}
+  constexpr FloatSize() : width_(0), height_(0) {}
+  constexpr FloatSize(float width, float height)
+      : width_(width), height_(height) {}
   explicit FloatSize(const IntSize& size)
       : width_(size.Width()), height_(size.Height()) {}
   FloatSize(const SkSize&);
@@ -68,13 +70,13 @@
 
   static FloatSize NarrowPrecision(double width, double height);
 
-  float Width() const { return width_; }
-  float Height() const { return height_; }
+  constexpr float Width() const { return width_; }
+  constexpr float Height() const { return height_; }
 
   void SetWidth(float width) { width_ = width; }
   void SetHeight(float height) { height_ = height; }
 
-  bool IsEmpty() const { return width_ <= 0 || height_ <= 0; }
+  constexpr bool IsEmpty() const { return width_ <= 0 || height_ <= 0; }
   bool IsZero() const {
     return fabs(width_) < std::numeric_limits<float>::epsilon() &&
            fabs(height_) < std::numeric_limits<float>::epsilon();
@@ -153,38 +155,38 @@
   return a;
 }
 
-inline FloatSize& operator-=(FloatSize& a, const FloatSize& b) {
+constexpr FloatSize& operator-=(FloatSize& a, const FloatSize& b) {
   a.SetWidth(a.Width() - b.Width());
   a.SetHeight(a.Height() - b.Height());
   return a;
 }
 
-inline FloatSize operator+(const FloatSize& a, const FloatSize& b) {
+constexpr FloatSize operator+(const FloatSize& a, const FloatSize& b) {
   return FloatSize(a.Width() + b.Width(), a.Height() + b.Height());
 }
 
-inline FloatSize operator-(const FloatSize& a, const FloatSize& b) {
+constexpr FloatSize operator-(const FloatSize& a, const FloatSize& b) {
   return FloatSize(a.Width() - b.Width(), a.Height() - b.Height());
 }
 
-inline FloatSize operator-(const FloatSize& size) {
+constexpr FloatSize operator-(const FloatSize& size) {
   return FloatSize(-size.Width(), -size.Height());
 }
 
-inline FloatSize operator*(const FloatSize& a, const float b) {
+constexpr FloatSize operator*(const FloatSize& a, const float b) {
   return FloatSize(a.Width() * b, a.Height() * b);
 }
 
-inline FloatSize operator*(const float a, const FloatSize& b) {
+constexpr FloatSize operator*(const float a, const FloatSize& b) {
   return FloatSize(a * b.Width(), a * b.Height());
 }
 
-inline bool operator==(const FloatSize& a, const FloatSize& b) {
+constexpr bool operator==(const FloatSize& a, const FloatSize& b) {
   return a.Width() == b.Width() && a.Height() == b.Height();
 }
 
-inline bool operator!=(const FloatSize& a, const FloatSize& b) {
-  return a.Width() != b.Width() || a.Height() != b.Height();
+constexpr bool operator!=(const FloatSize& a, const FloatSize& b) {
+  return !(a == b);
 }
 
 inline IntSize RoundedIntSize(const FloatSize& p) {
diff --git a/third_party/blink/renderer/platform/geometry/int_point.h b/third_party/blink/renderer/platform/geometry/int_point.h
index 95b7daf..5da33140 100644
--- a/third_party/blink/renderer/platform/geometry/int_point.h
+++ b/third_party/blink/renderer/platform/geometry/int_point.h
@@ -54,15 +54,15 @@
   USING_FAST_MALLOC(IntPoint);
 
  public:
-  IntPoint() : x_(0), y_(0) {}
-  IntPoint(int x, int y) : x_(x), y_(y) {}
+  constexpr IntPoint() : x_(0), y_(0) {}
+  constexpr IntPoint(int x, int y) : x_(x), y_(y) {}
   explicit IntPoint(const IntSize& size)
       : x_(size.Width()), y_(size.Height()) {}
 
   static IntPoint Zero() { return IntPoint(); }
 
-  int X() const { return x_; }
-  int Y() const { return y_; }
+  constexpr int X() const { return x_; }
+  constexpr int Y() const { return y_; }
 
   void SetX(int x) { x_ = x; }
   void SetY(int y) { y_ = y; }
@@ -126,32 +126,32 @@
   return a;
 }
 
-inline IntPoint operator+(const IntPoint& a, const IntSize& b) {
+constexpr IntPoint operator+(const IntPoint& a, const IntSize& b) {
   return IntPoint(a.X() + b.Width(), a.Y() + b.Height());
 }
 
-inline IntPoint operator+(const IntPoint& a, const IntPoint& b) {
+constexpr IntPoint operator+(const IntPoint& a, const IntPoint& b) {
   return IntPoint(a.X() + b.X(), a.Y() + b.Y());
 }
 
-inline IntSize operator-(const IntPoint& a, const IntPoint& b) {
+constexpr IntSize operator-(const IntPoint& a, const IntPoint& b) {
   return IntSize(a.X() - b.X(), a.Y() - b.Y());
 }
 
-inline IntPoint operator-(const IntPoint& a, const IntSize& b) {
+constexpr IntPoint operator-(const IntPoint& a, const IntSize& b) {
   return IntPoint(a.X() - b.Width(), a.Y() - b.Height());
 }
 
-inline IntPoint operator-(const IntPoint& point) {
+constexpr IntPoint operator-(const IntPoint& point) {
   return IntPoint(-point.X(), -point.Y());
 }
 
-inline bool operator==(const IntPoint& a, const IntPoint& b) {
+constexpr bool operator==(const IntPoint& a, const IntPoint& b) {
   return a.X() == b.X() && a.Y() == b.Y();
 }
 
-inline bool operator!=(const IntPoint& a, const IntPoint& b) {
-  return a.X() != b.X() || a.Y() != b.Y();
+constexpr bool operator!=(const IntPoint& a, const IntPoint& b) {
+  return !(a == b);
 }
 
 inline IntSize ToIntSize(const IntPoint& a) {
diff --git a/third_party/blink/renderer/platform/geometry/int_rect.h b/third_party/blink/renderer/platform/geometry/int_rect.h
index e9d86bf8..6d07e19 100644
--- a/third_party/blink/renderer/platform/geometry/int_rect.h
+++ b/third_party/blink/renderer/platform/geometry/int_rect.h
@@ -58,38 +58,38 @@
   USING_FAST_MALLOC(IntRect);
 
  public:
-  IntRect() = default;
-  IntRect(const IntPoint& location, const IntSize& size)
+  constexpr IntRect() = default;
+  constexpr IntRect(const IntPoint& location, const IntSize& size)
       : location_(location), size_(size) {}
-  IntRect(int x, int y, int width, int height)
+  constexpr IntRect(int x, int y, int width, int height)
       : location_(IntPoint(x, y)), size_(IntSize(width, height)) {}
 
   // Use EnclosingIntRect(), EnclosedIntRect(), RoundedIntRect(),
   // PixelSnappedIntRect(), etc. instead.
-  explicit IntRect(const FloatRect&) = delete;
-  explicit IntRect(const LayoutRect&) = delete;
+  constexpr explicit IntRect(const FloatRect&) = delete;
+  constexpr explicit IntRect(const LayoutRect&) = delete;
 
   explicit IntRect(const gfx::Rect& rect);
 
-  IntPoint Location() const { return location_; }
-  IntSize Size() const { return size_; }
+  constexpr IntPoint Location() const { return location_; }
+  constexpr IntSize Size() const { return size_; }
 
   void SetLocation(const IntPoint& location) { location_ = location; }
   void SetSize(const IntSize& size) { size_ = size; }
 
-  int X() const { return location_.X(); }
-  int Y() const { return location_.Y(); }
-  int MaxX() const { return X() + Width(); }
-  int MaxY() const { return Y() + Height(); }
-  int Width() const { return size_.Width(); }
-  int Height() const { return size_.Height(); }
+  constexpr int X() const { return location_.X(); }
+  constexpr int Y() const { return location_.Y(); }
+  constexpr int MaxX() const { return X() + Width(); }
+  constexpr int MaxY() const { return Y() + Height(); }
+  constexpr int Width() const { return size_.Width(); }
+  constexpr int Height() const { return size_.Height(); }
 
   void SetX(int x) { location_.SetX(x); }
   void SetY(int y) { location_.SetY(y); }
   void SetWidth(int width) { size_.SetWidth(width); }
   void SetHeight(int height) { size_.SetHeight(height); }
 
-  bool IsEmpty() const { return size_.IsEmpty(); }
+  constexpr bool IsEmpty() const { return size_.IsEmpty(); }
 
   // NOTE: The result is rounded to integer values, and thus may be not the
   // exact center point.
@@ -120,14 +120,16 @@
   void ShiftYEdgeTo(int);
   void ShiftMaxYEdgeTo(int);
 
-  IntPoint MinXMinYCorner() const { return location_; }  // typically topLeft
-  IntPoint MaxXMinYCorner() const {
+  constexpr IntPoint MinXMinYCorner() const {
+    return location_;
+  }  // typically topLeft
+  constexpr IntPoint MaxXMinYCorner() const {
     return IntPoint(location_.X() + size_.Width(), location_.Y());
   }  // typically topRight
-  IntPoint MinXMaxYCorner() const {
+  constexpr IntPoint MinXMaxYCorner() const {
     return IntPoint(location_.X(), location_.Y() + size_.Height());
   }  // typically bottomLeft
-  IntPoint MaxXMaxYCorner() const {
+  constexpr IntPoint MaxXMaxYCorner() const {
     return IntPoint(location_.X() + size_.Width(),
                     location_.Y() + size_.Height());
   }  // typically bottomRight
@@ -218,17 +220,17 @@
 
 PLATFORM_EXPORT IntRect UnionRectEvenIfEmpty(const Vector<IntRect>&);
 
-inline IntRect SaturatedRect(const IntRect& r) {
+constexpr IntRect SaturatedRect(const IntRect& r) {
   return IntRect(r.X(), r.Y(), ClampAdd(r.X(), r.Width()) - r.X(),
                  ClampAdd(r.Y(), r.Height()) - r.Y());
 }
 
-inline bool operator==(const IntRect& a, const IntRect& b) {
+constexpr bool operator==(const IntRect& a, const IntRect& b) {
   return a.Location() == b.Location() && a.Size() == b.Size();
 }
 
-inline bool operator!=(const IntRect& a, const IntRect& b) {
-  return a.Location() != b.Location() || a.Size() != b.Size();
+constexpr bool operator!=(const IntRect& a, const IntRect& b) {
+  return !(a == b);
 }
 
 PLATFORM_EXPORT std::ostream& operator<<(std::ostream&, const IntRect&);
diff --git a/third_party/blink/renderer/platform/geometry/int_rect_outsets.h b/third_party/blink/renderer/platform/geometry/int_rect_outsets.h
index a5e4689..30ccf48 100644
--- a/third_party/blink/renderer/platform/geometry/int_rect_outsets.h
+++ b/third_party/blink/renderer/platform/geometry/int_rect_outsets.h
@@ -44,22 +44,24 @@
   DISALLOW_NEW();
 
  public:
-  IntRectOutsets() : top_(0), right_(0), bottom_(0), left_(0) {}
+  constexpr IntRectOutsets() : top_(0), right_(0), bottom_(0), left_(0) {}
 
-  IntRectOutsets(int top, int right, int bottom, int left)
+  constexpr IntRectOutsets(int top, int right, int bottom, int left)
       : top_(top), right_(right), bottom_(bottom), left_(left) {}
 
-  int Top() const { return top_; }
-  int Right() const { return right_; }
-  int Bottom() const { return bottom_; }
-  int Left() const { return left_; }
+  constexpr int Top() const { return top_; }
+  constexpr int Right() const { return right_; }
+  constexpr int Bottom() const { return bottom_; }
+  constexpr int Left() const { return left_; }
 
   void SetTop(int top) { top_ = top; }
   void SetRight(int right) { right_ = right; }
   void SetBottom(int bottom) { bottom_ = bottom; }
   void SetLeft(int left) { left_ = left; }
 
-  bool IsZero() const { return !Left() && !Right() && !Top() && !Bottom(); }
+  constexpr bool IsZero() const {
+    return !Left() && !Right() && !Top() && !Bottom();
+  }
 
  private:
   int top_;
diff --git a/third_party/blink/renderer/platform/geometry/int_size.h b/third_party/blink/renderer/platform/geometry/int_size.h
index ca7913e..a67d575 100644
--- a/third_party/blink/renderer/platform/geometry/int_size.h
+++ b/third_party/blink/renderer/platform/geometry/int_size.h
@@ -53,18 +53,18 @@
   DISALLOW_NEW_EXCEPT_PLACEMENT_NEW();
 
  public:
-  IntSize() : width_(0), height_(0) {}
-  IntSize(int width, int height) : width_(width), height_(height) {}
+  constexpr IntSize() : width_(0), height_(0) {}
+  constexpr IntSize(int width, int height) : width_(width), height_(height) {}
   explicit IntSize(const gfx::Size&);
 
-  int Width() const { return width_; }
-  int Height() const { return height_; }
+  constexpr int Width() const { return width_; }
+  constexpr int Height() const { return height_; }
 
   void SetWidth(int width) { width_ = width; }
   void SetHeight(int height) { height_ = height; }
 
-  bool IsEmpty() const { return width_ <= 0 || height_ <= 0; }
-  bool IsZero() const { return !width_ && !height_; }
+  constexpr bool IsEmpty() const { return width_ <= 0 || height_ <= 0; }
+  constexpr bool IsZero() const { return !width_ && !height_; }
 
   float AspectRatio() const {
     return static_cast<float>(width_) / static_cast<float>(height_);
diff --git a/third_party/blink/renderer/platform/geometry/layout_point.h b/third_party/blink/renderer/platform/geometry/layout_point.h
index 10726fb7..2f3c1be 100644
--- a/third_party/blink/renderer/platform/geometry/layout_point.h
+++ b/third_party/blink/renderer/platform/geometry/layout_point.h
@@ -44,21 +44,21 @@
   DISALLOW_NEW();
 
  public:
-  LayoutPoint() = default;
-  LayoutPoint(LayoutUnit x, LayoutUnit y) : x_(x), y_(y) {}
+  constexpr LayoutPoint() = default;
+  constexpr LayoutPoint(LayoutUnit x, LayoutUnit y) : x_(x), y_(y) {}
   LayoutPoint(int x, int y) : x_(LayoutUnit(x)), y_(LayoutUnit(y)) {}
   LayoutPoint(const IntPoint& point) : x_(point.X()), y_(point.Y()) {}
   explicit LayoutPoint(const FloatPoint& point)
       : x_(point.X()), y_(point.Y()) {}
   explicit LayoutPoint(const DoublePoint& point)
       : x_(point.X()), y_(point.Y()) {}
-  explicit LayoutPoint(const LayoutSize& size)
+  constexpr explicit LayoutPoint(const LayoutSize& size)
       : x_(size.Width()), y_(size.Height()) {}
 
-  static LayoutPoint Zero() { return LayoutPoint(); }
+  static constexpr LayoutPoint Zero() { return LayoutPoint(); }
 
-  LayoutUnit X() const { return x_; }
-  LayoutUnit Y() const { return y_; }
+  constexpr LayoutUnit X() const { return x_; }
+  constexpr LayoutUnit Y() const { return y_; }
 
   void SetX(LayoutUnit x) { x_ = x; }
   void SetY(LayoutUnit y) { y_ = y; }
@@ -148,23 +148,24 @@
   return LayoutPoint(-point.X(), -point.Y());
 }
 
-ALWAYS_INLINE bool operator==(const LayoutPoint& a, const LayoutPoint& b) {
+constexpr ALWAYS_INLINE bool operator==(const LayoutPoint& a,
+                                        const LayoutPoint& b) {
   return a.X() == b.X() && a.Y() == b.Y();
 }
 
-inline bool operator!=(const LayoutPoint& a, const LayoutPoint& b) {
-  return a.X() != b.X() || a.Y() != b.Y();
+constexpr bool operator!=(const LayoutPoint& a, const LayoutPoint& b) {
+  return !(a == b);
 }
 
-inline LayoutPoint ToPoint(const LayoutSize& size) {
+constexpr inline LayoutPoint ToPoint(const LayoutSize& size) {
   return LayoutPoint(size.Width(), size.Height());
 }
 
-inline LayoutPoint ToLayoutPoint(const LayoutSize& p) {
+constexpr inline LayoutPoint ToLayoutPoint(const LayoutSize& p) {
   return LayoutPoint(p.Width(), p.Height());
 }
 
-inline LayoutSize ToSize(const LayoutPoint& a) {
+constexpr inline LayoutSize ToSize(const LayoutPoint& a) {
   return LayoutSize(a.X(), a.Y());
 }
 
diff --git a/third_party/blink/renderer/platform/geometry/layout_rect.h b/third_party/blink/renderer/platform/geometry/layout_rect.h
index e05e54d..c3dd51b 100644
--- a/third_party/blink/renderer/platform/geometry/layout_rect.h
+++ b/third_party/blink/renderer/platform/geometry/layout_rect.h
@@ -48,10 +48,13 @@
   DISALLOW_NEW_EXCEPT_PLACEMENT_NEW();
 
  public:
-  LayoutRect() = default;
-  LayoutRect(const LayoutPoint& location, const LayoutSize& size)
+  constexpr LayoutRect() = default;
+  constexpr LayoutRect(const LayoutPoint& location, const LayoutSize& size)
       : location_(location), size_(size) {}
-  LayoutRect(LayoutUnit x, LayoutUnit y, LayoutUnit width, LayoutUnit height)
+  constexpr LayoutRect(LayoutUnit x,
+                       LayoutUnit y,
+                       LayoutUnit width,
+                       LayoutUnit height)
       : location_(LayoutPoint(x, y)), size_(LayoutSize(width, height)) {}
   LayoutRect(int x, int y, int width, int height)
       : location_(LayoutPoint(x, y)), size_(LayoutSize(width, height)) {}
@@ -68,8 +71,8 @@
   explicit LayoutRect(const FloatRect&);
   explicit LayoutRect(const DoubleRect&);
 
-  LayoutPoint Location() const { return location_; }
-  LayoutSize Size() const { return size_; }
+  constexpr LayoutPoint Location() const { return location_; }
+  constexpr LayoutSize Size() const { return size_; }
 
   IntPoint PixelSnappedLocation() const { return RoundedIntPoint(location_); }
   IntSize PixelSnappedSize() const {
@@ -80,12 +83,12 @@
   void SetLocation(const LayoutPoint& location) { location_ = location; }
   void SetSize(const LayoutSize& size) { size_ = size; }
 
-  ALWAYS_INLINE LayoutUnit X() const { return location_.X(); }
-  ALWAYS_INLINE LayoutUnit Y() const { return location_.Y(); }
+  constexpr ALWAYS_INLINE LayoutUnit X() const { return location_.X(); }
+  constexpr ALWAYS_INLINE LayoutUnit Y() const { return location_.Y(); }
   ALWAYS_INLINE LayoutUnit MaxX() const { return X() + Width(); }
   ALWAYS_INLINE LayoutUnit MaxY() const { return Y() + Height(); }
-  LayoutUnit Width() const { return size_.Width(); }
-  LayoutUnit Height() const { return size_.Height(); }
+  constexpr LayoutUnit Width() const { return size_.Width(); }
+  constexpr LayoutUnit Height() const { return size_.Height(); }
 
   int PixelSnappedWidth() const { return SnapSizeToPixel(Width(), X()); }
   int PixelSnappedHeight() const { return SnapSizeToPixel(Height(), Y()); }
@@ -95,7 +98,7 @@
   void SetWidth(LayoutUnit width) { size_.SetWidth(width); }
   void SetHeight(LayoutUnit height) { size_.SetHeight(height); }
 
-  ALWAYS_INLINE bool IsEmpty() const { return size_.IsEmpty(); }
+  constexpr ALWAYS_INLINE bool IsEmpty() const { return size_.IsEmpty(); }
 
   // NOTE: The result is rounded to integer values, and thus may be not the
   // exact center point.
@@ -169,7 +172,9 @@
     SetHeight((Height() + delta).ClampNegativeToZero());
   }
 
-  LayoutPoint MinXMinYCorner() const { return location_; }  // typically topLeft
+  constexpr LayoutPoint MinXMinYCorner() const {
+    return location_;
+  }  // typically topLeft
   LayoutPoint MaxXMinYCorner() const {
     return LayoutPoint(location_.X() + size_.Width(), location_.Y());
   }  // typically topRight
@@ -277,12 +282,13 @@
 
 PLATFORM_EXPORT LayoutRect UnionRectEvenIfEmpty(const Vector<LayoutRect>&);
 
-ALWAYS_INLINE bool operator==(const LayoutRect& a, const LayoutRect& b) {
+constexpr ALWAYS_INLINE bool operator==(const LayoutRect& a,
+                                        const LayoutRect& b) {
   return a.Location() == b.Location() && a.Size() == b.Size();
 }
 
-inline bool operator!=(const LayoutRect& a, const LayoutRect& b) {
-  return a.Location() != b.Location() || a.Size() != b.Size();
+constexpr bool operator!=(const LayoutRect& a, const LayoutRect& b) {
+  return !(a == b);
 }
 
 inline IntRect PixelSnappedIntRect(const LayoutRect& rect) {
diff --git a/third_party/blink/renderer/platform/geometry/layout_rect_outsets.h b/third_party/blink/renderer/platform/geometry/layout_rect_outsets.h
index 6086d2c..9f9c4bc 100644
--- a/third_party/blink/renderer/platform/geometry/layout_rect_outsets.h
+++ b/third_party/blink/renderer/platform/geometry/layout_rect_outsets.h
@@ -49,11 +49,11 @@
   DISALLOW_NEW();
 
  public:
-  LayoutRectOutsets() = default;
-  LayoutRectOutsets(LayoutUnit top,
-                    LayoutUnit right,
-                    LayoutUnit bottom,
-                    LayoutUnit left)
+  constexpr LayoutRectOutsets() = default;
+  constexpr LayoutRectOutsets(LayoutUnit top,
+                              LayoutUnit right,
+                              LayoutUnit bottom,
+                              LayoutUnit left)
       : top_(top), right_(right), bottom_(bottom), left_(left) {}
   LayoutRectOutsets(int top, int right, int bottom, int left)
       : top_(LayoutUnit(top)),
@@ -73,10 +73,10 @@
         bottom_(LayoutUnit(outsets.Bottom())),
         left_(LayoutUnit(outsets.Left())) {}
 
-  LayoutUnit Top() const { return top_; }
-  LayoutUnit Right() const { return right_; }
-  LayoutUnit Bottom() const { return bottom_; }
-  LayoutUnit Left() const { return left_; }
+  constexpr LayoutUnit Top() const { return top_; }
+  constexpr LayoutUnit Right() const { return right_; }
+  constexpr LayoutUnit Bottom() const { return bottom_; }
+  constexpr LayoutUnit Left() const { return left_; }
 
   void SetTop(LayoutUnit value) { top_ = value; }
   void SetRight(LayoutUnit value) { right_ = value; }
@@ -84,7 +84,9 @@
   void SetLeft(LayoutUnit value) { left_ = value; }
 
   LayoutSize Size() const { return LayoutSize(left_ + right_, top_ + bottom_); }
-  bool IsZero() const { return !top_ && !right_ && !bottom_ && !left_; }
+  constexpr bool IsZero() const {
+    return !top_ && !right_ && !bottom_ && !left_;
+  }
 
   void ClampNegativeToZero();
 
@@ -92,7 +94,7 @@
 
   void FlipHorizontally() { std::swap(left_, right_); }
 
-  bool operator==(const LayoutRectOutsets other) const {
+  constexpr bool operator==(const LayoutRectOutsets other) const {
     return Top() == other.Top() && Right() == other.Right() &&
            Bottom() == other.Bottom() && Left() == other.Left();
   }
diff --git a/third_party/blink/renderer/platform/geometry/layout_size.h b/third_party/blink/renderer/platform/geometry/layout_size.h
index 280ee87..e506382 100644
--- a/third_party/blink/renderer/platform/geometry/layout_size.h
+++ b/third_party/blink/renderer/platform/geometry/layout_size.h
@@ -48,10 +48,10 @@
   DISALLOW_NEW();
 
  public:
-  LayoutSize() = default;
+  constexpr LayoutSize() = default;
   explicit LayoutSize(const IntSize& size)
       : width_(size.Width()), height_(size.Height()) {}
-  LayoutSize(LayoutUnit width, LayoutUnit height)
+  constexpr LayoutSize(LayoutUnit width, LayoutUnit height)
       : width_(width), height_(height) {}
   LayoutSize(int width, int height)
       : width_(LayoutUnit(width)), height_(LayoutUnit(height)) {}
@@ -63,16 +63,16 @@
   explicit LayoutSize(const DoubleSize& size)
       : width_(size.Width()), height_(size.Height()) {}
 
-  LayoutUnit Width() const { return width_; }
-  LayoutUnit Height() const { return height_; }
+  constexpr LayoutUnit Width() const { return width_; }
+  constexpr LayoutUnit Height() const { return height_; }
 
   void SetWidth(LayoutUnit width) { width_ = width; }
   void SetHeight(LayoutUnit height) { height_ = height; }
 
-  bool IsEmpty() const {
+  constexpr bool IsEmpty() const {
     return width_.RawValue() <= 0 || height_.RawValue() <= 0;
   }
-  bool IsZero() const { return !width_ && !height_; }
+  constexpr bool IsZero() const { return !width_ && !height_; }
 
   float AspectRatio() const { return width_.ToFloat() / height_.ToFloat(); }
 
@@ -194,7 +194,7 @@
   return LayoutSize(a.Width() * scale, a.Height() * scale);
 }
 
-inline bool operator==(const LayoutSize& a, const LayoutSize& b) {
+constexpr bool operator==(const LayoutSize& a, const LayoutSize& b) {
   return a.Width() == b.Width() && a.Height() == b.Height();
 }
 
@@ -202,15 +202,15 @@
   return a.Width() == b.Width() && a.Height() == b.Height();
 }
 
-inline bool operator!=(const LayoutSize& a, const LayoutSize& b) {
-  return a.Width() != b.Width() || a.Height() != b.Height();
+constexpr bool operator!=(const LayoutSize& a, const LayoutSize& b) {
+  return !(a == b);
 }
 
 inline bool operator!=(const LayoutSize& a, const IntSize& b) {
   return a.Width() != b.Width() || a.Height() != b.Height();
 }
 
-inline FloatPoint operator+(const FloatPoint& a, const LayoutSize& b) {
+constexpr FloatPoint operator+(const FloatPoint& a, const LayoutSize& b) {
   return FloatPoint(a.X() + b.Width(), a.Y() + b.Height());
 }
 
diff --git a/third_party/blink/renderer/platform/geometry/layout_size_test.cc b/third_party/blink/renderer/platform/geometry/layout_size_test.cc
index 2eb9e1ff..8c5e394 100644
--- a/third_party/blink/renderer/platform/geometry/layout_size_test.cc
+++ b/third_party/blink/renderer/platform/geometry/layout_size_test.cc
@@ -18,7 +18,6 @@
                 .FitToAspectRatio(aspect_ratio, kAspectRatioFitShrink)
                 .ToString());
 
-  LayoutSize size(1000, 2000);
   EXPECT_EQ("1000x1000",
             LayoutSize(1000, 2000)
                 .FitToAspectRatio(aspect_ratio, kAspectRatioFitShrink)
diff --git a/third_party/blink/renderer/platform/graphics/DEPS b/third_party/blink/renderer/platform/graphics/DEPS
index 0ef1e730..af03830e 100644
--- a/third_party/blink/renderer/platform/graphics/DEPS
+++ b/third_party/blink/renderer/platform/graphics/DEPS
@@ -3,18 +3,10 @@
     "-third_party/blink/renderer/platform",
 
     # Module.
-    "+third_party/blink/renderer/platform/geometry",
+    "+third_party/blink/renderer/platform/graphics",
 
     # Dependencies.
-    "+base/bind.h",
-    "+base/callback.h",
-    "+base/compiler_specific.h",
-    "+base/message_loop",
-    "+base/task_runner.h",
-    "+base/task_runner_util.h",
     "+base/threading/sequenced_task_runner_handle.h",
-    "+base/threading/thread.h",
-    "+base/threading/thread_checker.h",
     "+cc",
     "+components/viz/client",
     "+components/viz/common",
@@ -32,19 +24,18 @@
     "+services/ui/public/cpp/gpu/context_provider_command_buffer.h",
     "+services/viz/public/interfaces",
     "+third_party/blink/renderer/platform/animation",
-    "+third_party/blink/renderer/platform/bindings/runtime_call_stats.h",
     "+third_party/blink/renderer/platform/bindings",
     "+third_party/blink/renderer/platform/cpu/mips/common_macros_msa.h",
     "+third_party/blink/renderer/platform/cross_thread_functional.h",
     "+third_party/blink/renderer/platform/drag_image.h",
     "+third_party/blink/renderer/platform/fonts",
-    "+third_party/blink/renderer/platform/graphics",
+    "+third_party/blink/renderer/platform/geometry",
     "+third_party/blink/renderer/platform/heap",
     "+third_party/blink/renderer/platform/histogram.h",
     "+third_party/blink/renderer/platform/image-decoders",
     "+third_party/blink/renderer/platform/image-encoders",
     "+third_party/blink/renderer/platform/instrumentation",
-    "+third_party/blink/renderer/platform/json/json_values.h",
+    "+third_party/blink/renderer/platform/json",
     "+third_party/blink/renderer/platform/length.h",
     "+third_party/blink/renderer/platform/mojo/mojo_helper.h",
     "+third_party/blink/renderer/platform/network/mime/mime_type_registry.h",
diff --git a/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer_test.cc b/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer_test.cc
index e67ef2b..c5f07c6 100644
--- a/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer_test.cc
+++ b/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer_test.cc
@@ -218,8 +218,6 @@
   viz::TransferableResource resource3;
   std::unique_ptr<viz::SingleReleaseCallback> release_callback3;
 
-  IntSize initial_size(kInitialWidth, kInitialHeight);
-
   // Produce resources.
   EXPECT_FALSE(drawing_buffer_->MarkContentsChanged());
   drawing_buffer_->ClearFramebuffers(GL_STENCIL_BUFFER_BIT);
@@ -521,7 +519,6 @@
   // Request a resource. An image should already be created. Everything works
   // as expected.
   EXPECT_CALL(*gl_, BindTexImage2DMock(_)).Times(1);
-  IntSize initial_size(kInitialWidth, kInitialHeight);
   EXPECT_FALSE(drawing_buffer_->MarkContentsChanged());
   EXPECT_TRUE(drawing_buffer_->PrepareTransferableResource(nullptr, &resource1,
                                                            &release_callback1));
diff --git a/third_party/blink/renderer/platform/graphics/video_frame_submitter.cc b/third_party/blink/renderer/platform/graphics/video_frame_submitter.cc
index d74303c..2cf41c55f 100644
--- a/third_party/blink/renderer/platform/graphics/video_frame_submitter.cc
+++ b/third_party/blink/renderer/platform/graphics/video_frame_submitter.cc
@@ -6,7 +6,6 @@
 
 #include <vector>
 
-#include "base/task_runner.h"
 #include "base/threading/sequenced_task_runner_handle.h"
 #include "base/trace_event/trace_event.h"
 #include "cc/paint/filter_operations.h"
diff --git a/third_party/blink/renderer/platform/graphics/video_frame_submitter_test.cc b/third_party/blink/renderer/platform/graphics/video_frame_submitter_test.cc
index 5ad6fed..0eb72f7 100644
--- a/third_party/blink/renderer/platform/graphics/video_frame_submitter_test.cc
+++ b/third_party/blink/renderer/platform/graphics/video_frame_submitter_test.cc
@@ -6,10 +6,8 @@
 
 #include <memory>
 #include "base/memory/ptr_util.h"
-#include "base/task_runner_util.h"
 #include "base/test/scoped_task_environment.h"
 #include "base/test/simple_test_tick_clock.h"
-#include "base/threading/thread.h"
 #include "cc/layers/video_frame_provider.h"
 #include "cc/test/layer_test_common.h"
 #include "cc/trees/layer_tree_settings.h"
diff --git a/third_party/blink/renderer/platform/heap/DEPS b/third_party/blink/renderer/platform/heap/DEPS
index c5aa107..5409786d 100644
--- a/third_party/blink/renderer/platform/heap/DEPS
+++ b/third_party/blink/renderer/platform/heap/DEPS
@@ -8,9 +8,7 @@
     # Dependencies.
     "+base/atomicops.h",
     "+base/bits.h",
-    "+base/compiler_specific.h",
     "+base/synchronization/lock.h",
-    "+base/sys_info.h",
 
     "+third_party/blink/renderer/platform/bindings",
     "+third_party/blink/renderer/platform/cross_thread_functional.h",
diff --git a/third_party/blink/renderer/platform/image-encoders/DEPS b/third_party/blink/renderer/platform/image-encoders/DEPS
index 5acbcd3..b78682ac 100644
--- a/third_party/blink/renderer/platform/image-encoders/DEPS
+++ b/third_party/blink/renderer/platform/image-encoders/DEPS
@@ -6,13 +6,8 @@
     "+third_party/blink/renderer/platform/image-encoders",
 
     # Dependencies.
-    "+third_party/blink/renderer/platform/geometry",
-    "+third_party/blink/renderer/platform/graphics",
     "+third_party/blink/renderer/platform/histogram.h",
-    "+third_party/blink/renderer/platform/instrumentation",
     "+third_party/blink/renderer/platform/network/mime/mime_type_registry.h",
     "+third_party/blink/renderer/platform/platform_export.h",
-    "+third_party/blink/renderer/platform/shared_buffer.h",
-    "+third_party/blink/renderer/platform/testing",
     "+third_party/blink/renderer/platform/wtf",
 ]
diff --git a/third_party/blink/renderer/platform/instrumentation/DEPS b/third_party/blink/renderer/platform/instrumentation/DEPS
index 20dc455..7f6cc453 100644
--- a/third_party/blink/renderer/platform/instrumentation/DEPS
+++ b/third_party/blink/renderer/platform/instrumentation/DEPS
@@ -8,10 +8,8 @@
     # Dependencies.
     "+base/gtest_prod_util.h",
     "+base/json",
-    "+base/macros.h",
     "+base/memory",
     "+base/strings",
-    "+base/time",
     "+base/trace_event",
     "+base/values.h",
     "+skia/ext/skia_trace_memory_dump_impl.h",
diff --git a/third_party/blink/renderer/platform/layout_unit.h b/third_party/blink/renderer/platform/layout_unit.h
index 7865a05..8521847d 100644
--- a/third_party/blink/renderer/platform/layout_unit.h
+++ b/third_party/blink/renderer/platform/layout_unit.h
@@ -58,13 +58,13 @@
 
 // TODO(thakis): Remove these two lines once http://llvm.org/PR26504 is resolved
 class PLATFORM_EXPORT LayoutUnit;
-inline bool operator<(const LayoutUnit&, const LayoutUnit&);
+constexpr inline bool operator<(const LayoutUnit&, const LayoutUnit&);
 
 class LayoutUnit {
   DISALLOW_NEW_EXCEPT_PLACEMENT_NEW();
 
  public:
-  LayoutUnit() : value_(0) {}
+  constexpr LayoutUnit() : value_(0) {}
   explicit LayoutUnit(int value) { SetValue(value); }
   explicit LayoutUnit(unsigned short value) { SetValue(value); }
   explicit LayoutUnit(unsigned value) { SetValue(value); }
@@ -107,11 +107,11 @@
     return v;
   }
 
-  int ToInt() const { return value_ / kFixedPointDenominator; }
-  float ToFloat() const {
+  constexpr int ToInt() const { return value_ / kFixedPointDenominator; }
+  constexpr float ToFloat() const {
     return static_cast<float>(value_) / kFixedPointDenominator;
   }
-  double ToDouble() const {
+  constexpr double ToDouble() const {
     return static_cast<double>(value_) / kFixedPointDenominator;
   }
   unsigned ToUnsigned() const {
@@ -126,16 +126,16 @@
   operator int() const = delete;
   operator unsigned() const = delete;
 
-  operator double() const { return ToDouble(); }
-  operator float() const { return ToFloat(); }
-  operator bool() const { return value_; }
+  constexpr operator double() const { return ToDouble(); }
+  constexpr operator float() const { return ToFloat(); }
+  constexpr operator bool() const { return value_; }
 
   LayoutUnit operator++(int) {
     value_ = ClampAdd(value_, kFixedPointDenominator);
     return *this;
   }
 
-  inline int RawValue() const { return value_; }
+  constexpr int RawValue() const { return value_; }
   inline void SetRawValue(int value) { value_ = value; }
   void SetRawValue(long long value) {
     REPORT_OVERFLOW(value > std::numeric_limits<int>::min() &&
@@ -252,11 +252,11 @@
   int value_;
 };
 
-inline bool operator<=(const LayoutUnit& a, const LayoutUnit& b) {
+constexpr bool operator<=(const LayoutUnit& a, const LayoutUnit& b) {
   return a.RawValue() <= b.RawValue();
 }
 
-inline bool operator<=(const LayoutUnit& a, float b) {
+constexpr bool operator<=(const LayoutUnit& a, float b) {
   return a.ToFloat() <= b;
 }
 
@@ -264,7 +264,7 @@
   return a <= LayoutUnit(b);
 }
 
-inline bool operator<=(const float a, const LayoutUnit& b) {
+constexpr bool operator<=(const float a, const LayoutUnit& b) {
   return a <= b.ToFloat();
 }
 
@@ -272,7 +272,7 @@
   return LayoutUnit(a) <= b;
 }
 
-inline bool operator>=(const LayoutUnit& a, const LayoutUnit& b) {
+constexpr bool operator>=(const LayoutUnit& a, const LayoutUnit& b) {
   return a.RawValue() >= b.RawValue();
 }
 
@@ -280,11 +280,11 @@
   return a >= LayoutUnit(b);
 }
 
-inline bool operator>=(const float a, const LayoutUnit& b) {
+constexpr bool operator>=(const float a, const LayoutUnit& b) {
   return a >= b.ToFloat();
 }
 
-inline bool operator>=(const LayoutUnit& a, float b) {
+constexpr bool operator>=(const LayoutUnit& a, float b) {
   return a.ToFloat() >= b;
 }
 
@@ -292,7 +292,7 @@
   return LayoutUnit(a) >= b;
 }
 
-inline bool operator<(const LayoutUnit& a, const LayoutUnit& b) {
+constexpr bool operator<(const LayoutUnit& a, const LayoutUnit& b) {
   return a.RawValue() < b.RawValue();
 }
 
@@ -300,11 +300,11 @@
   return a < LayoutUnit(b);
 }
 
-inline bool operator<(const LayoutUnit& a, float b) {
+constexpr bool operator<(const LayoutUnit& a, float b) {
   return a.ToFloat() < b;
 }
 
-inline bool operator<(const LayoutUnit& a, double b) {
+constexpr bool operator<(const LayoutUnit& a, double b) {
   return a.ToDouble() < b;
 }
 
@@ -312,19 +312,19 @@
   return LayoutUnit(a) < b;
 }
 
-inline bool operator<(const float a, const LayoutUnit& b) {
+constexpr bool operator<(const float a, const LayoutUnit& b) {
   return a < b.ToFloat();
 }
 
-inline bool operator>(const LayoutUnit& a, const LayoutUnit& b) {
+constexpr bool operator>(const LayoutUnit& a, const LayoutUnit& b) {
   return a.RawValue() > b.RawValue();
 }
 
-inline bool operator>(const LayoutUnit& a, double b) {
+constexpr bool operator>(const LayoutUnit& a, double b) {
   return a.ToDouble() > b;
 }
 
-inline bool operator>(const LayoutUnit& a, float b) {
+constexpr bool operator>(const LayoutUnit& a, float b) {
   return a.ToFloat() > b;
 }
 
@@ -336,15 +336,15 @@
   return LayoutUnit(a) > b;
 }
 
-inline bool operator>(const float a, const LayoutUnit& b) {
+constexpr bool operator>(const float a, const LayoutUnit& b) {
   return a > b.ToFloat();
 }
 
-inline bool operator>(const double a, const LayoutUnit& b) {
+constexpr bool operator>(const double a, const LayoutUnit& b) {
   return a > b.ToDouble();
 }
 
-inline bool operator!=(const LayoutUnit& a, const LayoutUnit& b) {
+constexpr bool operator!=(const LayoutUnit& a, const LayoutUnit& b) {
   return a.RawValue() != b.RawValue();
 }
 
@@ -360,7 +360,7 @@
   return a != LayoutUnit(b);
 }
 
-inline bool operator==(const LayoutUnit& a, const LayoutUnit& b) {
+constexpr bool operator==(const LayoutUnit& a, const LayoutUnit& b) {
   return a.RawValue() == b.RawValue();
 }
 
@@ -372,11 +372,11 @@
   return LayoutUnit(a) == b;
 }
 
-inline bool operator==(const LayoutUnit& a, float b) {
+constexpr bool operator==(const LayoutUnit& a, float b) {
   return a.ToFloat() == b;
 }
 
-inline bool operator==(const float a, const LayoutUnit& b) {
+constexpr bool operator==(const float a, const LayoutUnit& b) {
   return a == b.ToFloat();
 }
 
@@ -452,11 +452,11 @@
   return LayoutUnit(a) * b;
 }
 
-inline float operator*(const float a, const LayoutUnit& b) {
+constexpr float operator*(const float a, const LayoutUnit& b) {
   return a * b.ToFloat();
 }
 
-inline double operator*(const double a, const LayoutUnit& b) {
+constexpr double operator*(const double a, const LayoutUnit& b) {
   return a * b.ToDouble();
 }
 
@@ -468,11 +468,11 @@
   return return_val;
 }
 
-inline float operator/(const LayoutUnit& a, float b) {
+constexpr float operator/(const LayoutUnit& a, float b) {
   return a.ToFloat() / b;
 }
 
-inline double operator/(const LayoutUnit& a, double b) {
+constexpr double operator/(const LayoutUnit& a, double b) {
   return a.ToDouble() / b;
 }
 
@@ -496,11 +496,11 @@
   return a / LayoutUnit(b);
 }
 
-inline float operator/(const float a, const LayoutUnit& b) {
+constexpr float operator/(const float a, const LayoutUnit& b) {
   return a / b.ToFloat();
 }
 
-inline double operator/(const double a, const LayoutUnit& b) {
+constexpr double operator/(const double a, const LayoutUnit& b) {
   return a / b.ToDouble();
 }
 
@@ -546,11 +546,11 @@
   return LayoutUnit(a) + b;
 }
 
-inline float operator+(const float a, const LayoutUnit& b) {
+constexpr inline float operator+(const float a, const LayoutUnit& b) {
   return a + b.ToFloat();
 }
 
-inline double operator+(const double a, const LayoutUnit& b) {
+constexpr inline double operator+(const double a, const LayoutUnit& b) {
   return a + b.ToDouble();
 }
 
@@ -568,11 +568,11 @@
   return a - LayoutUnit(b);
 }
 
-inline float operator-(const LayoutUnit& a, float b) {
+constexpr float operator-(const LayoutUnit& a, float b) {
   return a.ToFloat() - b;
 }
 
-inline double operator-(const LayoutUnit& a, double b) {
+constexpr double operator-(const LayoutUnit& a, double b) {
   return a.ToDouble() - b;
 }
 
@@ -580,7 +580,7 @@
   return LayoutUnit(a) - b;
 }
 
-inline float operator-(const float a, const LayoutUnit& b) {
+constexpr float operator-(const float a, const LayoutUnit& b) {
   return a - b.ToFloat();
 }
 
diff --git a/third_party/blink/renderer/platform/loader/fetch/raw_resource.cc b/third_party/blink/renderer/platform/loader/fetch/raw_resource.cc
index 2280203..d43122fc6 100644
--- a/third_party/blink/renderer/platform/loader/fetch/raw_resource.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/raw_resource.cc
@@ -205,7 +205,7 @@
   if (response.WasFallbackRequiredByServiceWorker()) {
     // The ServiceWorker asked us to re-fetch the request. This resource must
     // not be reused.
-    // Note: This logic is needed here because DocumentThreadableLoader handles
+    // Note: This logic is needed here because ThreadableLoader handles
     // CORS independently from ResourceLoader. Fix it.
     if (IsMainThread())
       GetMemoryCache()->Remove(this);
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource.cc b/third_party/blink/renderer/platform/loader/fetch/resource.cc
index 97a1597..83a2c12e 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/resource.cc
@@ -873,19 +873,19 @@
     case network::mojom::FetchRequestMode::kCORS:
     case network::mojom::FetchRequestMode::kSameOrigin:
     case network::mojom::FetchRequestMode::kCORSWithForcedPreflight:
-      // We have two separate CORS handling logics in DocumentThreadableLoader
+      // We have two separate CORS handling logics in ThreadableLoader
       // and ResourceLoader and sharing resources is difficult when they are
       // handled differently.
       if (options_.cors_handling_by_resource_fetcher !=
           new_options.cors_handling_by_resource_fetcher) {
-        // If the existing one is handled in DocumentThreadableLoader and the
+        // If the existing one is handled in ThreadableLoader and the
         // new one is handled in ResourceLoader, reusing the existing one will
         // lead to CORS violations.
         if (!options_.cors_handling_by_resource_fetcher)
           return false;
 
         // Otherwise (i.e., if the existing one is handled in ResourceLoader
-        // and the new one is handled in DocumentThreadableLoader), reusing
+        // and the new one is handled in ThreadableLoader), reusing
         // the existing one will lead to double check which is harmless.
       }
       break;
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc
index a3a04d9..5ab5d282 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc
@@ -654,7 +654,7 @@
           : SecurityViolationReportingPolicy::kReport;
 
   // Note that resource_request.GetRedirectStatus() may return kFollowedRedirect
-  // here since e.g. DocumentThreadableLoader may create a new Resource from
+  // here since e.g. ThreadableLoader may create a new Resource from
   // a ResourceRequest that originates from the ResourceRequest passed to
   // the redirect handling callback.
 
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_loader_options.h b/third_party/blink/renderer/platform/loader/fetch/resource_loader_options.h
index 0907407..3617906 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_loader_options.h
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_loader_options.h
@@ -59,7 +59,7 @@
   kRequestAsynchronously
 };
 
-// Used by the DocumentThreadableLoader to turn off part of the CORS handling
+// Used by the ThreadableLoader to turn off part of the CORS handling
 // logic in the ResourceFetcher to use its own CORS handling logic.
 enum CORSHandlingByResourceFetcher {
   kDisableCORSHandlingByResourceFetcher,
@@ -102,7 +102,7 @@
 
   // When set to kDisableCORSHandlingByResourceFetcher, the ResourceFetcher
   // suppresses part of its CORS handling logic.
-  // Used by DocumentThreadableLoader which does CORS handling by itself.
+  // Used by ThreadableLoader which does CORS handling by itself.
   CORSHandlingByResourceFetcher cors_handling_by_resource_fetcher;
 
   // Corresponds to the CORS flag in the Fetch spec.
diff --git a/third_party/blink/renderer/platform/scheduler/base/proto/sequence_manager_test_description.proto b/third_party/blink/renderer/platform/scheduler/base/proto/sequence_manager_test_description.proto
index d39f2bb8..a3a67b1c 100644
--- a/third_party/blink/renderer/platform/scheduler/base/proto/sequence_manager_test_description.proto
+++ b/third_party/blink/renderer/platform/scheduler/base/proto/sequence_manager_test_description.proto
@@ -21,7 +21,7 @@
   }
 
   message Action {
-    // NEXT ID = 9
+    // NEXT ID = 11
 
     optional uint64 action_id = 1;
 
@@ -33,6 +33,8 @@
       ShutdownTaskQueueAction shutdown_task_queue = 6;
       CancelTaskAction cancel_task = 7;
       CreateQueueVoterAction create_queue_voter = 8;
+      InsertFenceAction insert_fence = 9;
+      RemoveFenceAction remove_fence = 10;
     }
   }
 
@@ -42,7 +44,7 @@
     // Only needed for testing the fuzzer processor.
     optional uint64 task_id = 1;
 
-    optional uint64 duration_ms = 2;
+    optional uint32 duration_ms = 2;
 
     // If not set, then this is a no-op task.
     repeated Action actions = 3;
@@ -66,7 +68,7 @@
     optional Task task = 2;
 
     // Delay parameter passed to TaskQueue::PostDelayedTask.
-    optional uint64 delay_ms = 3;
+    optional uint32 delay_ms = 3;
   }
 
   // Describes the grammar of TaskQueue::SetQueuePriority.
@@ -121,5 +123,27 @@
     optional uint64 task_id = 1;
   }
 
+  message InsertFenceAction {
+    // NEXT ID = 3
+    enum FencePosition {
+      NOW = 0;
+      BEGINNING_OF_TIME = 1;
+    }
+
+    optional FencePosition position = 1 [default = NOW];
+
+    // Used to identify the |task_queue_id|'s oldest available queue to
+    // insert the fence to (modulo the number of available queues).
+    optional uint64 task_queue_id = 2;
+  }
+
+  message RemoveFenceAction {
+    // NEXT ID = 2
+
+    // Used to identify the |task_queue_id|'s oldest available queue to remove a
+    // fence from, if one exists (modulo the number of available queues).
+    optional uint64 task_queue_id = 2;
+  }
+
   repeated Action initial_actions = 1;
 }
diff --git a/third_party/blink/renderer/platform/scheduler/base/sequence_manager_fuzzer_processor.cc b/third_party/blink/renderer/platform/scheduler/base/sequence_manager_fuzzer_processor.cc
index 73e7ff74..484bc1de 100644
--- a/third_party/blink/renderer/platform/scheduler/base/sequence_manager_fuzzer_processor.cc
+++ b/third_party/blink/renderer/platform/scheduler/base/sequence_manager_fuzzer_processor.cc
@@ -89,6 +89,10 @@
                                    action.shutdown_task_queue());
   } else if (action.has_cancel_task()) {
     ExecuteCancelTaskAction(action.action_id(), action.cancel_task());
+  } else if (action.has_insert_fence()) {
+    ExecuteInsertFenceAction(action.action_id(), action.insert_fence());
+  } else if (action.has_remove_fence()) {
+    ExecuteRemoveFenceAction(action.action_id(), action.remove_fence());
   } else {
     ExecutePostDelayedTaskAction(action.action_id(),
                                  action.post_delayed_task());
@@ -202,17 +206,45 @@
                       test_task_runner_->GetMockTickClock()->NowTicks());
 
   if (!pending_tasks_.empty()) {
-    size_t queue_index = action.task_id() % pending_tasks_.size();
-    pending_tasks_[queue_index]->weak_ptr_factory_.InvalidateWeakPtrs();
+    size_t task_index = action.task_id() % pending_tasks_.size();
+    pending_tasks_[task_index]->weak_ptr_factory_.InvalidateWeakPtrs();
 
     // If it is already running, it is a parent task and will be deleted when
     // it is done.
-    if (!pending_tasks_[queue_index]->is_running) {
-      pending_tasks_.erase(pending_tasks_.begin() + queue_index);
+    if (!pending_tasks_[task_index]->is_running) {
+      pending_tasks_.erase(pending_tasks_.begin() + task_index);
     }
   }
 }
 
+void SequenceManagerFuzzerProcessor::ExecuteInsertFenceAction(
+    uint64_t action_id,
+    const SequenceManagerTestDescription::InsertFenceAction& action) {
+  LogActionForTesting(action_id, ActionForTest::ActionType::kInsertFence,
+                      test_task_runner_->GetMockTickClock()->NowTicks());
+
+  size_t queue_index = action.task_queue_id() % task_queues_.size();
+
+  if (action.position() ==
+      SequenceManagerTestDescription::InsertFenceAction::NOW) {
+    task_queues_[queue_index].queue.get()->InsertFence(
+        TaskQueue::InsertFencePosition::kNow);
+  } else {
+    task_queues_[queue_index].queue.get()->InsertFence(
+        TaskQueue::InsertFencePosition::kBeginningOfTime);
+  }
+}
+
+void SequenceManagerFuzzerProcessor::ExecuteRemoveFenceAction(
+    uint64_t action_id,
+    const SequenceManagerTestDescription::RemoveFenceAction& action) {
+  LogActionForTesting(action_id, ActionForTest::ActionType::kRemoveFence,
+                      test_task_runner_->GetMockTickClock()->NowTicks());
+
+  size_t queue_index = action.task_queue_id() % task_queues_.size();
+  task_queues_[queue_index].queue.get()->RemoveFence();
+}
+
 void SequenceManagerFuzzerProcessor::ExecuteTask(
     const SequenceManagerTestDescription::Task& task) {
   TimeTicks start_time = test_task_runner_->GetMockTickClock()->NowTicks();
diff --git a/third_party/blink/renderer/platform/scheduler/base/sequence_manager_fuzzer_processor.h b/third_party/blink/renderer/platform/scheduler/base/sequence_manager_fuzzer_processor.h
index fcd2502..a98d7d78 100644
--- a/third_party/blink/renderer/platform/scheduler/base/sequence_manager_fuzzer_processor.h
+++ b/third_party/blink/renderer/platform/scheduler/base/sequence_manager_fuzzer_processor.h
@@ -47,6 +47,8 @@
       kCreateQueueVoter,
       kCancelTask,
       kShutdownTaskQueue,
+      kInsertFence,
+      kRemoveFence
     };
 
     ActionForTest(uint64_t id, ActionType type, uint64_t start);
@@ -110,6 +112,12 @@
   void ExecuteCancelTaskAction(
       uint64_t action_id,
       const SequenceManagerTestDescription::CancelTaskAction& action);
+  void ExecuteInsertFenceAction(
+      uint64_t action_id,
+      const SequenceManagerTestDescription::InsertFenceAction& action);
+  void ExecuteRemoveFenceAction(
+      uint64_t action_id,
+      const SequenceManagerTestDescription::RemoveFenceAction& action);
 
   void ExecuteTask(const SequenceManagerTestDescription::Task& task);
 
diff --git a/third_party/blink/renderer/platform/scheduler/base/sequence_manager_fuzzer_processor_unittest.cc b/third_party/blink/renderer/platform/scheduler/base/sequence_manager_fuzzer_processor_unittest.cc
index aba61e4..a5384d6 100644
--- a/third_party/blink/renderer/platform/scheduler/base/sequence_manager_fuzzer_processor_unittest.cc
+++ b/third_party/blink/renderer/platform/scheduler/base/sequence_manager_fuzzer_processor_unittest.cc
@@ -944,5 +944,125 @@
   EXPECT_THAT(executed_actions, ContainerEq(expected_actions));
 }
 
+TEST(SequenceManagerFuzzerProcessorTest, InsertAndRemoveFence) {
+  std::vector<ActionForTest> executed_actions;
+  std::vector<TaskForTest> executed_tasks;
+
+  // Describes a test that inserts a fence to a task queue after a delay of
+  // 20ms, posts a task to it after a delay of 25ms, and removes the fence after
+  // a delay of 30ms.
+  SequenceManagerFuzzerProcessorForTest::ParseAndRun(R"(
+       initial_actions {
+         action_id : 1
+           create_task_queue{
+           }
+         }
+       initial_actions {
+         action_id : 2
+         post_delayed_task {
+           delay_ms : 20
+           task_queue_id : 2
+           task {
+             task_id : 1
+             actions {
+               action_id : 3
+               insert_fence {
+                 position: NOW
+                 task_queue_id: 1
+               }
+             }
+           }
+         }
+       }
+       initial_actions {
+         action_id : 4
+         post_delayed_task {
+           delay_ms : 30
+           task_queue_id : 2
+           task {
+             task_id : 2
+             actions {
+               action_id : 5
+               remove_fence {
+                 task_queue_id: 1
+               }
+             }
+           }
+         }
+      }
+      initial_actions {
+        action_id: 6
+        post_delayed_task {
+          delay_ms: 25
+          task_queue_id: 1
+          task {
+            task_id: 3
+          }
+        }
+      })",
+                                                     &executed_tasks,
+                                                     &executed_actions);
+
+  std::vector<ActionForTest> expected_actions;
+  expected_actions.emplace_back(1, ActionForTest::ActionType::kCreateTaskQueue,
+                                0);
+  expected_actions.emplace_back(2, ActionForTest::ActionType::kPostDelayedTask,
+                                0);
+  expected_actions.emplace_back(4, ActionForTest::ActionType::kPostDelayedTask,
+                                0);
+  expected_actions.emplace_back(6, ActionForTest::ActionType::kPostDelayedTask,
+                                0);
+  expected_actions.emplace_back(3, ActionForTest::ActionType::kInsertFence, 20);
+  expected_actions.emplace_back(5, ActionForTest::ActionType::kRemoveFence, 30);
+
+  EXPECT_THAT(executed_actions, ContainerEq(expected_actions));
+
+  std::vector<TaskForTest> expected_tasks;
+  expected_tasks.emplace_back(1, 20, 20);
+  expected_tasks.emplace_back(2, 30, 30);
+
+  // Task with id 3 will not execute until the fence is removed from the task
+  // queue it was posted to.
+  expected_tasks.emplace_back(3, 30, 30);
+
+  EXPECT_THAT(executed_tasks, ContainerEq(expected_tasks));
+}
+
+TEST(SequenceManagerFuzzerProcessorTest, ThrottleTaskQueue) {
+  std::vector<ActionForTest> executed_actions;
+  std::vector<TaskForTest> executed_tasks;
+
+  // Describes a test that throttles a task queue, and posts a task to it.
+  SequenceManagerFuzzerProcessorForTest::ParseAndRun(R"(
+       initial_actions {
+        action_id : 1
+        insert_fence {
+          position: BEGINNING_OF_TIME
+          task_queue_id: 1
+        }
+       }
+       initial_actions {
+         action_id: 2
+         post_delayed_task {
+           task_queue_id: 1
+           task {
+             task_id: 3
+           }
+         }
+       })",
+                                                     &executed_tasks,
+                                                     &executed_actions);
+
+  std::vector<ActionForTest> expected_actions;
+  expected_actions.emplace_back(1, ActionForTest::ActionType::kInsertFence, 0);
+  expected_actions.emplace_back(2, ActionForTest::ActionType::kPostDelayedTask,
+                                0);
+
+  EXPECT_THAT(executed_actions, ContainerEq(expected_actions));
+
+  // Task queue with id 1 is throttled, so posted tasks will not get executed.
+  EXPECT_THAT(executed_tasks, IsEmpty());
+}
+
 }  // namespace sequence_manager
 }  // namespace base
diff --git a/third_party/blink/renderer/platform/scroll/scroll_animator.cc b/third_party/blink/renderer/platform/scroll/scroll_animator.cc
index 565abbe..d53a19e 100644
--- a/third_party/blink/renderer/platform/scroll/scroll_animator.cc
+++ b/third_party/blink/renderer/platform/scroll/scroll_animator.cc
@@ -169,7 +169,7 @@
     // of sending to the compositor.
     if (run_state_ == RunState::kRunningOnMainThread) {
       animation_curve_->UpdateTarget(
-          time_function_() - start_time_,
+          TimeDelta::FromSecondsD(time_function_() - start_time_),
           CompositorOffsetFromBlinkOffset(target_offset));
       return true;
     }
@@ -329,7 +329,7 @@
       // ::adjustScrollOffsetAnimation should have made the necessary
       // adjustment to the curve.
       animation_curve_->UpdateTarget(
-          time_function_() - start_time_,
+          TimeDelta::FromSecondsD(time_function_() - start_time_),
           CompositorOffsetFromBlinkOffset(target_offset_));
     }
 
diff --git a/third_party/blink/renderer/platform/transforms/matrix_transform_operation.cc b/third_party/blink/renderer/platform/transforms/matrix_transform_operation.cc
index 531d274..5cc3d0c 100644
--- a/third_party/blink/renderer/platform/transforms/matrix_transform_operation.cc
+++ b/third_party/blink/renderer/platform/transforms/matrix_transform_operation.cc
@@ -33,7 +33,6 @@
     return this;
 
   // convert the TransformOperations into matrices
-  FloatSize size;
   TransformationMatrix from_t;
   TransformationMatrix to_t(a_, b_, c_, d_, e_, f_);
   if (from) {
diff --git a/third_party/blink/renderer/platform/wtf/math_extras.h b/third_party/blink/renderer/platform/wtf/math_extras.h
index c090e11..6913d3dc 100644
--- a/third_party/blink/renderer/platform/wtf/math_extras.h
+++ b/third_party/blink/renderer/platform/wtf/math_extras.h
@@ -48,83 +48,83 @@
 #include <sys/types.h>
 #endif
 
-const double kPiDouble = M_PI;
-const float kPiFloat = static_cast<float>(M_PI);
+constexpr double kPiDouble = M_PI;
+constexpr float kPiFloat = static_cast<float>(M_PI);
 
-const double kPiOverTwoDouble = M_PI_2;
-const float kPiOverTwoFloat = static_cast<float>(M_PI_2);
+constexpr double kPiOverTwoDouble = M_PI_2;
+constexpr float kPiOverTwoFloat = static_cast<float>(M_PI_2);
 
-const double kPiOverFourDouble = M_PI_4;
-const float kPiOverFourFloat = static_cast<float>(M_PI_4);
+constexpr double kPiOverFourDouble = M_PI_4;
+constexpr float kPiOverFourFloat = static_cast<float>(M_PI_4);
 
-const double kTwoPiDouble = kPiDouble * 2.0;
-const float kTwoPiFloat = kPiFloat * 2.0f;
+constexpr double kTwoPiDouble = kPiDouble * 2.0;
+constexpr float kTwoPiFloat = kPiFloat * 2.0f;
 
-inline double deg2rad(double d) {
+constexpr double deg2rad(double d) {
   return d * kPiDouble / 180.0;
 }
-inline double rad2deg(double r) {
+constexpr double rad2deg(double r) {
   return r * 180.0 / kPiDouble;
 }
-inline double deg2grad(double d) {
+constexpr double deg2grad(double d) {
   return d * 400.0 / 360.0;
 }
-inline double grad2deg(double g) {
+constexpr double grad2deg(double g) {
   return g * 360.0 / 400.0;
 }
-inline double turn2deg(double t) {
+constexpr double turn2deg(double t) {
   return t * 360.0;
 }
-inline double deg2turn(double d) {
+constexpr double deg2turn(double d) {
   return d / 360.0;
 }
-inline double rad2grad(double r) {
+constexpr double rad2grad(double r) {
   return r * 200.0 / kPiDouble;
 }
-inline double grad2rad(double g) {
+constexpr double grad2rad(double g) {
   return g * kPiDouble / 200.0;
 }
-inline double turn2grad(double t) {
+constexpr double turn2grad(double t) {
   return t * 400;
 }
-inline double grad2turn(double g) {
+constexpr double grad2turn(double g) {
   return g / 400;
 }
-inline double rad2turn(double r) {
+constexpr double rad2turn(double r) {
   return r / kTwoPiDouble;
 }
-inline double turn2rad(double t) {
+constexpr double turn2rad(double t) {
   return t * kTwoPiDouble;
 }
 
-inline float deg2rad(float d) {
+constexpr float deg2rad(float d) {
   return d * kPiFloat / 180.0f;
 }
-inline float rad2deg(float r) {
+constexpr float rad2deg(float r) {
   return r * 180.0f / kPiFloat;
 }
-inline float deg2grad(float d) {
+constexpr float deg2grad(float d) {
   return d * 400.0f / 360.0f;
 }
-inline float grad2deg(float g) {
+constexpr float grad2deg(float g) {
   return g * 360.0f / 400.0f;
 }
-inline float turn2deg(float t) {
+constexpr float turn2deg(float t) {
   return t * 360.0f;
 }
-inline float deg2turn(float d) {
+constexpr float deg2turn(float d) {
   return d / 360.0f;
 }
-inline float rad2grad(float r) {
+constexpr float rad2grad(float r) {
   return r * 200.0f / kPiFloat;
 }
-inline float grad2rad(float g) {
+constexpr float grad2rad(float g) {
   return g * kPiFloat / 200.0f;
 }
-inline float turn2grad(float t) {
+constexpr float turn2grad(float t) {
   return t * 400;
 }
-inline float grad2turn(float g) {
+constexpr float grad2turn(float g) {
   return g / 400;
 }
 
@@ -297,20 +297,20 @@
 };
 
 template <typename T>
-inline T defaultMaximumForClamp() {
+constexpr T defaultMaximumForClamp() {
   return std::numeric_limits<T>::max();
 }
 // This basically reimplements C++11's std::numeric_limits<T>::lowest().
 template <typename T>
-inline T defaultMinimumForClamp() {
+constexpr T defaultMinimumForClamp() {
   return std::numeric_limits<T>::min();
 }
 template <>
-inline float defaultMinimumForClamp<float>() {
+constexpr float defaultMinimumForClamp<float>() {
   return -std::numeric_limits<float>::max();
 }
 template <>
-inline double defaultMinimumForClamp<double>() {
+constexpr double defaultMinimumForClamp<double>() {
   return -std::numeric_limits<double>::max();
 }
 
@@ -324,16 +324,16 @@
   return ClampToHelper<LimitType, ValueType>::clampTo(value, min, max);
 }
 
-inline bool isWithinIntRange(float x) {
+constexpr bool isWithinIntRange(float x) {
   return x > static_cast<float>(std::numeric_limits<int>::min()) &&
          x < static_cast<float>(std::numeric_limits<int>::max());
 }
 
-static size_t greatestCommonDivisor(size_t a, size_t b) {
+static constexpr size_t greatestCommonDivisor(size_t a, size_t b) {
   return b ? greatestCommonDivisor(b, a % b) : a;
 }
 
-inline size_t lowestCommonMultiple(size_t a, size_t b) {
+constexpr size_t lowestCommonMultiple(size_t a, size_t b) {
   return a && b ? a / greatestCommonDivisor(a, b) * b : 0;
 }
 
diff --git a/third_party/crashpad/README.chromium b/third_party/crashpad/README.chromium
index aed01e02..73d39da 100644
--- a/third_party/crashpad/README.chromium
+++ b/third_party/crashpad/README.chromium
@@ -2,7 +2,7 @@
 Short Name: crashpad
 URL: https://crashpad.chromium.org/
 Version: unknown
-Revision: fb0f7ca8d7eb55ca51b77eb89813a3283a461b0c
+Revision: 2f3a8b8f72dccc7c1738eb496e46e86ee60ec4ed
 License: Apache 2.0
 License File: crashpad/LICENSE
 Security Critical: yes
diff --git a/third_party/crashpad/crashpad/DEPS b/third_party/crashpad/crashpad/DEPS
index dbdc3a4..34f1ef68 100644
--- a/third_party/crashpad/crashpad/DEPS
+++ b/third_party/crashpad/crashpad/DEPS
@@ -37,6 +37,90 @@
   'crashpad/third_party/zlib/zlib':
       Var('chromium_git') + '/chromium/src/third_party/zlib@' +
       '13dc246a58e4b72104d35f9b1809af95221ebda7',
+
+  # CIPD packages below.
+  'crashpad/third_party/linux/clang/linux-amd64': {
+    'packages': [
+      {
+        'package': 'fuchsia/clang/linux-amd64',
+        'version': 'goma',
+      },
+    ],
+    'condition': 'checkout_linux and pull_linux_clang',
+    'dep_type': 'cipd'
+  },
+  'crashpad/third_party/linux/clang/mac-amd64': {
+    'packages': [
+      {
+        'package': 'fuchsia/clang/mac-amd64',
+        'version': 'goma',
+      },
+    ],
+    'condition': 'checkout_fuchsia and host_os == "mac"',
+    'dep_type': 'cipd'
+  },
+  'crashpad/third_party/fuchsia/clang/linux-amd64': {
+    'packages': [
+      {
+        'package': 'fuchsia/clang/linux-amd64',
+        'version': 'goma',
+      },
+    ],
+    'condition': 'checkout_fuchsia and host_os == "linux"',
+    'dep_type': 'cipd'
+  },
+  'crashpad/third_party/fuchsia/qemu/mac-amd64': {
+    'packages': [
+      {
+        'package': 'fuchsia/qemu/mac-amd64',
+        'version': 'latest'
+      },
+    ],
+    'condition': 'checkout_fuchsia and host_os == "mac"',
+    'dep_type': 'cipd'
+  },
+  'crashpad/third_party/fuchsia/qemu/linux-amd64': {
+    'packages': [
+      {
+        'package': 'fuchsia/qemu/linux-amd64',
+        'version': 'latest'
+      },
+    ],
+    'condition': 'checkout_fuchsia and host_os == "linux"',
+    'dep_type': 'cipd'
+  },
+  'crashpad/third_party/fuchsia/sdk/linux-amd64': {
+    # The SDK is keyed to the host system because it contains build tools.
+    # Currently, linux-amd64 is the only SDK published (see
+    # https://chrome-infra-packages.appspot.com/#/?path=fuchsia/sdk).
+    # As long as this is the case, use that SDK package
+    # even on other build hosts.
+    # The sysroot (containing headers and libraries) and other components are
+    # related to the target and should be functional with an appropriate
+    # toolchain that runs on the build host (fuchsia_clang, above).
+    'packages': [
+      {
+        'package': 'fuchsia/sdk/linux-amd64',
+        'version': 'latest'
+      },
+    ],
+    'condition': 'checkout_fuchsia',
+    'dep_type': 'cipd'
+  },
+  'crashpad/third_party/win/toolchain': {
+    # This package is only updated when the solution in .gclient includes an
+    # entry like:
+    #   "custom_vars": { "pull_win_toolchain": True }
+    # This is because the contained bits are not redistributable.
+    'packages': [
+      {
+        'package': 'chrome_internal/third_party/sdk/windows',
+        'version': 'uploaded:2018-06-13'
+      },
+    ],
+    'condition': 'checkout_win and pull_win_toolchain',
+    'dep_type': 'cipd'
+  },
 }
 
 hooks = [
@@ -119,28 +203,6 @@
     ],
   },
   {
-    # This uses “cipd install” so that mac-amd64 and linux-amd64 can coexist
-    # peacefully. “cipd ensure” would remove the macOS package when running on a
-    # Linux build host and vice-versa. https://crbug.com/789364. This package is
-    # only updated when the solution in .gclient includes an entry like:
-    #   "custom_vars": { "pull_linux_clang": True }
-    # The ref used is "goma". This is like "latest", but is considered a more
-    # stable latest by the Fuchsia toolchain team.
-    'name': 'clang_linux',
-    'pattern': '.',
-    'condition': 'checkout_linux and pull_linux_clang',
-    'action': [
-      'cipd',
-      'install',
-      # sic, using Fuchsia team's generic build of clang for linux-amd64 to
-      # build for linux-amd64 target too.
-      'fuchsia/clang/linux-amd64',
-      'goma',
-      '-root', 'crashpad/third_party/linux/clang/linux-amd64',
-      '-log-level', 'info',
-    ],
-  },
-  {
     # If using a local clang ("pull_linux_clang" above), also pull down a
     # sysroot.
     'name': 'sysroot_linux',
@@ -151,105 +213,6 @@
     ],
   },
   {
-    # Same rationale for using "install" rather than "ensure" as for first clang
-    # package. https://crbug.com/789364.
-    # Same rationale for using "goma" instead of "latest" as clang_linux above.
-    'name': 'fuchsia_clang_mac',
-    'pattern': '.',
-    'condition': 'checkout_fuchsia and host_os == "mac"',
-    'action': [
-      'cipd',
-      'install',
-      'fuchsia/clang/mac-amd64',
-      'goma',
-      '-root', 'crashpad/third_party/fuchsia/clang/mac-amd64',
-      '-log-level', 'info',
-    ],
-  },
-  {
-    # Same rationale for using "install" rather than "ensure" as for first clang
-    # package. https://crbug.com/789364.
-    # Same rationale for using "goma" instead of "latest" as clang_linux above.
-    'name': 'fuchsia_clang_linux',
-    'pattern': '.',
-    'condition': 'checkout_fuchsia and host_os == "linux"',
-    'action': [
-      'cipd',
-      'install',
-      'fuchsia/clang/linux-amd64',
-      'goma',
-      '-root', 'crashpad/third_party/fuchsia/clang/linux-amd64',
-      '-log-level', 'info',
-    ],
-  },
-  {
-    # Same rationale for using "install" rather than "ensure" as for clang
-    # packages. https://crbug.com/789364.
-    'name': 'fuchsia_qemu_mac',
-    'pattern': '.',
-    'condition': 'checkout_fuchsia and host_os == "mac"',
-    'action': [
-      'cipd',
-      'install',
-      'fuchsia/qemu/mac-amd64',
-      'latest',
-      '-root', 'crashpad/third_party/fuchsia/qemu/mac-amd64',
-      '-log-level', 'info',
-    ],
-  },
-  {
-    # Same rationale for using "install" rather than "ensure" as for clang
-    # packages. https://crbug.com/789364.
-    'name': 'fuchsia_qemu_linux',
-    'pattern': '.',
-    'condition': 'checkout_fuchsia and host_os == "linux"',
-    'action': [
-      'cipd',
-      'install',
-      'fuchsia/qemu/linux-amd64',
-      'latest',
-      '-root', 'crashpad/third_party/fuchsia/qemu/linux-amd64',
-      '-log-level', 'info',
-    ],
-  },
-  {
-    # The SDK is keyed to the host system because it contains build tools.
-    # Currently, linux-amd64 is the only SDK published (see
-    # https://chrome-infra-packages.appspot.com/#/?path=fuchsia/sdk). As long as
-    # this is the case, use that SDK package even on other build hosts. The
-    # sysroot (containing headers and libraries) and other components are
-    # related to the target and should be functional with an appropriate
-    # toolchain that runs on the build host (fuchsia_clang, above).
-    'name': 'fuchsia_sdk',
-    'pattern': '.',
-    'condition': 'checkout_fuchsia',
-    'action': [
-      'cipd',
-      'install',
-      'fuchsia/sdk/linux-amd64',
-      'latest',
-      '-root', 'crashpad/third_party/fuchsia/sdk/linux-amd64',
-      '-log-level', 'info',
-    ],
-  },
-  {
-    'name': 'toolchain_win',
-    'pattern': '.',
-    # This package is only updated when the solution in .gclient includes an
-    # entry like:
-    #   "custom_vars": { "pull_win_toolchain": True }
-    # This is because the contained bits are not redistributable.
-    'condition': 'checkout_win and pull_win_toolchain',
-    'action': [
-      'cipd',
-      'install',
-      'chrome_internal/third_party/sdk/windows',
-      'uploaded:2018-06-13',
-      '-root', 'crashpad/third_party/win/toolchain',
-      '-log-level', 'info',
-    ],
-  },
-  {
     'name': 'gyp',
     'pattern': '\.gypi?$',
     'action': ['python', 'crashpad/build/gyp_crashpad.py'],
diff --git a/third_party/crashpad/crashpad/client/client_argv_handling.cc b/third_party/crashpad/crashpad/client/client_argv_handling.cc
index 9b813b1..6933aac 100644
--- a/third_party/crashpad/crashpad/client/client_argv_handling.cc
+++ b/third_party/crashpad/crashpad/client/client_argv_handling.cc
@@ -27,38 +27,38 @@
 
 }  // namespace
 
-void BuildHandlerArgvStrings(
+std::vector<std::string> BuildHandlerArgvStrings(
     const base::FilePath& handler,
     const base::FilePath& database,
     const base::FilePath& metrics_dir,
     const std::string& url,
     const std::map<std::string, std::string>& annotations,
-    const std::vector<std::string>& arguments,
-    std::vector<std::string>* argv_strings) {
-  argv_strings->clear();
+    const std::vector<std::string>& arguments) {
+  std::vector<std::string> argv_strings(1, handler.value());
 
-  argv_strings->push_back(handler.value());
   for (const auto& argument : arguments) {
-    argv_strings->push_back(argument);
+    argv_strings.push_back(argument);
   }
 
   if (!database.empty()) {
-    argv_strings->push_back(FormatArgumentString("database", database.value()));
+    argv_strings.push_back(FormatArgumentString("database", database.value()));
   }
 
   if (!metrics_dir.empty()) {
-    argv_strings->push_back(
+    argv_strings.push_back(
         FormatArgumentString("metrics-dir", metrics_dir.value()));
   }
 
   if (!url.empty()) {
-    argv_strings->push_back(FormatArgumentString("url", url));
+    argv_strings.push_back(FormatArgumentString("url", url));
   }
 
   for (const auto& kv : annotations) {
-    argv_strings->push_back(
+    argv_strings.push_back(
         FormatArgumentString("annotation", kv.first + '=' + kv.second));
   }
+
+  return argv_strings;
 }
 
 void ConvertArgvStrings(const std::vector<std::string>& argv_strings,
diff --git a/third_party/crashpad/crashpad/client/client_argv_handling.h b/third_party/crashpad/crashpad/client/client_argv_handling.h
index 0ef3a15..d380b1a 100644
--- a/third_party/crashpad/crashpad/client/client_argv_handling.h
+++ b/third_party/crashpad/crashpad/client/client_argv_handling.h
@@ -28,16 +28,14 @@
 //!
 //! See StartHandlerAtCrash() for documentation on the input arguments.
 //!
-//! \param[out] A argv_strings vector of arguments suitable for starting the
-//!     handler with.
-void BuildHandlerArgvStrings(
+//! \return A vector of arguments suitable for starting the handler with.
+std::vector<std::string> BuildHandlerArgvStrings(
     const base::FilePath& handler,
     const base::FilePath& database,
     const base::FilePath& metrics_dir,
     const std::string& url,
     const std::map<std::string, std::string>& annotations,
-    const std::vector<std::string>& arguments,
-    std::vector<std::string>* argv_strings);
+    const std::vector<std::string>& arguments);
 
 //! \brief Flattens a string vector into a const char* vector suitable for use
 //!     in an exec() call.
diff --git a/third_party/crashpad/crashpad/client/crash_report_database.cc b/third_party/crashpad/crashpad/client/crash_report_database.cc
index aa365be..d300a8f9 100644
--- a/third_party/crashpad/crashpad/client/crash_report_database.cc
+++ b/third_party/crashpad/crashpad/client/crash_report_database.cc
@@ -69,7 +69,8 @@
       reader_(std::make_unique<FileReader>()),
       database_(nullptr),
       attachment_readers_(),
-      attachment_map_() {}
+      attachment_map_(),
+      report_metrics_(false) {}
 
 CrashReportDatabase::UploadReport::~UploadReport() {
   if (database_) {
diff --git a/third_party/crashpad/crashpad/client/crash_report_database.h b/third_party/crashpad/crashpad/client/crash_report_database.h
index 9ceeddc33..d115c74b 100644
--- a/third_party/crashpad/crashpad/client/crash_report_database.h
+++ b/third_party/crashpad/crashpad/client/crash_report_database.h
@@ -178,6 +178,7 @@
     CrashReportDatabase* database_;
     std::vector<std::unique_ptr<FileReader>> attachment_readers_;
     std::map<std::string, FileReader*> attachment_map_;
+    bool report_metrics_;
 
     DISALLOW_COPY_AND_ASSIGN(UploadReport);
   };
@@ -326,11 +327,16 @@
   //! \param[in] uuid The unique identifier for the crash report record.
   //! \param[out] report A crash report record for the report to be uploaded.
   //!     Only valid if this returns #kNoError.
+  //! \param[in] report_metrics If `false`, metrics will not be recorded for
+  //!     this upload attempt when RecordUploadComplete() is called or \a report
+  //!     is destroyed. Metadata for the upload attempt will still be recorded
+  //!     in the database.
   //!
   //! \return The operation status code.
   virtual OperationStatus GetReportForUploading(
       const UUID& uuid,
-      std::unique_ptr<const UploadReport>* report) = 0;
+      std::unique_ptr<const UploadReport>* report,
+      bool report_metrics = true) = 0;
 
   //! \brief Records a successful upload for a report and updates the last
   //!     upload attempt time as returned by
diff --git a/third_party/crashpad/crashpad/client/crash_report_database_generic.cc b/third_party/crashpad/crashpad/client/crash_report_database_generic.cc
index 6dc8e9e..8e93237 100644
--- a/third_party/crashpad/crashpad/client/crash_report_database_generic.cc
+++ b/third_party/crashpad/crashpad/client/crash_report_database_generic.cc
@@ -180,7 +180,8 @@
   OperationStatus GetCompletedReports(std::vector<Report>* reports) override;
   OperationStatus GetReportForUploading(
       const UUID& uuid,
-      std::unique_ptr<const UploadReport>* report) override;
+      std::unique_ptr<const UploadReport>* report,
+      bool report_metrics) override;
   OperationStatus SkipReportUpload(const UUID& uuid,
                                    Metrics::CrashSkippedReason reason) override;
   OperationStatus DeleteReport(const UUID& uuid) override;
@@ -455,7 +456,8 @@
 
 OperationStatus CrashReportDatabaseGeneric::GetReportForUploading(
     const UUID& uuid,
-    std::unique_ptr<const UploadReport>* report) {
+    std::unique_ptr<const UploadReport>* report,
+    bool report_metrics) {
   INITIALIZATION_STATE_DCHECK_VALID(initialized_);
 
   auto upload_report = std::make_unique<LockfileUploadReport>();
@@ -470,6 +472,7 @@
   if (!upload_report->Initialize(path, this)) {
     return kFileSystemError;
   }
+  upload_report->report_metrics_ = report_metrics;
 
   report->reset(upload_report.release());
   return kNoError;
@@ -609,7 +612,9 @@
     const std::string& id) {
   INITIALIZATION_STATE_DCHECK_VALID(initialized_);
 
-  Metrics::CrashUploadAttempted(successful);
+  if (report->report_metrics_) {
+    Metrics::CrashUploadAttempted(successful);
+  }
   time_t now = time(nullptr);
 
   report->id = id;
diff --git a/third_party/crashpad/crashpad/client/crash_report_database_mac.mm b/third_party/crashpad/crashpad/client/crash_report_database_mac.mm
index 79b876d..3106dc2c 100644
--- a/third_party/crashpad/crashpad/client/crash_report_database_mac.mm
+++ b/third_party/crashpad/crashpad/client/crash_report_database_mac.mm
@@ -141,7 +141,8 @@
   OperationStatus GetCompletedReports(std::vector<Report>* reports) override;
   OperationStatus GetReportForUploading(
       const UUID& uuid,
-      std::unique_ptr<const UploadReport>* report) override;
+      std::unique_ptr<const UploadReport>* report,
+      bool report_metrics) override;
   OperationStatus SkipReportUpload(const UUID& uuid,
                                    Metrics::CrashSkippedReason reason) override;
   OperationStatus DeleteReport(const UUID& uuid) override;
@@ -422,7 +423,8 @@
 CrashReportDatabase::OperationStatus
 CrashReportDatabaseMac::GetReportForUploading(
     const UUID& uuid,
-    std::unique_ptr<const UploadReport>* report) {
+    std::unique_ptr<const UploadReport>* report,
+    bool report_metrics) {
   INITIALIZATION_STATE_DCHECK_VALID(initialized_);
 
   auto upload_report = std::make_unique<UploadReportMac>();
@@ -444,6 +446,7 @@
 
   upload_report->database_ = this;
   upload_report->lock_fd.reset(lock.release());
+  upload_report->report_metrics_ = report_metrics;
   report->reset(upload_report.release());
   return kNoError;
 }
@@ -454,7 +457,9 @@
                                             const std::string& id) {
   INITIALIZATION_STATE_DCHECK_VALID(initialized_);
 
-  Metrics::CrashUploadAttempted(successful);
+  if (report->report_metrics_) {
+    Metrics::CrashUploadAttempted(successful);
+  }
 
   DCHECK(report);
   DCHECK(successful || id.empty());
diff --git a/third_party/crashpad/crashpad/client/crash_report_database_win.cc b/third_party/crashpad/crashpad/client/crash_report_database_win.cc
index e19e605..8967770 100644
--- a/third_party/crashpad/crashpad/client/crash_report_database_win.cc
+++ b/third_party/crashpad/crashpad/client/crash_report_database_win.cc
@@ -594,7 +594,8 @@
   OperationStatus GetCompletedReports(std::vector<Report>* reports) override;
   OperationStatus GetReportForUploading(
       const UUID& uuid,
-      std::unique_ptr<const UploadReport>* report) override;
+      std::unique_ptr<const UploadReport>* report,
+      bool report_metrics) override;
   OperationStatus SkipReportUpload(const UUID& uuid,
                                    Metrics::CrashSkippedReason reason) override;
   OperationStatus DeleteReport(const UUID& uuid) override;
@@ -731,7 +732,8 @@
 
 OperationStatus CrashReportDatabaseWin::GetReportForUploading(
     const UUID& uuid,
-    std::unique_ptr<const UploadReport>* report) {
+    std::unique_ptr<const UploadReport>* report,
+    bool report_metrics) {
   INITIALIZATION_STATE_DCHECK_VALID(initialized_);
 
   std::unique_ptr<Metadata> metadata(AcquireMetadata());
@@ -749,6 +751,7 @@
     if (!upload_report->Initialize(upload_report->file_path, this)) {
       return kFileSystemError;
     }
+    upload_report->report_metrics_ = report_metrics;
 
     report->reset(upload_report.release());
   }
@@ -761,7 +764,9 @@
     const std::string& id) {
   INITIALIZATION_STATE_DCHECK_VALID(initialized_);
 
-  Metrics::CrashUploadAttempted(successful);
+  if (report->report_metrics_) {
+    Metrics::CrashUploadAttempted(successful);
+  }
 
   std::unique_ptr<Metadata> metadata(AcquireMetadata());
   if (!metadata)
diff --git a/third_party/crashpad/crashpad/client/crashpad_client_fuchsia.cc b/third_party/crashpad/crashpad/client/crashpad_client_fuchsia.cc
index 26781094..0d1b65b 100644
--- a/third_party/crashpad/crashpad/client/crashpad_client_fuchsia.cc
+++ b/third_party/crashpad/crashpad/client/crashpad_client_fuchsia.cc
@@ -58,14 +58,8 @@
     return false;
   }
 
-  std::vector<std::string> argv_strings;
-  BuildHandlerArgvStrings(handler,
-                          database,
-                          metrics_dir,
-                          url,
-                          annotations,
-                          arguments,
-                          &argv_strings);
+  std::vector<std::string> argv_strings = BuildHandlerArgvStrings(
+      handler, database, metrics_dir, url, annotations, arguments);
 
   std::vector<const char*> argv;
   ConvertArgvStrings(argv_strings, &argv);
diff --git a/third_party/crashpad/crashpad/client/crashpad_client_linux.cc b/third_party/crashpad/crashpad/client/crashpad_client_linux.cc
index e7fa162c..54fe268 100644
--- a/third_party/crashpad/crashpad/client/crashpad_client_linux.cc
+++ b/third_party/crashpad/crashpad/client/crashpad_client_linux.cc
@@ -175,9 +175,8 @@
     const std::string& url,
     const std::map<std::string, std::string>& annotations,
     const std::vector<std::string>& arguments) {
-  std::vector<std::string> argv;
-  BuildHandlerArgvStrings(
-      handler, database, metrics_dir, url, annotations, arguments, &argv);
+  std::vector<std::string> argv = BuildHandlerArgvStrings(
+      handler, database, metrics_dir, url, annotations, arguments);
 
   auto signal_handler = LaunchAtCrashHandler::Get();
   if (signal_handler->Initialize(&argv)) {
@@ -197,9 +196,8 @@
     const std::map<std::string, std::string>& annotations,
     const std::vector<std::string>& arguments,
     int socket) {
-  std::vector<std::string> argv;
-  BuildHandlerArgvStrings(
-      handler, database, metrics_dir, url, annotations, arguments, &argv);
+  std::vector<std::string> argv = BuildHandlerArgvStrings(
+      handler, database, metrics_dir, url, annotations, arguments);
 
   argv.push_back(FormatArgumentInt("initial-client", socket));
 
diff --git a/third_party/crashpad/crashpad/client/prune_crash_reports_test.cc b/third_party/crashpad/crashpad/client/prune_crash_reports_test.cc
index e1be2f4..27a2836 100644
--- a/third_party/crashpad/crashpad/client/prune_crash_reports_test.cc
+++ b/third_party/crashpad/crashpad/client/prune_crash_reports_test.cc
@@ -41,9 +41,10 @@
   MOCK_METHOD2(LookUpCrashReport, OperationStatus(const UUID&, Report*));
   MOCK_METHOD1(GetPendingReports, OperationStatus(std::vector<Report>*));
   MOCK_METHOD1(GetCompletedReports, OperationStatus(std::vector<Report>*));
-  MOCK_METHOD2(GetReportForUploading,
+  MOCK_METHOD3(GetReportForUploading,
                OperationStatus(const UUID&,
-                               std::unique_ptr<const UploadReport>*));
+                               std::unique_ptr<const UploadReport>*,
+                               bool report_metrics));
   MOCK_METHOD3(RecordUploadAttempt,
                OperationStatus(UploadReport*, bool, const std::string&));
   MOCK_METHOD2(SkipReportUpload,
diff --git a/third_party/crashpad/crashpad/client/simple_string_dictionary_test.cc b/third_party/crashpad/crashpad/client/simple_string_dictionary_test.cc
index 5fdeb5b..7af51a27 100644
--- a/third_party/crashpad/crashpad/client/simple_string_dictionary_test.cc
+++ b/third_party/crashpad/crashpad/client/simple_string_dictionary_test.cc
@@ -115,8 +115,7 @@
 // Add a bunch of values to the dictionary, remove some entries in the middle,
 // and then add more.
 TEST(SimpleStringDictionary, Iterator) {
-  SimpleStringDictionary* dict = new SimpleStringDictionary;
-  ASSERT_TRUE(dict);
+  SimpleStringDictionary dict;
 
   char key[SimpleStringDictionary::key_size];
   char value[SimpleStringDictionary::value_size];
@@ -135,32 +134,32 @@
   for (int i = 0; i < kPartitionIndex; ++i) {
     sprintf(key, "key%d", i);
     sprintf(value, "value%d", i);
-    dict->SetKeyValue(key, value);
+    dict.SetKeyValue(key, value);
   }
   expected_dictionary_size = kPartitionIndex;
 
   // set a couple of the keys twice (with the same value) - should be nop
-  dict->SetKeyValue("key2", "value2");
-  dict->SetKeyValue("key4", "value4");
-  dict->SetKeyValue("key15", "value15");
+  dict.SetKeyValue("key2", "value2");
+  dict.SetKeyValue("key4", "value4");
+  dict.SetKeyValue("key15", "value15");
 
   // Remove some random elements in the middle
-  dict->RemoveKey("key7");
-  dict->RemoveKey("key18");
-  dict->RemoveKey("key23");
-  dict->RemoveKey("key31");
+  dict.RemoveKey("key7");
+  dict.RemoveKey("key18");
+  dict.RemoveKey("key23");
+  dict.RemoveKey("key31");
   expected_dictionary_size -= 4;  // we just removed four key/value pairs
 
   // Set some more key/value pairs like key59/value59, key60/value60, ...
   for (int i = kPartitionIndex; i < kDictionaryCapacity; ++i) {
     sprintf(key, "key%d", i);
     sprintf(value, "value%d", i);
-    dict->SetKeyValue(key, value);
+    dict.SetKeyValue(key, value);
   }
   expected_dictionary_size += kDictionaryCapacity - kPartitionIndex;
 
   // Now create an iterator on the dictionary
-  SimpleStringDictionary::Iterator iter(*dict);
+  SimpleStringDictionary::Iterator iter(dict);
 
   // We then verify that it iterates through exactly the number of key/value
   // pairs we expect, and that they match one-for-one with what we would expect.
diff --git a/third_party/crashpad/crashpad/handler/crash_report_upload_thread.cc b/third_party/crashpad/crashpad/handler/crash_report_upload_thread.cc
index 4783ecb..205d860 100644
--- a/third_party/crashpad/crashpad/handler/crash_report_upload_thread.cc
+++ b/third_party/crashpad/crashpad/handler/crash_report_upload_thread.cc
@@ -227,6 +227,10 @@
       database_->RecordUploadComplete(std::move(upload_report), response_body);
       break;
     case UploadResult::kPermanentFailure:
+      upload_report.reset();
+      database_->SkipReportUpload(
+          report.uuid, Metrics::CrashSkippedReason::kPrepareForUploadFailed);
+      break;
     case UploadResult::kRetry:
       upload_report.reset();
 
diff --git a/third_party/crashpad/crashpad/snapshot/linux/process_reader_linux_test.cc b/third_party/crashpad/crashpad/snapshot/linux/process_reader_linux_test.cc
index 6c0b98a..940114c6 100644
--- a/third_party/crashpad/crashpad/snapshot/linux/process_reader_linux_test.cc
+++ b/third_party/crashpad/crashpad/snapshot/linux/process_reader_linux_test.cc
@@ -40,6 +40,7 @@
 #include "test/multiprocess.h"
 #include "util/file/file_io.h"
 #include "util/linux/direct_ptrace_connection.h"
+#include "util/misc/address_sanitizer.h"
 #include "util/misc/from_pointer_cast.h"
 #include "util/synchronization/semaphore.h"
 
@@ -264,12 +265,17 @@
               iterator->second.tls);
 
     ASSERT_TRUE(memory_map.FindMapping(thread.stack_region_address));
-    EXPECT_LE(thread.stack_region_address, iterator->second.stack_address);
-
     ASSERT_TRUE(memory_map.FindMapping(thread.stack_region_address +
                                        thread.stack_region_size - 1));
+
+#if !defined(ADDRESS_SANITIZER)
+    // AddressSanitizer causes stack variables to be stored separately from the
+    // call stack.
+    EXPECT_LE(thread.stack_region_address, iterator->second.stack_address);
     EXPECT_GE(thread.stack_region_address + thread.stack_region_size,
               iterator->second.stack_address);
+#endif  // !defined(ADDRESS_SANITIZER)
+
     if (iterator->second.max_stack_size) {
       EXPECT_LT(thread.stack_region_size, iterator->second.max_stack_size);
     }
diff --git a/third_party/crashpad/crashpad/snapshot/mac/mach_o_image_segment_reader.cc b/third_party/crashpad/crashpad/snapshot/mac/mach_o_image_segment_reader.cc
index 1be829d..478b37d 100644
--- a/third_party/crashpad/crashpad/snapshot/mac/mach_o_image_segment_reader.cc
+++ b/third_party/crashpad/crashpad/snapshot/mac/mach_o_image_segment_reader.cc
@@ -15,6 +15,7 @@
 #include "snapshot/mac/mach_o_image_segment_reader.h"
 
 #include <mach-o/loader.h>
+#include <string.h>
 
 #include <utility>
 
@@ -35,6 +36,37 @@
 
 }  // namespace
 
+bool IsMalformedCLKernelsModule(uint32_t mach_o_file_type,
+                                const std::string& module_name,
+                                bool* has_timestamp) {
+  if (mach_o_file_type != MH_BUNDLE) {
+    return false;
+  }
+
+  if (module_name == "cl_kernels") {
+    if (MacOSXMinorVersion() >= 10) {
+      if (has_timestamp) {
+        *has_timestamp = false;
+      }
+      return true;
+    }
+    return false;
+  }
+
+  static const char kCvmsObjectPathPrefix[] =
+      "/private/var/db/CVMS/cvmsCodeSignObj";
+  if (module_name.compare(
+          0, strlen(kCvmsObjectPathPrefix), kCvmsObjectPathPrefix) == 0 &&
+      MacOSXMinorVersion() >= 14) {
+    if (has_timestamp) {
+      *has_timestamp = true;
+    }
+    return true;
+  }
+
+  return false;
+}
+
 MachOImageSegmentReader::MachOImageSegmentReader()
     : segment_command_(),
       sections_(),
@@ -121,21 +153,13 @@
                                                   load_command_info.c_str());
 
     // cl_kernels modules (for OpenCL) aren’t ld output, and they’re formatted
-    // incorrectly on OS X 10.10 and later. They have a single __TEXT segment,
-    // but one of the sections within it claims to belong to the __LD segment.
-    // This mismatch shouldn’t happen. This errant section also has the
-    // S_ATTR_DEBUG flag set, which shouldn’t happen unless all of the other
-    // sections in the segment also have this bit set (they don’t). These odd
-    // sections are reminiscent of unwind information stored in MH_OBJECT
-    // images, although cl_kernels images claim to be MH_BUNDLE. Because at
-    // least one cl_kernels module will commonly be found in a process, and
-    // sometimes more will be, tolerate this quirk.
+    // incorrectly on OS X 10.10 and later. Because at least one cl_kernels
+    // module will commonly be found in a process, and sometimes more will be,
+    // tolerate this quirk.
     //
     // https://openradar.appspot.com/20239912
     if (section_segment_name != segment_name &&
-        !(file_type == MH_BUNDLE &&
-          module_name == "cl_kernels" &&
-          MacOSXMinorVersion() >= 10 &&
+        !(IsMalformedCLKernelsModule(file_type, module_name, nullptr) &&
           segment_name == SEG_TEXT &&
           section_segment_name == "__LD" &&
           section_name == "__compact_unwind" &&
diff --git a/third_party/crashpad/crashpad/snapshot/mac/mach_o_image_segment_reader.h b/third_party/crashpad/crashpad/snapshot/mac/mach_o_image_segment_reader.h
index bdd5771..1e72785 100644
--- a/third_party/crashpad/crashpad/snapshot/mac/mach_o_image_segment_reader.h
+++ b/third_party/crashpad/crashpad/snapshot/mac/mach_o_image_segment_reader.h
@@ -29,6 +29,41 @@
 
 namespace crashpad {
 
+//! \brief Determines whether a module appears to be a malformed OpenCL
+//!     `cl_kernels` module based on its name and Mach-O file type.
+//!
+//! `cl_kernels` modules require special handling because they’re malformed on
+//! OS X 10.10 and later. A `cl_kernels` module always has Mach-O type
+//! `MH_BUNDLE` and is named `"cl_kernels"` until macOS 10.14, and
+//! `"/private/var/db/CVMS/cvmsCodeSignObj"` plus 16 random characters on macOS
+//! 10.14.
+//!
+//! Malformed `cl_kernels` modules have a single `__TEXT` segment, but one of
+//! the sections within it claims to belong to the `__LD` segment. This mismatch
+//! shouldn’t happen. This errant section also has the `S_ATTR_DEBUG` flag set,
+//! which shouldn’t happen unless all of the other sections in the segment also
+//! have this bit set (they don’t). These odd sections are reminiscent of unwind
+//! information stored in `MH_OBJECT` images, although `cl_kernels` images claim
+//! to be `MH_BUNDLE`.
+//!
+//! This function is exposed for testing purposes only.
+//!
+//! \param[in] mach_o_file_type The Mach-O type of the module being examined.
+//! \param[in] module_name The pathname that `dyld` reported having loaded the
+//!     module from.
+//! \param[out] has_timestamp Optional, may be `nullptr`. If provided, and the
+//!     module is a maformed `cl_kernels` module, this will be set to `true` if
+//!     the module was loaded from the filesystem (as is the case when loaded
+//!     from the CVMS directory) and is expected to have a timestamp, and
+//!     `false` otherwise. Note that even when loaded from the filesystem, these
+//!     modules are unlinked from the filesystem after loading.
+//!
+//! \return `true` if the module appears to be a malformed `cl_kernels` module
+//!     based on the provided information, `false` otherwise.
+bool IsMalformedCLKernelsModule(uint32_t mach_o_file_type,
+                                const std::string& module_name,
+                                bool* has_timestamp);
+
 //! \brief A reader for `LC_SEGMENT` or `LC_SEGMENT_64` load commands in Mach-O
 //!     images mapped into another process.
 //!
diff --git a/third_party/crashpad/crashpad/snapshot/mac/process_reader_mac_test.cc b/third_party/crashpad/crashpad/snapshot/mac/process_reader_mac_test.cc
index faec147..59884a6 100644
--- a/third_party/crashpad/crashpad/snapshot/mac/process_reader_mac_test.cc
+++ b/third_party/crashpad/crashpad/snapshot/mac/process_reader_mac_test.cc
@@ -32,6 +32,7 @@
 #include "build/build_config.h"
 #include "gtest/gtest.h"
 #include "snapshot/mac/mach_o_image_reader.h"
+#include "snapshot/mac/mach_o_image_segment_reader.h"
 #include "test/errors.h"
 #include "test/mac/dyld.h"
 #include "test/mac/mach_errors.h"
@@ -663,14 +664,20 @@
         modules[index].reader->Address(),
         FromPointerCast<mach_vm_address_t>(_dyld_get_image_header(index)));
 
+    bool expect_timestamp;
     if (index == 0) {
       // dyld didn’t load the main executable, so it couldn’t record its
       // timestamp, and it is reported as 0.
       EXPECT_EQ(modules[index].timestamp, 0);
-    } else if (modules[index].reader->FileType() == MH_BUNDLE &&
-               modules[index].name == "cl_kernels") {
-      // cl_kernels doesn’t exist as a file.
-      EXPECT_EQ(modules[index].timestamp, 0);
+    } else if (IsMalformedCLKernelsModule(modules[index].reader->FileType(),
+                                          modules[index].name,
+                                          &expect_timestamp)) {
+      // cl_kernels doesn’t exist as a file, but may still have a timestamp.
+      if (!expect_timestamp) {
+        EXPECT_EQ(modules[index].timestamp, 0);
+      } else {
+        EXPECT_NE(modules[index].timestamp, 0);
+      }
       found_cl_kernels = true;
     } else {
       // Hope that the module didn’t change on disk.
@@ -747,14 +754,20 @@
       ASSERT_TRUE(modules[index].reader);
       EXPECT_EQ(modules[index].reader->Address(), expect_address);
 
+      bool expect_timestamp;
       if (index == 0 || index == modules.size() - 1) {
         // dyld didn’t load the main executable or itself, so it couldn’t record
         // these timestamps, and they are reported as 0.
         EXPECT_EQ(modules[index].timestamp, 0);
-      } else if (modules[index].reader->FileType() == MH_BUNDLE &&
-                 modules[index].name == "cl_kernels") {
-        // cl_kernels doesn’t exist as a file.
-        EXPECT_EQ(modules[index].timestamp, 0);
+      } else if (IsMalformedCLKernelsModule(modules[index].reader->FileType(),
+                                            modules[index].name,
+                                            &expect_timestamp)) {
+        // cl_kernels doesn’t exist as a file, but may still have a timestamp.
+        if (!expect_timestamp) {
+          EXPECT_EQ(modules[index].timestamp, 0);
+        } else {
+          EXPECT_NE(modules[index].timestamp, 0);
+        }
         found_cl_kernels = true;
       } else {
         // Hope that the module didn’t change on disk.
diff --git a/third_party/crashpad/crashpad/snapshot/minidump/process_snapshot_minidump.cc b/third_party/crashpad/crashpad/snapshot/minidump/process_snapshot_minidump.cc
index 90bfac54..652e0e4 100644
--- a/third_party/crashpad/crashpad/snapshot/minidump/process_snapshot_minidump.cc
+++ b/third_party/crashpad/crashpad/snapshot/minidump/process_snapshot_minidump.cc
@@ -31,6 +31,7 @@
       crashpad_info_(),
       annotations_simple_map_(),
       file_reader_(nullptr),
+      process_id_(static_cast<pid_t>(-1)),
       initialized_() {
 }
 
@@ -83,19 +84,19 @@
     stream_map_[stream_type] = &directory.Location;
   }
 
-  INITIALIZATION_STATE_SET_VALID(initialized_);
-
-  if (!InitializeCrashpadInfo()) {
+  if (!InitializeCrashpadInfo() ||
+      !InitializeMiscInfo() ||
+      !InitializeModules()) {
     return false;
   }
 
-  return InitializeModules();
+  INITIALIZATION_STATE_SET_VALID(initialized_);
+  return true;
 }
 
 pid_t ProcessSnapshotMinidump::ProcessID() const {
   INITIALIZATION_STATE_DCHECK_VALID(initialized_);
-  NOTREACHED();  // https://crashpad.chromium.org/bug/10
-  return 0;
+  return process_id_;
 }
 
 pid_t ProcessSnapshotMinidump::ParentProcessID() const {
@@ -234,6 +235,45 @@
       &annotations_simple_map_);
 }
 
+bool ProcessSnapshotMinidump::InitializeMiscInfo() {
+  const auto& stream_it = stream_map_.find(kMinidumpStreamTypeMiscInfo);
+  if (stream_it == stream_map_.end()) {
+    return true;
+  }
+
+  if (!file_reader_->SeekSet(stream_it->second->Rva)) {
+    return false;
+  }
+
+  const size_t size = stream_it->second->DataSize;
+  if (size != sizeof(MINIDUMP_MISC_INFO_5) &&
+      size != sizeof(MINIDUMP_MISC_INFO_4) &&
+      size != sizeof(MINIDUMP_MISC_INFO_3) &&
+      size != sizeof(MINIDUMP_MISC_INFO_2) &&
+      size != sizeof(MINIDUMP_MISC_INFO)) {
+    LOG(ERROR) << "misc_info size mismatch";
+    return false;
+  }
+
+  MINIDUMP_MISC_INFO_5 info;
+  if (!file_reader_->ReadExactly(&info, size)) {
+    return false;
+  }
+
+  switch (stream_it->second->DataSize) {
+    case sizeof(MINIDUMP_MISC_INFO_5):
+    case sizeof(MINIDUMP_MISC_INFO_4):
+    case sizeof(MINIDUMP_MISC_INFO_3):
+    case sizeof(MINIDUMP_MISC_INFO_2):
+    case sizeof(MINIDUMP_MISC_INFO):
+      // TODO(jperaza): Save the remaining misc info.
+      // https://crashpad.chromium.org/bug/10
+      process_id_ = info.ProcessId;
+  }
+
+  return true;
+}
+
 bool ProcessSnapshotMinidump::InitializeModules() {
   const auto& stream_it = stream_map_.find(kMinidumpStreamTypeModuleList);
   if (stream_it == stream_map_.end()) {
diff --git a/third_party/crashpad/crashpad/snapshot/minidump/process_snapshot_minidump.h b/third_party/crashpad/crashpad/snapshot/minidump/process_snapshot_minidump.h
index 211805e..9ba5d9c 100644
--- a/third_party/crashpad/crashpad/snapshot/minidump/process_snapshot_minidump.h
+++ b/third_party/crashpad/crashpad/snapshot/minidump/process_snapshot_minidump.h
@@ -92,6 +92,10 @@
       std::map<uint32_t, MINIDUMP_LOCATION_DESCRIPTOR>*
           module_crashpad_info_links);
 
+  // Initializes data carried in a MINIDUMP_MISC_INFO structure on behalf of
+  // Initialize().
+  bool InitializeMiscInfo();
+
   MINIDUMP_HEADER header_;
   std::vector<MINIDUMP_DIRECTORY> stream_directory_;
   std::map<MinidumpStreamType, const MINIDUMP_LOCATION_DESCRIPTOR*> stream_map_;
@@ -100,6 +104,7 @@
   MinidumpCrashpadInfo crashpad_info_;
   std::map<std::string, std::string> annotations_simple_map_;
   FileReaderInterface* file_reader_;  // weak
+  pid_t process_id_;
   InitializationStateDcheck initialized_;
 
   DISALLOW_COPY_AND_ASSIGN(ProcessSnapshotMinidump);
diff --git a/third_party/crashpad/crashpad/snapshot/minidump/process_snapshot_minidump_test.cc b/third_party/crashpad/crashpad/snapshot/minidump/process_snapshot_minidump_test.cc
index 82e14a7a..ed17939 100644
--- a/third_party/crashpad/crashpad/snapshot/minidump/process_snapshot_minidump_test.cc
+++ b/third_party/crashpad/crashpad/snapshot/minidump/process_snapshot_minidump_test.cc
@@ -420,6 +420,38 @@
   EXPECT_EQ(annotation_objects, annotations_4);
 }
 
+TEST(ProcessSnapshotMinidump, ProcessID) {
+  StringFile string_file;
+
+  MINIDUMP_HEADER header = {};
+  ASSERT_TRUE(string_file.Write(&header, sizeof(header)));
+
+  static const pid_t kTestProcessId = 42;
+  MINIDUMP_MISC_INFO misc_info = {};
+  misc_info.SizeOfInfo = sizeof(misc_info);
+  misc_info.Flags1 = MINIDUMP_MISC1_PROCESS_ID;
+  misc_info.ProcessId = kTestProcessId;
+
+  MINIDUMP_DIRECTORY misc_directory = {};
+  misc_directory.StreamType = kMinidumpStreamTypeMiscInfo;
+  misc_directory.Location.DataSize = sizeof(misc_info);
+  misc_directory.Location.Rva = static_cast<RVA>(string_file.SeekGet());
+  ASSERT_TRUE(string_file.Write(&misc_info, sizeof(misc_info)));
+
+  header.StreamDirectoryRva = static_cast<RVA>(string_file.SeekGet());
+  ASSERT_TRUE(string_file.Write(&misc_directory, sizeof(misc_directory)));
+
+  header.Signature = MINIDUMP_SIGNATURE;
+  header.Version = MINIDUMP_VERSION;
+  header.NumberOfStreams = 1;
+  ASSERT_TRUE(string_file.SeekSet(0));
+  ASSERT_TRUE(string_file.Write(&header, sizeof(header)));
+
+  ProcessSnapshotMinidump process_snapshot;
+  ASSERT_TRUE(process_snapshot.Initialize(&string_file));
+  EXPECT_EQ(process_snapshot.ProcessID(), kTestProcessId);
+}
+
 }  // namespace
 }  // namespace test
 }  // namespace crashpad
diff --git a/third_party/crashpad/crashpad/snapshot/sanitized/process_snapshot_sanitized_test.cc b/third_party/crashpad/crashpad/snapshot/sanitized/process_snapshot_sanitized_test.cc
index 485ef87..cb413e3b 100644
--- a/third_party/crashpad/crashpad/snapshot/sanitized/process_snapshot_sanitized_test.cc
+++ b/third_party/crashpad/crashpad/snapshot/sanitized/process_snapshot_sanitized_test.cc
@@ -19,6 +19,7 @@
 #include "gtest/gtest.h"
 #include "test/multiprocess_exec.h"
 #include "util/file/file_io.h"
+#include "util/misc/address_sanitizer.h"
 #include "util/numeric/safe_assignment.h"
 
 #if defined(OS_LINUX) || defined(OS_ANDROID)
@@ -162,6 +163,23 @@
 
   // MemorySnapshot::Delegate
   bool MemorySnapshotDelegateRead(void* data, size_t size) override {
+#if defined(ADDRESS_SANITIZER) && (defined(OS_LINUX) || defined(OS_ANDROID))
+    // AddressSanitizer causes stack variables to be stored separately from the
+    // call stack.
+    auto addr_not_in_stack_range =
+        [](VMAddress addr, VMAddress stack_addr, VMSize stack_size) {
+          return addr < stack_addr || addr >= stack_addr + stack_size;
+        };
+    EXPECT_PRED3(addr_not_in_stack_range,
+                 addrs_.code_pointer_address,
+                 stack_->Address(),
+                 size);
+    EXPECT_PRED3(addr_not_in_stack_range,
+                 addrs_.string_address,
+                 stack_->Address(),
+                 size);
+    return true;
+#else
     size_t pointer_offset;
     if (!AssignIfInRange(&pointer_offset,
                          addrs_.code_pointer_address - stack_->Address())) {
@@ -192,6 +210,7 @@
       EXPECT_STREQ(string, kSensitiveStackData);
     }
     return true;
+#endif  // ADDRESS_SANITIZER && (OS_LINUX || OS_ANDROID)
   }
 
  private:
diff --git a/third_party/crashpad/crashpad/util/misc/capture_context_test.cc b/third_party/crashpad/crashpad/util/misc/capture_context_test.cc
index 1117789d..7f3890f1 100644
--- a/third_party/crashpad/crashpad/util/misc/capture_context_test.cc
+++ b/third_party/crashpad/crashpad/util/misc/capture_context_test.cc
@@ -60,12 +60,16 @@
                kReferencePC);
 #endif  // !defined(ADDRESS_SANITIZER)
 
-  // Declare sp and context_2 here because all local variables need to be
-  // declared before computing the stack pointer reference value, so that the
-  // reference value can be the lowest value possible.
-  uintptr_t sp;
+  const uintptr_t sp = StackPointerFromContext(context_1);
+
+  // Declare context_2 here because all local variables need to be declared
+  // before computing the stack pointer reference value, so that the reference
+  // value can be the lowest value possible.
   NativeCPUContext context_2;
 
+// AddressSanitizer on Linux causes stack variables to be stored separately from
+// the call stack.
+#if !defined(ADDRESS_SANITIZER) || (!defined(OS_LINUX) && !defined(OS_ANDROID))
   // The stack pointer reference value is the lowest address of a local variable
   // in this function. The captured program counter will be slightly less than
   // or equal to the reference stack pointer.
@@ -74,11 +78,11 @@
                         reinterpret_cast<uintptr_t>(&context_2)),
                std::min(reinterpret_cast<uintptr_t>(&pc),
                         reinterpret_cast<uintptr_t>(&sp)));
-  sp = StackPointerFromContext(context_1);
   EXPECT_PRED2([](uintptr_t actual,
                   uintptr_t reference) { return reference - actual < 768u; },
                sp,
                kReferenceSP);
+#endif  // !ADDRESS_SANITIZER || (!OS_LINUX && !OS_ANDROID)
 
   // Capture the context again, expecting that the stack pointer stays the same
   // and the program counter increases. Strictly speaking, there’s no guarantee
diff --git a/third_party/crashpad/crashpad/util/misc/metrics.h b/third_party/crashpad/crashpad/util/misc/metrics.h
index 3e9337a..8046497 100644
--- a/third_party/crashpad/crashpad/util/misc/metrics.h
+++ b/third_party/crashpad/crashpad/util/misc/metrics.h
@@ -77,6 +77,10 @@
     //!     server.
     kUploadFailed = 4,
 
+    //! \brief There was an error between accessing the report from the database
+    //!     and uploading it to the crash server.
+    kPrepareForUploadFailed = 5,
+
     //! \brief The number of values in this enumeration; not a valid value.
     kMaxValue
   };
diff --git a/third_party/tcmalloc/chromium/src/windows/addr2line-pdb.c b/third_party/tcmalloc/chromium/src/windows/addr2line-pdb.c
index 5c65a035..16bef1e3 100644
--- a/third_party/tcmalloc/chromium/src/windows/addr2line-pdb.c
+++ b/third_party/tcmalloc/chromium/src/windows/addr2line-pdb.c
@@ -35,9 +35,17 @@
  * c:\websymbols without asking.
  */
 
+#ifndef WIN32_LEAN_AND_MEAN
 #define WIN32_LEAN_AND_MEAN
+#endif
+
+#ifndef _CRT_SECURE_NO_WARNINGS
 #define _CRT_SECURE_NO_WARNINGS
+#endif
+
+#ifndef _CRT_SECURE_NO_DEPRECATE
 #define _CRT_SECURE_NO_DEPRECATE
+#endif
 
 #include <stdio.h>
 #include <stdlib.h>
@@ -93,7 +101,7 @@
 
   if (!SymInitialize(process, NULL, FALSE)) {
     error = GetLastError();
-    fprintf(stderr, "SymInitialize returned error : %d\n", error);
+    fprintf(stderr, "SymInitialize returned error : %lu\n", error);
     return 1;
   }
 
@@ -107,13 +115,13 @@
     strcat(search, ";" WEBSYM);
   } else {
     error = GetLastError();
-    fprintf(stderr, "SymGetSearchPath returned error : %d\n", error);
+    fprintf(stderr, "SymGetSearchPath returned error : %lu\n", error);
     rv = 1;                   /* An error, but not a fatal one */
     strcpy(search, WEBSYM);   /* Use a default value */
   }
   if (!SymSetSearchPath(process, search)) {
     error = GetLastError();
-    fprintf(stderr, "SymSetSearchPath returned error : %d\n", error);
+    fprintf(stderr, "SymSetSearchPath returned error : %lu\n", error);
     rv = 1;                   /* An error, but not a fatal one */
   }
 
@@ -122,7 +130,7 @@
   if (!module_base) {
     /* SymLoadModuleEx failed */
     error = GetLastError();
-    fprintf(stderr, "SymLoadModuleEx returned error : %d for %s\n",
+    fprintf(stderr, "SymLoadModuleEx returned error : %lu for %s\n",
             error, filename);
     SymCleanup(process);
     return 1;
diff --git a/tools/binary_size/libsupersize/html_report.py b/tools/binary_size/libsupersize/html_report.py
index e6bbb0e1..25cc18e5 100644
--- a/tools/binary_size/libsupersize/html_report.py
+++ b/tools/binary_size/libsupersize/html_report.py
@@ -27,6 +27,7 @@
 _COMPACT_SYMBOL_BYTE_SIZE_KEY = 'b'
 _COMPACT_SYMBOL_TYPE_KEY = 't'
 _COMPACT_SYMBOL_COUNT_KEY = 'u'
+_COMPACT_SYMBOL_FLAGS_KEY = 'f'
 
 _SMALL_SYMBOL_DESCRIPTIONS = {
   'b': 'Other small uninitialized data',
@@ -34,7 +35,6 @@
   'r': 'Other small readonly data',
   't': 'Other small code',
   'v': 'Other small vtable entries',
-  '*': 'Other small generated symbols',
   'x': 'Other small dex non-method entries',
   'm': 'Other small dex methods',
   'p': 'Other small locale pak entries',
@@ -49,8 +49,6 @@
   symbol_type = symbol.section
   if symbol.name.endswith('[vtable]'):
     symbol_type = _SYMBOL_TYPE_VTABLE
-  elif symbol.name.endswith(']'):
-    symbol_type = _SYMBOL_TYPE_GENERATED
   if symbol_type not in _SMALL_SYMBOL_DESCRIPTIONS:
     symbol_type = _SYMBOL_TYPE_OTHER
   return symbol_type
@@ -147,6 +145,8 @@
     # so this data is only included for methods.
     if is_dex_method and symbol_count != 1:
       symbol_entry[_COMPACT_SYMBOL_COUNT_KEY] = symbol_count
+    if symbol.flags:
+      symbol_entry[_COMPACT_SYMBOL_FLAGS_KEY] = symbol.flags
     file_node[_COMPACT_FILE_SYMBOLS_KEY].append(symbol_entry)
 
   for symbol in extra_symbols:
diff --git a/tools/binary_size/libsupersize/models.py b/tools/binary_size/libsupersize/models.py
index 3126088d..39107bd 100644
--- a/tools/binary_size/libsupersize/models.py
+++ b/tools/binary_size/libsupersize/models.py
@@ -138,6 +138,9 @@
 # which was removed by name normalization. Occurs when an AFDO profile is
 # supplied to the linker.
 FLAG_HOT = 128
+# Relevant for .text symbols. If a method has this flag, then it was run
+# according to the code coverage.
+FLAG_COVERED = 256
 
 
 DIFF_STATUS_UNCHANGED = 0
diff --git a/tools/binary_size/libsupersize/static/index.html b/tools/binary_size/libsupersize/static/index.html
index 9e176e1..d7c644a 100644
--- a/tools/binary_size/libsupersize/static/index.html
+++ b/tools/binary_size/libsupersize/static/index.html
@@ -34,6 +34,7 @@
             align-items: center;
         }
         .appbar-progress {
+            box-sizing: border-box;
             display: block;
             width: 100%;
             height: 4px;
@@ -140,6 +141,7 @@
         .icon {
             display: block;
             margin-right: 6px;
+            flex: none;
         }
 
         /** Tree nodes */
@@ -179,13 +181,13 @@
         .symbol-name {
             font-weight: 500;
             word-break: break-word;
-            flex: 1;
         }
 
         .count,
         .size,
         .percent {
-            margin-left: 16px;
+            margin-left: auto;
+            padding-left: 16px;
             text-align: right;
             color: #5f6368;
             white-space: nowrap;
@@ -200,6 +202,16 @@
             text-decoration: line-through;
         }
 
+        .highlight {
+            background: #feefc3;
+        }
+        .highlight-positive {
+            background: #ceead6;
+        }
+        .highlight-negative {
+            background: #fad2cf;
+        }
+
         .diff .size-header::after {
             content: " diff";
         }
@@ -220,6 +232,7 @@
 
 <body>
     <div class="scrim toggle-options" hidden></div>
+    <!-- App Toolbar -->
     <header class="appbar">
         <div class="appbar-inner">
             <h1 class="headline">Super Size Tiger View</h1>
@@ -234,7 +247,8 @@
                 </svg>
                 <span class="label-text">Upload data</span>
             </label>
-            <a href="https://chromium.googlesource.com/chromium/src/+/master/tools/binary_size/html_report_faq.md" class="icon-button" title="FAQ" id="faq">
+            <a href="https://chromium.googlesource.com/chromium/src/+/master/tools/binary_size/html_report_faq.md" class="icon-button"
+                title="FAQ" id="faq">
                 <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="#5f6368">
                     <path d="M11,18h2v-2h-2V18z M12,2C6.48,2,2,6.48,2,12s4.48,10,10,10s10-4.48,10-10S17.52,2,12,2z M12,20c-4.41,0-8-3.59-8-8
                             s3.59-8,8-8s8,3.59,8,8S16.41,20,12,20z M12,6c-2.21,0-4,1.79-4,4h2c0-1.1,0.9-2,2-2s2,0.9,2,2c0,2-3,1.75-3,5h2c0-2.25,3-2.5,3-5
@@ -264,7 +278,7 @@
         </div>
         <progress value="0" id="progress" class="appbar-progress"></progress>
     </header>
-    <link href="options.css" rel="stylesheet">
+    <!-- Options side panel -->
     <form id="options" class="options" method="GET">
         <header class="form-bar">
             <button type="button" class="icon-button toggle-options" title="Close">
@@ -319,9 +333,9 @@
                 <p class="input-error" id="include-error"></p>
             </div>
             <div class="input-wrapper">
-                <input class="input-regex" type="text" id="excluderegex" name="exclude" placeholder="\(.+\)"  aria-describedby="exclude-error">
+                <input class="input-regex" type="text" id="excluderegex" name="exclude" placeholder="\(.+\)" aria-describedby="exclude-error">
                 <label class="input-label" for="excluderegex">
-                        Symbols must exclude
+                    Symbols must exclude
                 </label>
                 <p class="input-error" id="exclude-error"></p>
             </div>
@@ -360,12 +374,6 @@
                 </label>
             </div>
             <div class="checkbox-wrapper">
-                <input type="checkbox" id="filtergen" name="type" value="*" checked>
-                <label class="checkbox-label" for="filtergen">
-                    Generated Symbols (typeinfo, thunks, etc)
-                </label>
-            </div>
-            <div class="checkbox-wrapper">
                 <input type="checkbox" id="filterdexnon" name="type" value="x" checked>
                 <label class="checkbox-label" for="filterdexnon">
                     Dex non-method entries
@@ -398,8 +406,34 @@
             <button type="button" class="text-button" id="type-all">Select all</button>
             <button type="button" class="text-button" id="type-none">Select none</button>
         </fieldset>
+
+        <fieldset id="highlight-container">
+            <legend class="subhead">Highlight symbols</legend>
+            <div class="radio-wrapper">
+                <input type="radio" id="clearhighlight" name="highlight" value="clear" checked>
+                <label class="radio-label" for="clearhighlight">None</label>
+            </div>
+            <div class="radio-wrapper">
+                <input type="radio" id="hothighlight" name="highlight" value="hot">
+                <label class="radio-label" for="hothighlight">Hot code</label>
+            </div>
+            <div class="radio-wrapper">
+                <input type="radio" id="generatedhighlight" name="highlight" value="generated">
+                <label class="radio-label" for="generatedhighlight">Generated files</label>
+            </div>
+            <div class="radio-wrapper">
+                <input type="radio" id="coveragehightlight" name="highlight" value="coverage">
+                <label class="radio-label" for="coveragehightlight">Code coverage</label>
+            </div>
+        </fieldset>
+
+        <div class="checkbox-wrapper">
+            <input type="checkbox" id="generatedfilter" name="generated_filter" value="on">
+            <label class="checkbox-label" for="generatedfilter">Show only generated files</label>
+        </div>
     </form>
     <div class="symbols">
+        <!-- Icons for symbols are stored here and cloned. -->
         <div hidden id="icons">
             <svg class="icon foldericon" height="24" width="24" fill="#5f6368">
                 <title>Directory</title>
@@ -449,11 +483,6 @@
                 <path d="M20,3H5C3.9,3,3,3.9,3,5v14c0,1.1,0.9,2,2,2h15c1.1,0,2-0.9,2-2V5C22,3.9,21.1,3,20,3z M20,5v3H5V5H20z M15,19h-5v-9h5V19z
                             M5,10h3v9H5V10z M17,19v-9h3v9H17z" />
             </svg>
-            <svg class="icon generatedicon" height="24" width="24" fill="#f439a0">
-                <title>Generated symbol</title>
-                <path d="M6 2a2 2 0 0 0-2 2v16c0 1.1.9 2 2 2h12a2 2 0 0 0 2-2V8l-6-6H6zm0 2h7v5h5v11H6V4zm9.5 8l-.6 1.4-1.4.6 1.4.6.6 1.4.6-1.4 1.4-.6-1.4-.6-.6-1.4zm-6 1l-1 2-2 1 2 1 1 2 1-2 2-1-2-1-1-2z"
-                />
-            </svg>
             <svg class="icon dexicon" height="24" width="24" fill="#ea4335">
                 <title>Dex non-method entry</title>
                 <path d="M6.6 1.44l-.82.83 2.1 2.1A6.96 6.96 0 0 0 5 10v1h14v-1a6.96 6.96 0 0 0-2.88-5.63l2.1-2.1-.82-.83-2.3 2.31a6.81 6.81 0 0 0-6.19 0L6.6 1.44zM9 7a1 1 0 0 1 1 1 1 1 0 0 1-1 1 1 1 0 0 1-1-1 1 1 0 0 1 1-1zm6 0a1 1 0 0 1 1 1 1 1 0 0 1-1 1 1 1 0 0 1-1-1 1 1 0 0 1 1-1zM5 12v4.27C5 20 8.17 23 12 23s7-3 7-6.73V12H5zm2 2h10v2.27c0 2.6-2.2 4.73-5 4.73s-5-2.13-5-4.73V14z"
@@ -480,6 +509,7 @@
                 />
             </svg>
         </div>
+        <!-- Template for trees and leaves -->
         <template id="treenode-container">
             <li role="treeitem" aria-expanded="false" aria-describedby="infocard-container">
                 <a class="node" href="#" tabindex="-1" role="presentation">
@@ -497,6 +527,7 @@
                 </span>
             </li>
         </template>
+        <!-- Tree view -->
         <main class="tree-container">
             <header class="tree-header">
                 <span class="subtitle">Name</span>
@@ -504,6 +535,7 @@
             </header>
             <ul id="symboltree" class="tree" role="tree" aria-labelledby="headline"></ul>
         </main>
+        <!-- Symbol and container breakdown cards -->
         <link href="infocard.css" rel="stylesheet">
         <footer class="infocards">
             <div class="infocard infocard-container open" id="infocard-container" hidden>
@@ -514,11 +546,12 @@
                 <header class="header-info">
                     <h4 class="subhead size-info"></h4>
                     <p class="body-2 path-info"></p>
-                    <p class="caption type-info"></p>
+                    <p class="caption type-info type-info-container"></p>
                 </header>
                 <table class="type-breakdown-info">
                     <thead>
                         <tr>
+                            <th class="subhead-2">Icon</th>
                             <th class="subhead-2">Type</th>
                             <th class="subhead-2 count">Count</th>
                             <th class="subhead-2 size">Total size</th>
@@ -527,66 +560,118 @@
                     </thead>
                     <tbody>
                         <tr class="bss-info">
+                            <td>
+                                <svg class="icon" viewBox="0 0 24 24" height="18" width="18" fill="#a142f4">
+                                    <path d="M6 2a2 2 0 0 0-2 2v16c0 1.1.9 2 2 2h12a2 2 0 0 0 2-2V8l-6-6H6zm0 2h7v5h5v11H6V4zm4 6v4h2v-4h-2zm0 6v2h2v-2h-2z"
+                                    />
+                                </svg>
+                            </td>
                             <th scope="row">.bss</th>
                             <td class="count"></td>
                             <td class="size"></td>
                             <td class="percent"></td>
                         </tr>
                         <tr class="data-info">
+                            <td>
+                                <svg class="icon" viewBox="0 0 24 24" height="18" width="18" fill="#fa7b17">
+                                    <path d="M6 2a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8l-6-6H6m0 2h7v5h5v11H6V4m2 8v2h8v-2H8m0 4v2h5v-2z" />
+                                </svg>
+                            </td>
                             <th scope="row">.data and .data.*</th>
                             <td class="count"></td>
                             <td class="size"></td>
                             <td class="percent"></td>
                         </tr>
                         <tr class="rodata-info">
+                            <td>
+                                <svg class="icon" viewBox="0 0 24 24" height="18" width="18" fill="#24c1e0">
+                                    <path d="M6 2a2 2 0 0 0-2 2v16c0 1.1.9 2 2 2h12a2 2 0 0 0 2-2V8l-6-6H6zm0 2h7v5h5v11H6V4zm5.9 8c-2 0-3.7 1.2-4.4 3a4.7 4.7 0 0 0 8.8 0c-.7-1.8-2.4-3-4.4-3zm0 1a2 2 0 0 1 2 2 2 2 0 0 1-2 2 2 2 0 0 1-2-2 2 2 0 0 1 2-2zm0 .8a1.2 1.2 0 0 0-1.2 1.2 1.2 1.2 0 0 0 1.2 1.2 1.2 1.2 0 0 0 1.2-1.2 1.2 1.2 0 0 0-1.2-1.2z"
+                                    />
+                                </svg>
+                            </td>
                             <th scope="row">.rodata</th>
                             <td class="count"></td>
                             <td class="size"></td>
                             <td class="percent"></td>
                         </tr>
                         <tr class="text-info">
+                            <td>
+                                <svg class="icon" viewBox="0 0 24 24" height="18" width="18" fill="#1a73e8">
+                                    <path d="M9.4,16.6L4.8,12l4.6-4.6L8,6l-6,6l6,6L9.4,16.6z M14.6,16.6l4.6-4.6l-4.6-4.6L16,6l6,6l-6,6L14.6,16.6z" />
+                                </svg>
+                            </td>
                             <th scope="row">.text</th>
                             <td class="count"></td>
                             <td class="size"></td>
                             <td class="percent"></td>
                         </tr>
                         <tr class="vtable-info">
+                            <td>
+                                <svg class="icon" viewBox="0 0 24 24" height="18" width="18" fill="#fbbc04">
+                                    <path d="M20,3H5C3.9,3,3,3.9,3,5v14c0,1.1,0.9,2,2,2h15c1.1,0,2-0.9,2-2V5C22,3.9,21.1,3,20,3z M20,5v3H5V5H20z M15,19h-5v-9h5V19z
+                                                        M5,10h3v9H5V10z M17,19v-9h3v9H17z" />
+                                </svg>
+                            </td>
                             <th scope="row">Vtable entry</th>
                             <td class="count"></td>
                             <td class="size"></td>
                             <td class="percent"></td>
                         </tr>
-                        <tr class="gen-info">
-                            <th scope="row">Generated symbols</th>
-                            <td class="count"></td>
-                            <td class="size"></td>
-                            <td class="percent"></td>
-                        </tr>
                         <tr class="dexnon-info">
+                            <td>
+                                <svg class="icon" viewBox="0 0 24 24" height="18" width="18" fill="#ea4335">
+                                    <path d="M6.6 1.44l-.82.83 2.1 2.1A6.96 6.96 0 0 0 5 10v1h14v-1a6.96 6.96 0 0 0-2.88-5.63l2.1-2.1-.82-.83-2.3 2.31a6.81 6.81 0 0 0-6.19 0L6.6 1.44zM9 7a1 1 0 0 1 1 1 1 1 0 0 1-1 1 1 1 0 0 1-1-1 1 1 0 0 1 1-1zm6 0a1 1 0 0 1 1 1 1 1 0 0 1-1 1 1 1 0 0 1-1-1 1 1 0 0 1 1-1zM5 12v4.27C5 20 8.17 23 12 23s7-3 7-6.73V12H5zm2 2h10v2.27c0 2.6-2.2 4.73-5 4.73s-5-2.13-5-4.73V14z"
+                                    />
+                                </svg>
+                            </td>
                             <th scope="row">Dex non-method entries</th>
                             <td class="count"></td>
                             <td class="size"></td>
                             <td class="percent"></td>
                         </tr>
                         <tr class="dex-info">
+                            <td>
+                                <svg class="icon" viewBox="0 0 24 24" height="18" width="18" fill="#a50e0e">
+                                    <path d="M6.6 1.44l-.82.83 2.1 2.1A6.96 6.96 0 0 0 5 10v1h14v-1a6.96 6.96 0 0 0-2.88-5.63l2.1-2.1-.82-.83-2.3 2.31a6.81 6.81 0 0 0-6.19 0L6.6 1.44zM9 7a1 1 0 0 1 1 1 1 1 0 0 1-1 1 1 1 0 0 1-1-1 1 1 0 0 1 1-1zm6 0a1 1 0 0 1 1 1 1 1 0 0 1-1 1 1 1 0 0 1-1-1 1 1 0 0 1 1-1zM5 12v4.27C5 20 8.17 23 12 23s7-3 7-6.73V12H5zm2 2h10v2.27c0 2.6-2.2 4.73-5 4.73s-5-2.13-5-4.73V14z"
+                                    />
+                                </svg>
+                            </td>
                             <th scope="row">Dex methods</th>
                             <td class="count"></td>
                             <td class="size"></td>
                             <td class="percent"></td>
                         </tr>
                         <tr class="pak-info">
+                            <td>
+                                <svg class="icon" viewBox="0 0 24 24" height="18" width="18" fill="#34a853">
+                                    <path d="M5 3a2 2 0 0 0-2 2v14c0 1.1.9 2 2 2h14a2 2 0 0 0 2-2V5a2 2 0 0 0-2-2H5zm0 2h5v2h2V5h7v14H5V5zm7 2v2h2V7h-2zm0 2h-2v2h2V9zm0 2v2h2v-2h-2zm0 2h-2v2h2v-2zm0 2v2h2v-2h-2z"
+                                    />
+                                </svg>
+                            </td>
                             <th scope="row">Locale pak entries</th>
                             <td class="count"></td>
                             <td class="size"></td>
                             <td class="percent"></td>
                         </tr>
                         <tr class="paknon-info">
+                            <td>
+                                <svg class="icon" viewBox="0 0 24 24" height="18" width="18" fill="#0d652d">
+                                    <path d="M5 3a2 2 0 0 0-2 2v14c0 1.1.9 2 2 2h14a2 2 0 0 0 2-2V5a2 2 0 0 0-2-2H5zm0 2h5v2h2V5h7v14H5V5zm7 2v2h2V7h-2zm0 2h-2v2h2V9zm0 2v2h2v-2h-2zm0 2h-2v2h2v-2zm0 2v2h2v-2h-2z"
+                                    />
+                                </svg>
+                            </td>
                             <th scope="row">Non-locale pak entries</th>
                             <td class="count"></td>
                             <td class="size"></td>
                             <td class="percent"></td>
                         </tr>
                         <tr class="other-info">
+                            <td>
+                                <svg class="icon" viewBox="0 0 24 24" height="18" width="18" fill="#5f6368">
+                                    <path d="M10.88 2l-.85 1.36L4 13h6v-2H7.6l3.28-5.23L12.28 8h2.35l-3.75-6zM12 10v10h10V10H12zm2 2h6v6h-6v-6zM2.21 15A5.52 5.52 0 0 0 10 21.4v-2.45A3.48 3.48 0 0 1 7.5 20a3.48 3.48 0 0 1-3.15-5H2.2z"
+                                    />
+                                </svg>
+                            </td>
                             <th scope="row">Other entries</th>
                             <td class="count"></td>
                             <td class="size"></td>
@@ -596,14 +681,17 @@
                 </table>
             </div>
             <div class="infocard infocard-symbol" id="infocard-symbol" hidden>
-                    <div class="icon-info">
-                        <div></div>
-                    </div>
+                <div class="icon-info">
+                    <div></div>
+                </div>
                 <header class="header-info">
                     <h4 class="subhead size-info"></h4>
                     <p class="body-2 path-info"></p>
                 </header>
-                <p class="caption type-info"></p>
+                <p class="caption type-info-container">
+                    <span class="type-info"></span>
+                    <span class="flags-info"></span>
+                </p>
             </div>
         </footer>
     </div>
diff --git a/tools/binary_size/libsupersize/static/infocard-ui.js b/tools/binary_size/libsupersize/static/infocard-ui.js
index 7d04641..b244a04 100644
--- a/tools/binary_size/libsupersize/static/infocard-ui.js
+++ b/tools/binary_size/libsupersize/static/infocard-ui.js
@@ -14,6 +14,18 @@
 const displayInfocard = (() => {
   const _CANVAS_RADIUS = 40;
 
+  const _FLAG_LABELS = new Map([
+    [_FLAGS.ANONYMOUS, 'anon'],
+    [_FLAGS.STARTUP, 'startup'],
+    [_FLAGS.UNLIKELY, 'unlikely'],
+    [_FLAGS.REL, 'rel'],
+    [_FLAGS.REL_LOCAL, 'rel.loc'],
+    [_FLAGS.GENERATED_SOURCE, 'gen'],
+    [_FLAGS.CLONE, 'clone'],
+    [_FLAGS.HOT, 'hot'],
+    [_FLAGS.COVERAGE, 'covered'],
+  ]);
+
   class Infocard {
     /**
      * @param {string} id
@@ -26,7 +38,7 @@
       this._pathInfo = this._infocard.querySelector('.path-info');
       /** @type {HTMLDivElement} */
       this._iconInfo = this._infocard.querySelector('.icon-info');
-      /** @type {HTMLParagraphElement} */
+      /** @type {HTMLSpanElement} */
       this._typeInfo = this._infocard.querySelector('.type-info');
 
       /**
@@ -136,6 +148,12 @@
   }
 
   class SymbolInfocard extends Infocard {
+    constructor(id) {
+      super(id);
+      /** @type {HTMLSpanElement} */
+      this._flagsInfo = this._infocard.querySelector('.flags-info');
+    }
+
     /**
      * @param {SVGSVGElement} icon Icon to display
      */
@@ -144,6 +162,31 @@
       super._setTypeContent(icon);
       this._iconInfo.style.backgroundColor = color;
     }
+
+    /**
+     * Updates the DOM for the info card.
+     * @param {TreeNode} node
+     */
+    _updateInfocard(node) {
+      super._updateInfocard(node);
+      this._flagsInfo.textContent = this._flagsString(node);
+    }
+
+    /**
+     * Returns a string representing the flags in the node.
+     * @param {TreeNode} symbolNode
+     */
+    _flagsString(symbolNode) {
+      if (!symbolNode.flags) {
+        return '';
+      }
+
+      const flagsString = Array.from(_FLAG_LABELS)
+        .filter(([flag]) => hasFlag(flag, symbolNode))
+        .map(([, part]) => part)
+        .join(',');
+      return `{${flagsString}}`;
+    }
   }
 
   class ContainerInfocard extends Infocard {
@@ -162,7 +205,6 @@
         r: this._tableBody.querySelector('.rodata-info'),
         t: this._tableBody.querySelector('.text-info'),
         v: this._tableBody.querySelector('.vtable-info'),
-        '*': this._tableBody.querySelector('.gen-info'),
         x: this._tableBody.querySelector('.dexnon-info'),
         m: this._tableBody.querySelector('.dex-info'),
         p: this._tableBody.querySelector('.pak-info'),
@@ -272,7 +314,7 @@
      * @param {TreeNode} containerNode
      */
     _updateInfocard(containerNode) {
-      const extraRows = {...this._infoRows};
+      const extraRows = Object.assign({}, this._infoRows);
       const statsEntries = Object.entries(containerNode.childStats).sort(
         (a, b) => b[1].size - a[1].size
       );
diff --git a/tools/binary_size/libsupersize/static/infocard.css b/tools/binary_size/libsupersize/static/infocard.css
index 86f139b..02d3d26 100644
--- a/tools/binary_size/libsupersize/static/infocard.css
+++ b/tools/binary_size/libsupersize/static/infocard.css
@@ -78,7 +78,7 @@
 .symbol-name-info {
   font-weight: 500;
 }
-.type-info {
+.type-info-container {
   grid-area: type;
   margin-bottom: 0;
 }
diff --git a/tools/binary_size/libsupersize/static/shared.js b/tools/binary_size/libsupersize/static/shared.js
index 6892a57..4e0ac18 100644
--- a/tools/binary_size/libsupersize/static/shared.js
+++ b/tools/binary_size/libsupersize/static/shared.js
@@ -23,6 +23,7 @@
  * @prop {number} size Byte size of this node and its children.
  * @prop {string} type Type of this node. If this node has children, the string
  * may have a second character to denote the most common child.
+ * @prop {number} flags
  * @prop {{[type: string]: {size:number,count:number}}} childStats Stats about
  * this node's descendants, organized by symbol type.
  */
@@ -57,6 +58,20 @@
   SIZE: /** @type {'b'} */ ('b'),
   TYPE: /** @type {'t'} */ ('t'),
   COUNT: /** @type {'u'} */ ('u'),
+  FLAGS: /** @type {'f'} */ ('f'),
+});
+
+/** Abberivated keys used by FileEntrys in the JSON data file. */
+const _FLAGS = Object.freeze({
+  ANONYMOUS: 2 ** 0,
+  STARTUP: 2 ** 1,
+  UNLIKELY: 2 ** 2,
+  REL: 2 ** 3,
+  REL_LOCAL: 2 ** 4,
+  GENERATED_SOURCE: 2 ** 5,
+  CLONE: 2 ** 6,
+  HOT: 2 ** 7,
+  COVERAGE: 2 ** 8,
 });
 
 /**
@@ -69,8 +84,6 @@
   KiB: 1024 ** 1,
   B: 1024 ** 0,
 });
-/** Set of all byte units */
-const _BYTE_UNITS_SET = new Set(Object.keys(_BYTE_UNITS));
 
 /**
  * Special types used by containers, such as folders and files.
@@ -83,13 +96,15 @@
 };
 const _CONTAINER_TYPE_SET = new Set(Object.values(_CONTAINER_TYPES));
 
+/** Type for a code/.text symbol */
+const _CODE_SYMBOL_TYPE = 't';
 /** Type for a dex method symbol */
 const _DEX_METHOD_SYMBOL_TYPE = 'm';
 /** Type for an 'other' symbol */
 const _OTHER_SYMBOL_TYPE = 'o';
 
 /** Set of all known symbol types. Container types are not included. */
-const _SYMBOL_TYPE_SET = new Set('bdrtv*xmpP' + _OTHER_SYMBOL_TYPE);
+const _SYMBOL_TYPE_SET = new Set('bdrtvxmpP' + _OTHER_SYMBOL_TYPE);
 
 /** Name used by a directory created to hold symbols with no name. */
 const _NO_NAME = '(No path)';
@@ -133,9 +148,18 @@
 function debounce(func, wait) {
   /** @type {number} */
   let timeoutId;
-  function debounced (...args) {
+  function debounced(...args) {
     clearTimeout(timeoutId);
     timeoutId = setTimeout(() => func(...args), wait);
-  };
+  }
   return /** @type {any} */ (debounced);
 }
+
+/**
+ * Returns tree if a symbol has a certain bit flag
+ * @param {number} flag Bit flag from `_FLAGS`
+ * @param {TreeNode} symbolNode
+ */
+function hasFlag(flag, symbolNode) {
+  return (symbolNode.flags & flag) === flag;
+}
diff --git a/tools/binary_size/libsupersize/static/state.js b/tools/binary_size/libsupersize/static/state.js
index f0f1abf..531c600 100644
--- a/tools/binary_size/libsupersize/static/state.js
+++ b/tools/binary_size/libsupersize/static/state.js
@@ -68,44 +68,11 @@
   const state = Object.freeze({
     /**
      * Returns a string from the current query string state.
-     * Can optionally restrict valid values for the query.
-     * Values not present in the query will return null, or the default
-     * value if supplied.
      * @param {string} key
-     * @param {object} [options]
-     * @param {string} [options.default] Default to use if key is not present
-     * in the state
-     * @param {Set<string>} [options.valid] If provided, values must be in this
-     * set to be returned. Invalid values will return null or `defaultValue`.
      * @returns {string | null}
      */
-    get(key, options = {}) {
-      const [val = null] = state.getAll(key, {
-        default: options.default ? [options.default] : null,
-        valid: options.valid,
-      });
-      return val;
-    },
-    /**
-     * Returns all string values for a key from the current query string state.
-     * Can optionally provide default values used if there are no values.
-     * @param {string} key
-     * @param {object} [options]
-     * @param {string[]} [options.default] Default to use if key is not present
-     * in the state.
-     * @param {Set<string>} [options.valid] If provided, values must be in this
-     * set to be returned. Invalid values will be omitted.
-     * @returns {string[]}
-     */
-    getAll(key, options = {}) {
-      let vals = _filterParams.getAll(key);
-      if (options.valid != null) {
-        vals = vals.filter(val => options.valid.has(val));
-      }
-      if (options.default != null && vals.length === 0) {
-        vals = options.default;
-      }
-      return vals;
+    get(key) {
+      return _filterParams.get(key);
     },
     /**
      * Checks if a key is present in the query string state.
@@ -140,7 +107,7 @@
   });
 
   // Update form inputs to reflect the state from URL.
-  for (const element of form.elements) {
+  for (const element of Array.from(form.elements)) {
     if (element.name) {
       const input = /** @type {HTMLInputElement} */ (element);
       const values = _filterParams.getAll(input.name);
@@ -370,12 +337,15 @@
       };
     } else {
       const bytes = node.size;
-      const unit = state.get('byteunit', {
-        default: 'MiB',
-        valid: _BYTE_UNITS_SET,
-      });
+      let unit = state.get('byteunit');
+      let suffix = _BYTE_UNITS[unit];
+      if (suffix == null) {
+        unit = 'MiB';
+        suffix = _BYTE_UNITS.MiB;
+      }
+
       // Format the bytes as a number with 2 digits after the decimal point
-      const text = (bytes / _BYTE_UNITS[unit]).toLocaleString(_LOCALE, {
+      const text = (bytes / suffix).toLocaleString(_LOCALE, {
         minimumFractionDigits: 2,
         maximumFractionDigits: 2,
       });
diff --git a/tools/binary_size/libsupersize/static/tree-ui.js b/tools/binary_size/libsupersize/static/tree-ui.js
index 4ace63c..6720848 100644
--- a/tools/binary_size/libsupersize/static/tree-ui.js
+++ b/tools/binary_size/libsupersize/static/tree-ui.js
@@ -24,6 +24,9 @@
   const _treeTemplate = document.getElementById('treenode-container');
 
   const _symbolTree = document.getElementById('symboltree');
+  const _highlightRadio = document.getElementById('highlight-container');
+  /** @type {HTMLSelectElement} */
+  const _byteunitSelect = form.elements.namedItem('byteunit');
 
   /**
    * @type {HTMLCollectionOf<HTMLAnchorElement | HTMLSpanElement>}
@@ -45,12 +48,64 @@
   const _uiNodeData = new WeakMap();
 
   /**
+   * @type {{[mode:string]: (nameEl: HTMLSpanElement, node: TreeNode) => void}}
+   */
+  const _highlightActions = {
+    hot(symbolName, symbolNode) {
+      if (hasFlag(_FLAGS.HOT, symbolNode)) {
+        symbolName.classList.add('highlight');
+      }
+    },
+    generated(symbolName, symbolNode) {
+      if (hasFlag(_FLAGS.GENERATED_SOURCE, symbolNode)) {
+        symbolName.classList.add('highlight');
+      }
+    },
+    coverage(symbolName, symbolNode) {
+      if (symbolNode.type === _CODE_SYMBOL_TYPE) {
+        if (hasFlag(_FLAGS.COVERAGE, symbolNode)) {
+          symbolName.classList.add('highlight-positive');
+        } else {
+          symbolName.classList.add('highlight-negative');
+        }
+      }
+    },
+    reset(symbolName) {
+      symbolName.classList.remove('highlight');
+      symbolName.classList.remove('highlight-positive');
+      symbolName.classList.remove('highlight-negative');
+    },
+  };
+
+  /**
+   * Applies highlights to the tree element based on certain flags and state.
+   * @param {HTMLSpanElement} symbolNameElement
+   * @param {TreeNode} symbolNode
+   */
+  function _highlightSymbolName(symbolNameElement, symbolNode) {
+    const isDexMethod = symbolNode.type === _DEX_METHOD_SYMBOL_TYPE;
+    if (isDexMethod && state.has('method_count')) {
+      const {count = 0} = symbolNode.childStats[_DEX_METHOD_SYMBOL_TYPE] || {};
+      if (count < 0) {
+        symbolNameElement.classList.add('removed');
+      }
+    }
+
+    const hightlightFunc = _highlightActions[state.get('highlight')];
+    _highlightActions.reset(symbolNameElement, symbolNode);
+    if (hightlightFunc) {
+      hightlightFunc(symbolNameElement, symbolNode);
+    }
+  }
+
+  /**
    * Sets focus to a new tree element while updating the element that last had
    * focus. The tabindex property is used to avoid needing to tab through every
    * single tree item in the page to reach other areas.
    * @param {number | HTMLElement} el Index of tree node in `_liveNodeList`
    */
   function _focusTreeElement(el) {
+    /** @type {HTMLElement} */
     const lastFocused = document.activeElement;
     if (_uiNodeData.has(lastFocused)) {
       // Update DOM
@@ -86,7 +141,9 @@
 
       let data = _uiNodeData.get(link);
       if (data == null || data.children == null) {
-        const idPath = link.querySelector('.symbol-name').title;
+        /** @type {HTMLSpanElement} */
+        const symbolName = link.querySelector('.symbol-name');
+        const idPath = symbolName.title;
         data = await worker.openNode(idPath);
         _uiNodeData.set(link, data);
       }
@@ -95,7 +152,9 @@
       if (newElements.length === 1) {
         // Open the inner element if it only has a single child.
         // Ensures nodes like "java"->"com"->"google" are opened all at once.
-        newElements[0].querySelector('.node').click();
+        /** @type {HTMLAnchorElement | HTMLSpanElement} */
+        const link = newElements[0].querySelector('.node');
+        link.click();
       }
       const newElementsFragment = dom.createFragment(newElements);
 
@@ -185,7 +244,9 @@
             const groupList = link.parentElement.parentElement;
             if (groupList.getAttribute('role') === 'group') {
               event.preventDefault();
-              _focusTreeElement(groupList.previousElementSibling);
+              /** @type {HTMLAnchorElement} */
+              const parentLink = groupList.previousElementSibling;
+              _focusTreeElement(parentLink);
             }
           }
         }
@@ -292,13 +353,7 @@
       _ZERO_WIDTH_SPACE
     );
     symbolName.title = data.idPath;
-
-    if (state.has('method_count') && type === _DEX_METHOD_SYMBOL_TYPE) {
-      const {count = 0} = data.childStats[type] || {};
-      if (count < 0) {
-        symbolName.classList.add('removed');
-      }
-    }
+    _highlightSymbolName(symbolName, data);
 
     // Set the byte size and hover text
     _setSize(element.querySelector('.size'), data);
@@ -312,7 +367,7 @@
   }
 
   // When the `byteunit` state changes, update all .size elements in the page
-  form.elements.namedItem('byteunit').addEventListener('change', event => {
+  _byteunitSelect.addEventListener('change', event => {
     event.stopPropagation();
     state.set(event.currentTarget.name, event.currentTarget.value);
     // Update existing size elements with the new unit
@@ -321,6 +376,19 @@
       if (data) _setSize(sizeElement, data);
     }
   });
+  _highlightRadio.addEventListener('change', event => {
+    event.stopPropagation();
+    state.set(event.target.name, event.target.value);
+    // Update existing symbol elements
+    for (const link of _liveNodeList) {
+      const data = _uiNodeData.get(link);
+      if (data.children && data.children.length === 0) {
+        /** @type {HTMLSpanElement} */
+        const symbolName = link.querySelector('.symbol-name');
+        _highlightSymbolName(symbolName, data);
+      }
+    }
+  });
 
   _symbolTree.addEventListener('keydown', _handleKeyNavigation);
   _symbolTree.addEventListener('focusin', event => {
@@ -337,7 +405,7 @@
     }
   });
 
-  return newTreeElement
+  return newTreeElement;
 })();
 
 {
diff --git a/tools/binary_size/libsupersize/static/tree-worker.js b/tools/binary_size/libsupersize/static/tree-worker.js
index 0597776..5c9eef2 100644
--- a/tools/binary_size/libsupersize/static/tree-worker.js
+++ b/tools/binary_size/libsupersize/static/tree-worker.js
@@ -24,6 +24,7 @@
  * @prop {string} t Single character string to indicate the symbol type.
  * @prop {number} [u] Count value indicating how many symbols this entry
  * represents. Negative value when removed in a diff.
+ * @prop {number} [f] Bit flags, defaults to 0.
  */
 /**
  * @typedef {object} FileEntry JSON object representing a single file and its
@@ -82,7 +83,14 @@
  * @returns {TreeNode}
  */
 function createNode(options) {
-  const {idPath, type, shortNameIndex, size = 0, childStats = {}} = options;
+  const {
+    idPath,
+    type,
+    shortNameIndex,
+    size = 0,
+    flags = 0,
+    childStats = {},
+  } = options;
   return {
     children: [],
     parent: null,
@@ -91,6 +99,7 @@
     shortNameIndex,
     size,
     type,
+    flags,
   };
 }
 
@@ -143,13 +152,14 @@
 
     const additionalSize = node.size;
     const additionalStats = Object.entries(node.childStats);
+    const additionalFlags = node.flags;
 
     // Update the size and childStats of all ancestors
     while (node.parent != null) {
       const {parent} = node;
       const [containerType, lastBiggestType] = parent.type;
       let {size: lastBiggestSize = 0} =
-        parent.childStats[lastBiggestType] || {};
+          parent.childStats[lastBiggestType] || {};
       for (const [type, stat] of additionalStats) {
         const parentStat = parent.childStats[type] || {size: 0, count: 0};
 
@@ -165,6 +175,7 @@
       }
 
       parent.size += additionalSize;
+      parent.flags |= additionalFlags;
       node = parent;
     }
   }
@@ -257,15 +268,16 @@
       // If there is 1 child, include it so the UI doesn't need to make a
       // roundtrip in order to expand the chain.
       children = node.children
-          .map(n => TreeBuilder.formatNode(n, childDepth))
-          .sort(_compareFunc);
+        .map(n => TreeBuilder.formatNode(n, childDepth))
+        .sort(_compareFunc);
     }
 
-    return TreeBuilder._joinDexMethodClasses({
-      ...node,
-      children,
-      parent: null,
-    });
+    return TreeBuilder._joinDexMethodClasses(
+      Object.assign({}, node, {
+        children,
+        parent: null,
+      })
+    );
   }
 
   /**
@@ -344,7 +356,8 @@
         idPath: `${idPath}:${symbol[_KEYS.SYMBOL_NAME]}`,
         shortNameIndex: idPath.length + 1,
         size,
-        type: symbol[_KEYS.TYPE],
+        type,
+        flags: symbol[_KEYS.FLAGS] || 0,
         childStats: {[type]: {size, count}},
       });
 
@@ -548,6 +561,7 @@
 
   const groupBy = params.get('group_by') || 'source_path';
   const methodCountMode = params.has('method_count');
+  const filterGeneratedFiles = params.has('generated_filter');
 
   let minSymbolSize = Number(params.get('min_size'));
   if (Number.isNaN(minSymbolSize)) {
@@ -569,19 +583,28 @@
     }
   }
 
-  /** @type {Array<(symbolNode: TreeNode) => boolean>} */
+  /**
+   * @type {Array<(symbolNode: TreeNode) => boolean>} List of functions that
+   * check each symbol. If any returns false, the symbol will not be used.
+   */
   const filters = [];
 
-  /** Ensure symbol size is past the minimum */
+  // Ensure symbol size is past the minimum
   if (minSymbolSize > 0) {
     filters.push(s => Math.abs(s.size) >= minSymbolSize);
   }
 
-  /** Ensure the symbol size wasn't filtered out */
+  // Ensure the symbol size wasn't filtered out
   if (typeFilter.size < _SYMBOL_TYPE_SET.size) {
     filters.push(s => typeFilter.has(s.type));
   }
 
+  // Only show generated files
+  if (filterGeneratedFiles) {
+    filters.push(s => hasFlag(_FLAGS.GENERATED_SOURCE, s));
+  }
+
+  // Search symbol names using regex
   if (includeRegex) {
     try {
       const regex = new RegExp(includeRegex);
@@ -692,7 +715,7 @@
         const currentTime = Date.now();
         if (currentTime - lastBatchSent > 500) {
           postToUi();
-          await Promise.resolve();  // Pause loop to check for worker messages
+          await Promise.resolve(); // Pause loop to check for worker messages
           lastBatchSent = currentTime;
         }
       }
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl
index 14de8d2..933cca3 100644
--- a/tools/mb/mb_config.pyl
+++ b/tools/mb/mb_config.pyl
@@ -438,6 +438,7 @@
     },
 
     'chromium.webrtc': {
+      'Android Builder': 'android_debug_static_bot_arm64',
       'Linux Builder': 'release_bot_chrome_with_codecs',
       'Mac Builder': 'release_bot_chrome_with_codecs',
       'Win Builder': 'release_bot_x86_minimal_symbols_no_com_init_hooks_with_codecs',
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 57ab8ab2..8228f0f 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -504,6 +504,17 @@
   <int value="2" label="Failed (missing product details)"/>
 </enum>
 
+<enum name="AddIceCandidateResult">
+  <int value="0" label="Success"/>
+  <int value="1" label="Closed"/>
+  <int value="2" label="No remote description"/>
+  <int value="3" label="Null candidate"/>
+  <int value="4" label="Candidate not valid"/>
+  <int value="5" label="PeerConnection not ready"/>
+  <int value="6" label="Failed in addition"/>
+  <int value="7" label="Failed - not usable"/>
+</enum>
+
 <enum name="AddressFamily">
   <int value="0" label="Unspecified"/>
   <int value="1" label="IPv4"/>
@@ -8226,6 +8237,7 @@
   <int value="2" label="kUnexpectedTime"/>
   <int value="3" label="kDatabaseError"/>
   <int value="4" label="kUploadFailed"/>
+  <int value="5" label="kPrepareForUploadFailed"/>
 </enum>
 
 <enum name="CrashpadWinExceptionCodes">
@@ -19426,6 +19438,7 @@
   <int value="2513" label="V8RTCPeerConnection_AddTransceiver_Method"/>
   <int value="2514" label="V8RTCRtpTransceiver_Direction_AttributeGetter"/>
   <int value="2515" label="V8RTCRtpTransceiver_Direction_AttributeSetter"/>
+  <int value="2516" label="HTMLLinkElementDisabledByParser"/>
 </enum>
 
 <enum name="FeedbackSource">
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 29edf4c3..c28e1cd 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -112764,6 +112764,15 @@
   </summary>
 </histogram>
 
+<histogram name="WebRTC.PeerConnection.AddCandidate"
+    enum="AddIceCandidateResult" expires_after="M72">
+  <owner>hta@chromium.org</owner>
+  <summary>
+    Outcomes of adding ICE candidates to a PeerConnection. Used to check the
+    theory that failures in candidate addition are ignored by applications.
+  </summary>
+</histogram>
+
 <histogram name="WebRTC.PeerConnection.CandidatePairType"
     enum="IceCandidatePairTypes">
   <owner>guoweis@chromium.org</owner>
diff --git a/tools/perf/core/oauth_api.py b/tools/perf/core/oauth_api.py
deleted file mode 100644
index 88869e6..0000000
--- a/tools/perf/core/oauth_api.py
+++ /dev/null
@@ -1,38 +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.
-
-"""API for generating OAuth2 access tokens from service account
-keys predeployed to Chrome Ops bots via Puppet.
-"""
-
-import contextlib
-import os
-import subprocess
-import tempfile
-
-
-@contextlib.contextmanager
-def with_access_token(
-    service_account_json, prefix, token_expiration_in_minutes):
-  """Yields an access token for the service account.
-
-  Args:
-    service_account_json: The path to the service account JSON file.
-    prefix: the prefix of the token file
-    token_expiration_in_minutes: the integer expiration time of the token
-  """
-  fd, path = tempfile.mkstemp(suffix='.json', prefix=prefix)
-  try:
-    args = ['luci-auth', 'token']
-    if service_account_json:
-      args += ['-service-account-json', service_account_json]
-    args += ['-lifetime', '%im' % token_expiration_in_minutes]
-    subprocess.check_call(args, stdout=fd)
-    os.close(fd)
-    fd = None
-    yield path
-  finally:
-    if fd is not None:
-      os.close(fd)
-    os.remove(path)
diff --git a/tools/perf/core/results_dashboard.py b/tools/perf/core/results_dashboard.py
index 2d2d9a9..984882e2 100755
--- a/tools/perf/core/results_dashboard.py
+++ b/tools/perf/core/results_dashboard.py
@@ -34,10 +34,7 @@
 # The paths in the results dashboard URLs for sending results.
 SEND_RESULTS_PATH = '/add_point'
 SEND_HISTOGRAMS_PATH = '/add_histograms'
-
-
-ERROR_NO_OAUTH_TOKEN = (
-    'No oauth token provided, cannot upload HistogramSet. Discarding.')
+DEFAULT_TOKEN_TIMEOUT_IN_MINUTES = 30
 
 
 class SendResultException(Exception):
@@ -52,7 +49,22 @@
   pass
 
 
-def SendResults(data, url, send_as_histograms=False, oauth_token=None,
+def LuciAuthTokenGeneratorCallback(
+  service_account_file, token_expiration_in_minutes):
+  args = ['luci-auth', 'token',
+          '-service-account-json', service_account_file,
+          '-lifetime', '%im' % token_expiration_in_minutes]
+  p = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+  if p.wait() == 0:
+    return p.stdout.read()
+  else:
+    raise RuntimeError(
+        'Error generating authentication token.\nStdout: %s\nStder:%s' %
+        (p.stdout.read(), p.stderr.read()))
+
+
+def SendResults(data, url, send_as_histograms=False, service_account_file=None,
+                token_generator_callback=LuciAuthTokenGeneratorCallback,
                 num_retries=3):
   """Sends results to the Chrome Performance Dashboard.
 
@@ -62,18 +74,31 @@
     data: The data to try to send. Must be JSON-serializable.
     url: Performance Dashboard URL (including schema).
     send_as_histograms: True if result is to be sent to /add_histograms.
-    oauth_token: string; used for flushing oauth uploads from cache. Note that
-      client is responsible for making sure that the oauth_token doesn't expire
-      when using this API.
+    service_account_file: string; path to service account file which is used
+      for authenticating when upload data to perf dashboard.
+    token_generator_callback: a callback for generating the authentication token
+      to upload to perf dashboard.
+      This callback takes two parameters
+      (service_account_file, token_expiration_in_minutes) and returns the token
+      string.
+      If |token_generator_callback| is not specified, it's default to
+      LuciAuthTokenGeneratorCallback.
     num_retries: Number of times to retry uploading to the perf dashboard upon
       recoverable error.
   """
   start = time.time()
 
+  if send_as_histograms and not service_account_file:
+    raise ValueError(
+        'Must set a valid service_account_file for uploading histogram set '
+        'data')
+
   # Send all the results from this run and the previous cache to the
   # dashboard.
   errors, all_data_uploaded = _SendResultsToDashboard(
-      data, url, oauth_token, is_histogramset=send_as_histograms,
+      data, url, is_histogramset=send_as_histograms,
+      service_account_file=service_account_file,
+      token_generator_callback=token_generator_callback,
       num_retries=num_retries)
 
   print 'Time spent sending results to %s: %s' % (url, time.time() - start)
@@ -85,15 +110,12 @@
 
 
 def _SendResultsToDashboard(
-    dashboard_data, url, oauth_token, is_histogramset, num_retries):
+    dashboard_data, url, is_histogramset, service_account_file,
+    token_generator_callback, num_retries):
   """Tries to send perf dashboard data to |url|.
 
   Args:
-    perf_results_file_path: A file name.
-    url: The instance URL to which to post results.
-    oauth_token: An oauth token to use for histogram uploads. Might be None.
-    num_retries: Number of time to retry uploading to the perf dashboard upon
-      recoverable error.
+    See arguments in SendResults method above.
 
   Returns:
     A tuple (errors, all_data_uploaded), whereas:
@@ -107,26 +129,26 @@
 
   data_type = ('histogram' if is_histogramset else 'chartjson')
 
+  dashboard_data_str = json.dumps(dashboard_data)
+
   for i in xrange(1, num_retries + 1):
     try:
       print 'Sending %s result to dashboard (attempt %i out of %i).' % (
           data_type, i, num_retries)
       if is_histogramset:
-        # TODO(eakuefner): Remove this discard logic once all bots use
-        # histograms.
-        if oauth_token is None:
-          raise SendResultsFatalException(ERROR_NO_OAUTH_TOKEN)
-
-        _SendHistogramJson(url, json.dumps(dashboard_data), oauth_token)
+        oauth_token = token_generator_callback(
+            service_account_file, DEFAULT_TOKEN_TIMEOUT_IN_MINUTES)
+        _SendHistogramJson(url, dashboard_data_str, oauth_token)
       else:
-        _SendResultsJson(url, json.dumps(dashboard_data))
+        # TODO(eakuefner): Remove this logic once all bots use histograms.
+        _SendResultsJson(url, dashboard_data_str)
       all_data_uploaded = True
       break
     except SendResultsRetryException as e:
       error = 'Error while uploading %s data: %s' % (data_type, str(e))
       errors.append(error)
     except SendResultsFatalException as e:
-      error = 'Error uploading %s data: %s' % (data_type, str(e))
+      error = 'Fatal error while uploading %s data: %s' % (data_type, str(e))
       errors.append(error)
       break
     except Exception:
@@ -477,10 +499,10 @@
     # A 500 is presented on an exception on the dashboard side, timeout,
     # exception, etc. The dashboard can also send back 400 and 403, we could
     # recover from 403 (auth error), but 400 is generally malformed data.
-    if response.status == 403:
-      raise SendResultsRetryException(traceback.format_exc())
-
-    if response.status != 200:
+    if response.status in (403, 500):
+      raise SendResultsRetryException('HTTP Response %d: %s' % (
+          response.status, response.reason))
+    elif response.status != 200:
       raise SendResultsFatalException('HTTP Response %d: %s' % (
           response.status, response.reason))
   except httplib2.HttpLib2Error:
diff --git a/tools/perf/core/results_dashboard_unittest.py b/tools/perf/core/results_dashboard_unittest.py
index 10213d7..a242a87 100644
--- a/tools/perf/core/results_dashboard_unittest.py
+++ b/tools/perf/core/results_dashboard_unittest.py
@@ -11,34 +11,38 @@
 class ResultsDashboardTest(unittest.TestCase):
 
   def setUp(self):
-    self.fake_oath = 'fake-oath'
+    self.fake_service = '/foo/bar/kingsman-service-account'
+    self.dummy_token_generator = lambda service_file, timeout: 'Arthur-Merlin'
     self.perf_data = {'foo': 1, 'bar': 2}
     self.dashboard_url = 'https://chromeperf.appspot.com'
 
   def testRetryForSendResultRetryException(self):
-    def raise_retry_exception(url, histogramset_json, oauth_token):
-      del url, histogramset_json, oauth_token  # unused
+    def raise_retry_exception(url, histogramset_json, service_account_file):
+      del url, histogramset_json, service_account_file  # unused
       raise results_dashboard.SendResultsRetryException('Should retry')
 
     with mock.patch('core.results_dashboard._SendHistogramJson',
                     side_effect=raise_retry_exception) as m:
       upload_result = results_dashboard.SendResults(
           self.perf_data, self.dashboard_url, send_as_histograms=True,
-          oauth_token=self.fake_oath, num_retries=5)
+          service_account_file=self.fake_service,
+          token_generator_callback=self.dummy_token_generator, num_retries=5)
       self.assertFalse(upload_result)
       self.assertEqual(m.call_count, 5)
 
   def testNoRetryForSendResultFatalException(self):
 
-    def raise_retry_exception(url, histogramset_json, oauth_token):
-      del url, histogramset_json, oauth_token  # unused
+    def raise_retry_exception(url, histogramset_json, service_account_file):
+      del url, histogramset_json, service_account_file  # unused
       raise results_dashboard.SendResultsFatalException('Do not retry')
 
     with mock.patch('core.results_dashboard._SendHistogramJson',
                     side_effect=raise_retry_exception) as m:
       upload_result =  results_dashboard.SendResults(
           self.perf_data, self.dashboard_url, send_as_histograms=True,
-          oauth_token=self.fake_oath, num_retries=5)
+          service_account_file=self.fake_service,
+          token_generator_callback=self.dummy_token_generator,
+          num_retries=5)
       self.assertFalse(upload_result)
       self.assertEqual(m.call_count, 1)
 
@@ -46,15 +50,17 @@
     with mock.patch('core.results_dashboard._SendHistogramJson') as m:
       upload_result = results_dashboard.SendResults(
           self.perf_data, self.dashboard_url, send_as_histograms=True,
-          oauth_token=self.fake_oath, num_retries=5)
+          service_account_file=self.fake_service,
+          token_generator_callback=self.dummy_token_generator,
+          num_retries=5)
       self.assertTrue(upload_result)
       self.assertEqual(m.call_count, 1)
 
   def testNoRetryAfterSucessfulSendResult(self):
     counter = [0]
     def raise_retry_exception_first_two_times(
-        url, histogramset_json, oauth_token):
-      del url, histogramset_json, oauth_token  # unused
+        url, histogramset_json, service_account_file):
+      del url, histogramset_json, service_account_file  # unused
       counter[0] += 1
       if counter[0] <= 2:
         raise results_dashboard.SendResultsRetryException('Please retry')
@@ -63,6 +69,8 @@
                     side_effect=raise_retry_exception_first_two_times) as m:
       upload_result = results_dashboard.SendResults(
           self.perf_data, self.dashboard_url, send_as_histograms=True,
-          oauth_token=self.fake_oath, num_retries=5)
+          service_account_file=self.fake_service,
+          token_generator_callback=self.dummy_token_generator,
+          num_retries=5)
       self.assertTrue(upload_result)
       self.assertEqual(m.call_count, 3)
diff --git a/tools/perf/core/upload_results_to_perf_dashboard.py b/tools/perf/core/upload_results_to_perf_dashboard.py
index 6133c8d..68e1bbd5 100755
--- a/tools/perf/core/upload_results_to_perf_dashboard.py
+++ b/tools/perf/core/upload_results_to_perf_dashboard.py
@@ -101,7 +101,7 @@
   parser.add_option('--git-revision')
   parser.add_option('--output-json-dashboard-url')
   parser.add_option('--send-as-histograms', action='store_true')
-  parser.add_option('--oauth-token-file')
+  parser.add_option('--service-account-file')
   return parser
 
 
@@ -115,11 +115,7 @@
   if not options.configuration_name or not options.results_url:
     parser.error('configuration_name and results_url are required.')
 
-  if options.oauth_token_file:
-    with open(options.oauth_token_file) as f:
-      oauth_token = f.readline()
-  else:
-    oauth_token = None
+  service_account_file = options.service_account_file or None
 
   if not options.perf_dashboard_machine_group:
     print 'Error: Invalid perf dashboard machine group'
@@ -148,7 +144,7 @@
         dashboard_json,
         options.results_url,
         send_as_histograms=options.send_as_histograms,
-        oauth_token=oauth_token):
+        service_account_file=service_account_file):
       return 1
   else:
     # The upload didn't fail since there was no data to upload.
diff --git a/tools/perf/process_perf_results.py b/tools/perf/process_perf_results.py
index 380e4970..3d279c3 100755
--- a/tools/perf/process_perf_results.py
+++ b/tools/perf/process_perf_results.py
@@ -16,7 +16,6 @@
 import time
 import uuid
 
-from core import oauth_api
 from core import path_util
 from core import upload_results_to_perf_dashboard
 from core import results_merger
@@ -64,7 +63,7 @@
 
 
 def _upload_perf_results(json_to_upload, name, configuration_name,
-    build_properties, oauth_file, output_json_file):
+    build_properties, service_account_file, output_json_file):
   """Upload the contents of result JSON(s) to the perf dashboard."""
   args= [
       '--buildername', build_properties['buildername'],
@@ -76,7 +75,7 @@
       '--got-revision-cp', build_properties['got_revision_cp'],
       '--got-v8-revision', build_properties['got_v8_revision'],
       '--got-webrtc-revision', build_properties['got_webrtc_revision'],
-      '--oauth-token-file', oauth_file,
+      '--service-account-file', service_account_file,
       '--output-json-file', output_json_file,
       '--perf-dashboard-machine-group', _GetMachineGroup(build_properties)
   ]
@@ -350,20 +349,15 @@
       results_filename = join(directories[0], 'perf_results.json')
 
     print 'Uploading perf results from %s benchmark' % benchmark_name
-    # We generate an oauth token for every benchmark upload in the event
-    # the token could time out, see crbug.com/854162
-    with oauth_api.with_access_token(
-        service_account_file, ('%s_tok' % benchmark_name),
-        token_expiration_in_minutes=30) as oauth_file:
-      with open(output_json_file, 'w') as oj:
-        upload_fail = _upload_perf_results(
-          results_filename,
-          benchmark_name, configuration_name, build_properties,
-          oauth_file, oj)
-        upload_end_time = time.time()
-        print_duration(('%s upload time' % (benchmark_name)),
-                       upload_begin_time, upload_end_time)
-        return (benchmark_name, upload_fail)
+    with open(output_json_file, 'w') as oj:
+      upload_fail = _upload_perf_results(
+        results_filename,
+        benchmark_name, configuration_name, build_properties,
+        service_account_file, oj)
+      upload_end_time = time.time()
+      print_duration(('%s upload time' % (benchmark_name)),
+                     upload_begin_time, upload_end_time)
+      return (benchmark_name, upload_fail)
   finally:
     shutil.rmtree(tmpfile_dir)
 
diff --git a/tools/perf/process_perf_results_unittest.py b/tools/perf/process_perf_results_unittest.py
index 8aaeb50..e4a74a841 100755
--- a/tools/perf/process_perf_results_unittest.py
+++ b/tools/perf/process_perf_results_unittest.py
@@ -8,7 +8,6 @@
 import sys
 import tempfile
 import json
-import contextlib
 import unittest
 
 from core import path_util
@@ -44,35 +43,22 @@
     self.task_output_dir = os.path.join(
         os.path.dirname(__file__), 'testdata', 'task_output_dir')
 
-    @contextlib.contextmanager
-    def mocked_with_access_token(service_account_json, append):
-      del service_account_json  # unused
-      test_token_file = os.path.join(self.test_dir, 'token-%s' % append)
-      with open(test_token_file, 'w') as f:
-        f.write('1234')
-      yield test_token_file
-
-    m1 = mock.patch('process_perf_results.oauth_api.with_access_token',
-                   side_effect=mocked_with_access_token)
+    m1 = mock.patch(
+        'process_perf_results.logdog_helper.text',
+        return_value = 'http://foo.link')
     m1.start()
     self.addCleanup(m1.stop)
 
     m2 = mock.patch(
-        'process_perf_results.logdog_helper.text',
-        return_value = 'http://foo.link')
+        'process_perf_results.logdog_helper.open_text',
+        return_value=_FakeLogdogStream())
     m2.start()
     self.addCleanup(m2.stop)
 
-    m3 = mock.patch(
-        'process_perf_results.logdog_helper.open_text',
-        return_value=_FakeLogdogStream())
+    m3 = mock.patch('core.results_dashboard.SendResults')
     m3.start()
     self.addCleanup(m3.stop)
 
-    m4 = mock.patch('core.results_dashboard.SendResults')
-    m4.start()
-    self.addCleanup(m4.stop)
-
 
   def tearDown(self):
     shutil.rmtree(self.test_dir)
diff --git a/ui/accessibility/platform/ax_platform_node_auralinux.cc b/ui/accessibility/platform/ax_platform_node_auralinux.cc
index b281f47..735e150 100644
--- a/ui/accessibility/platform/ax_platform_node_auralinux.cc
+++ b/ui/accessibility/platform/ax_platform_node_auralinux.cc
@@ -6,7 +6,12 @@
 
 #include <stdint.h>
 
+#include <memory>
+#include <string>
+#include <utility>
+
 #include "base/command_line.h"
+#include "base/strings/string_number_conversions.h"
 #include "base/strings/sys_string_conversions.h"
 #include "base/strings/utf_string_conversions.h"
 #include "ui/accessibility/ax_action_data.h"
@@ -306,7 +311,13 @@
 
 static AtkAttributeSet* ax_platform_node_auralinux_get_attributes(
     AtkObject* atk_object) {
-  return NULL;
+
+  ui::AXPlatformNodeAuraLinux* obj =
+      AtkObjectToAXPlatformNodeAuraLinux(atk_object);
+  if (!obj)
+    return nullptr;
+
+  return obj->GetAtkAttributes();
 }
 
 static AtkRole ax_platform_node_auralinux_get_role(AtkObject* atk_object) {
@@ -973,9 +984,13 @@
     case ax::mojom::Role::kAnnotation:
       return ATK_ROLE_PANEL;
     case ax::mojom::Role::kApplication:
-      // Don't use ATK_ROLE_APPLICATION, which is for top level app windows,
-      // not ARIA applications.
-      return ATK_ROLE_EMBEDDED;
+      // Only use ATK_ROLE_APPLICATION for elements with no parent, since it
+      // is only for top level app windows and not ARIA applications.
+      if (!GetParent()) {
+        return ATK_ROLE_APPLICATION;
+      } else {
+        return ATK_ROLE_EMBEDDED;
+      }
     case ax::mojom::Role::kArticle:
       return ATK_ROLE_ARTICLE;
     case ax::mojom::Role::kAudio:
@@ -1252,7 +1267,6 @@
                .empty() ||
           IsFocusedInputWithSuggestions()) {
         return ATK_ROLE_AUTOCOMPLETE;
-        ;
       }
       return ATK_ROLE_ENTRY;
     case ax::mojom::Role::kTextFieldWithComboBox:
@@ -1346,8 +1360,8 @@
     atk_state_set_add_state(atk_state_set, ATK_STATE_FOCUSED);
 }
 
-void AXPlatformNodeAuraLinux::GetAtkRelations(AtkRelationSet* atk_relation_set)
-{
+void AXPlatformNodeAuraLinux::GetAtkRelations(
+    AtkRelationSet* atk_relation_set) {
 }
 
 AXPlatformNodeAuraLinux::AXPlatformNodeAuraLinux()
@@ -1533,6 +1547,15 @@
   ATK_AURALINUX_RETURN_STRING(base::UTF16ToUTF8(action_verb));
 }
 
+AtkAttributeSet* AXPlatformNodeAuraLinux::GetAtkAttributes() const {
+  AtkAttributeSet* atk_attributes = nullptr;
+
+  atk_attributes = AddIntAttributeToAtkAttributeSet(
+      atk_attributes, ax::mojom::IntAttribute::kHierarchicalLevel, "level");
+
+  return atk_attributes;
+}
+
 // AtkDocumentHelpers
 
 const gchar* AXPlatformNodeAuraLinux::GetDocumentAttributeValue(
@@ -1549,6 +1572,17 @@
   return nullptr;
 }
 
+static AtkAttributeSet* PrependAtkAttributeToAtkAttributeSet(
+    AtkAttributeSet* attribute_set,
+    const char* name,
+    const char* value) {
+  AtkAttribute* attribute =
+      static_cast<AtkAttribute*>(g_malloc(sizeof(AtkAttribute)));
+  attribute->name = g_strdup(name);
+  attribute->value = g_strdup(value);
+  return g_slist_prepend(attribute_set, attribute);
+}
+
 AtkAttributeSet* AXPlatformNodeAuraLinux::GetDocumentAttributes() const {
   AtkAttributeSet* attribute_set = nullptr;
   const gchar* doc_attributes[] = {"DocType", "MimeType", "Title", "URI"};
@@ -1557,11 +1591,8 @@
   for (unsigned i = 0; i < G_N_ELEMENTS(doc_attributes); i++) {
     value = GetDocumentAttributeValue(doc_attributes[i]);
     if (value) {
-      AtkAttribute* attribute =
-          static_cast<AtkAttribute*>(g_malloc(sizeof(AtkAttribute)));
-      attribute->name = g_strdup(doc_attributes[i]);
-      attribute->value = g_strdup(value);
-      attribute_set = g_slist_prepend(attribute_set, attribute);
+      attribute_set = PrependAtkAttributeToAtkAttributeSet(
+          attribute_set, doc_attributes[i], value);
     }
   }
 
@@ -1601,4 +1632,17 @@
   }
 }
 
+AtkAttributeSet* AXPlatformNodeAuraLinux::AddIntAttributeToAtkAttributeSet(
+    AtkAttributeSet* attributes,
+    ax::mojom::IntAttribute attribute,
+    const char* atk_attribute) const {
+  int value;
+  if (GetIntAttribute(attribute, &value)) {
+    attributes = PrependAtkAttributeToAtkAttributeSet(
+        attributes, atk_attribute, base::IntToString(value).c_str());
+  }
+
+  return attributes;
+}
+
 }  // namespace ui
diff --git a/ui/accessibility/platform/ax_platform_node_auralinux.h b/ui/accessibility/platform/ax_platform_node_auralinux.h
index e0c31e92..e34398c 100644
--- a/ui/accessibility/platform/ax_platform_node_auralinux.h
+++ b/ui/accessibility/platform/ax_platform_node_auralinux.h
@@ -2,11 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef UI_ACCESSIBILITY_AX_PLATFORM_NODE_AURALINUX_H_
-#define UI_ACCESSIBILITY_AX_PLATFORM_NODE_AURALINUX_H_
+#ifndef UI_ACCESSIBILITY_PLATFORM_AX_PLATFORM_NODE_AURALINUX_H_
+#define UI_ACCESSIBILITY_PLATFORM_AX_PLATFORM_NODE_AURALINUX_H_
 
 #include <atk/atk.h>
 
+#include <string>
+
 #include "base/macros.h"
 #include "base/strings/utf_string_conversions.h"
 #include "ui/accessibility/ax_export.h"
@@ -57,6 +59,7 @@
   bool GrabFocus();
   bool DoDefaultAction();
   const gchar* GetDefaultActionName();
+  AtkAttributeSet* GetAtkAttributes() const;
 
   void SetExtentsRelativeToAtkCoordinateType(
       gint* x, gint* y, gint* width, gint* height,
@@ -71,6 +74,10 @@
 
   // Misc helpers
   void GetFloatAttributeInGValue(ax::mojom::FloatAttribute attr, GValue* value);
+  AtkAttributeSet* AddIntAttributeToAtkAttributeSet(
+      AtkAttributeSet* attributes,
+      ax::mojom::IntAttribute attribute,
+      const char* atk_attribute) const;
 
   // Event helpers
   void OnFocused();
@@ -124,4 +131,4 @@
 
 }  // namespace ui
 
-#endif  // UI_ACCESSIBILITY_AX_PLATFORM_NODE_AURALINUX_H_
+#endif  // UI_ACCESSIBILITY_PLATFORM_AX_PLATFORM_NODE_AURALINUX_H_
diff --git a/ui/accessibility/platform/ax_platform_node_auralinux_unittest.cc b/ui/accessibility/platform/ax_platform_node_auralinux_unittest.cc
index b9714a2b..eb4fd62 100644
--- a/ui/accessibility/platform/ax_platform_node_auralinux_unittest.cc
+++ b/ui/accessibility/platform/ax_platform_node_auralinux_unittest.cc
@@ -35,6 +35,44 @@
   AtkObject* GetRootAtkObject() { return AtkObjectFromNode(GetRootNode()); }
 };
 
+static void EnsureAtkObjectHasAttributeWithValue(
+    AtkObject* atk_object,
+    const gchar* attribute_name,
+    const gchar* attribute_value) {
+  AtkAttributeSet* attributes = atk_object_get_attributes(atk_object);
+  bool saw_attribute = false;
+
+  AtkAttributeSet* current = attributes;
+  while (current) {
+    AtkAttribute* attribute = static_cast<AtkAttribute*>(current->data);
+
+    if (0 == strcmp(attribute_name, attribute->name)) {
+      // Ensure that we only see this attribute once.
+      ASSERT_FALSE(saw_attribute);
+
+      EXPECT_STREQ(attribute_value, attribute->value);
+      saw_attribute = true;
+    }
+
+    current = current->next;
+  }
+
+  ASSERT_TRUE(saw_attribute);
+  atk_attribute_set_free(attributes);
+}
+
+static void EnsureAtkObjectDoesNotHaveAttribute(
+    AtkObject* atk_object,
+    const gchar* attribute_name) {
+  AtkAttributeSet* attributes = atk_object_get_attributes(atk_object);
+  AtkAttributeSet* current = attributes;
+  while (current) {
+    AtkAttribute* attribute = static_cast<AtkAttribute*>(current->data);
+    ASSERT_NE(0, strcmp(attribute_name, attribute->name));
+  }
+  atk_attribute_set_free(attributes);
+}
+
 //
 // AtkObject tests
 //
@@ -105,6 +143,7 @@
   AXNodeData root;
   root.id = 1;
   root.child_ids.push_back(2);
+  root.role = ax::mojom::Role::kApplication;
 
   AXNodeData child;
   child.id = 2;
@@ -112,6 +151,12 @@
   Init(root, child);
   AXNode* child_node = GetRootNode()->children()[0];
 
+  AtkObject* root_obj(AtkObjectFromNode(GetRootNode()));
+  ASSERT_TRUE(ATK_IS_OBJECT(root_obj));
+  g_object_ref(root_obj);
+  EXPECT_EQ(ATK_ROLE_APPLICATION, atk_object_get_role(root_obj));
+  g_object_unref(root_obj);
+
   child.role = ax::mojom::Role::kAlert;
   child_node->SetData(child);
   AtkObject* child_obj(AtkObjectFromNode(child_node));
@@ -135,6 +180,14 @@
   g_object_ref(child_obj);
   EXPECT_EQ(ATK_ROLE_CANVAS, atk_object_get_role(child_obj));
   g_object_unref(child_obj);
+
+  child.role = ax::mojom::Role::kApplication;
+  child_node->SetData(child);
+  child_obj = AtkObjectFromNode(child_node);
+  ASSERT_TRUE(ATK_IS_OBJECT(child_obj));
+  g_object_ref(child_obj);
+  EXPECT_EQ(ATK_ROLE_EMBEDDED, atk_object_get_role(child_obj));
+  g_object_unref(child_obj);
 }
 
 TEST_F(AXPlatformNodeAuraLinuxTest, TestAtkObjectState) {
@@ -244,6 +297,39 @@
   g_object_unref(root_obj);
 }
 
+TEST_F(AXPlatformNodeAuraLinuxTest, TestAtkObjectAttributes) {
+  AXNodeData root_data;
+  root_data.id = 1;
+
+  Init(root_data);
+
+  AXNode* root_node = GetRootNode();
+  AtkObject* root_atk_object(AtkObjectFromNode(root_node));
+  ASSERT_TRUE(ATK_IS_OBJECT(root_atk_object));
+  g_object_ref(root_atk_object);
+  EnsureAtkObjectDoesNotHaveAttribute(root_atk_object, "level");
+
+  root_data = AXNodeData();
+  root_data.id = 1;
+  root_data.AddIntAttribute(ax::mojom::IntAttribute::kHierarchicalLevel, 1);
+  root_node->SetData(root_data);
+  EnsureAtkObjectHasAttributeWithValue(root_atk_object, "level", "1");
+
+  root_data = AXNodeData();
+  root_data.id = 1;
+  root_data.AddIntAttribute(ax::mojom::IntAttribute::kHierarchicalLevel, 2);
+  root_node->SetData(root_data);
+  EnsureAtkObjectHasAttributeWithValue(root_atk_object, "level", "2");
+
+  root_data = AXNodeData();
+  root_data.id = 1;
+  root_data.AddIntAttribute(ax::mojom::IntAttribute::kHierarchicalLevel, 34);
+  root_node->SetData(root_data);
+  EnsureAtkObjectHasAttributeWithValue(root_atk_object, "level", "34");
+
+  g_object_unref(root_atk_object);
+}
+
 //
 // AtkComponent tests
 //
diff --git a/ui/compositor/compositor.cc b/ui/compositor/compositor.cc
index fe0f3230..4e471cb 100644
--- a/ui/compositor/compositor.cc
+++ b/ui/compositor/compositor.cc
@@ -433,16 +433,17 @@
   return host_->IsVisible();
 }
 
-bool Compositor::ScrollLayerTo(int layer_id, const gfx::ScrollOffset& offset) {
+bool Compositor::ScrollLayerTo(cc::ElementId element_id,
+                               const gfx::ScrollOffset& offset) {
   auto input_handler = host_->GetInputHandler();
-  return input_handler && input_handler->ScrollLayerTo(layer_id, offset);
+  return input_handler && input_handler->ScrollLayerTo(element_id, offset);
 }
 
-bool Compositor::GetScrollOffsetForLayer(int layer_id,
+bool Compositor::GetScrollOffsetForLayer(cc::ElementId element_id,
                                          gfx::ScrollOffset* offset) const {
   auto input_handler = host_->GetInputHandler();
   return input_handler &&
-         input_handler->GetScrollOffsetForLayer(layer_id, offset);
+         input_handler->GetScrollOffsetForLayer(element_id, offset);
 }
 
 void Compositor::SetAuthoritativeVSyncInterval(
diff --git a/ui/compositor/compositor.h b/ui/compositor/compositor.h
index fccba71..b3c7e5f 100644
--- a/ui/compositor/compositor.h
+++ b/ui/compositor/compositor.h
@@ -18,6 +18,7 @@
 #include "base/single_thread_task_runner.h"
 #include "base/time/time.h"
 #include "build/build_config.h"
+#include "cc/trees/element_id.h"
 #include "cc/trees/layer_tree_host_client.h"
 #include "cc/trees/layer_tree_host_single_thread_client.h"
 #include "components/viz/common/frame_sinks/begin_frame_args.h"
@@ -299,8 +300,9 @@
 
   // Gets or sets the scroll offset for the given layer in step with the
   // cc::InputHandler. Returns true if the layer is active on the impl side.
-  bool GetScrollOffsetForLayer(int layer_id, gfx::ScrollOffset* offset) const;
-  bool ScrollLayerTo(int layer_id, const gfx::ScrollOffset& offset);
+  bool GetScrollOffsetForLayer(cc::ElementId element_id,
+                               gfx::ScrollOffset* offset) const;
+  bool ScrollLayerTo(cc::ElementId element_id, const gfx::ScrollOffset& offset);
 
   // The "authoritative" vsync interval, if provided, will override interval
   // reported from 3D context. This is typically the value reported by a more
diff --git a/ui/compositor/layer.cc b/ui/compositor/layer.cc
index 64fba7f..9a6e9b7 100644
--- a/ui/compositor/layer.cc
+++ b/ui/compositor/layer.cc
@@ -983,7 +983,7 @@
   const Compositor* compositor = GetCompositor();
   gfx::ScrollOffset offset;
   if (compositor &&
-      compositor->GetScrollOffsetForLayer(cc_layer_->id(), &offset))
+      compositor->GetScrollOffsetForLayer(cc_layer_->element_id(), &offset))
     return offset;
   return cc_layer_->CurrentScrollOffset();
 }
@@ -991,7 +991,7 @@
 void Layer::SetScrollOffset(const gfx::ScrollOffset& offset) {
   Compositor* compositor = GetCompositor();
   bool scrolled_on_impl_side =
-      compositor && compositor->ScrollLayerTo(cc_layer_->id(), offset);
+      compositor && compositor->ScrollLayerTo(cc_layer_->element_id(), offset);
 
   if (!scrolled_on_impl_side)
     cc_layer_->SetScrollOffset(offset);
diff --git a/ui/events/blink/input_handler_proxy_unittest.cc b/ui/events/blink/input_handler_proxy_unittest.cc
index 25117194..0b54ce2 100644
--- a/ui/events/blink/input_handler_proxy_unittest.cc
+++ b/ui/events/blink/input_handler_proxy_unittest.cc
@@ -124,11 +124,12 @@
   cc::ScrollElasticityHelper* CreateScrollElasticityHelper() override {
     return NULL;
   }
-  bool GetScrollOffsetForLayer(int layer_id,
+  bool GetScrollOffsetForLayer(cc::ElementId element_id,
                                gfx::ScrollOffset* offset) override {
     return false;
   }
-  bool ScrollLayerTo(int layer_id, const gfx::ScrollOffset& offset) override {
+  bool ScrollLayerTo(cc::ElementId element_id,
+                     const gfx::ScrollOffset& offset) override {
     return false;
   }
 
diff --git a/ui/gfx/OWNERS b/ui/gfx/OWNERS
index 8fb8afb..128cf4c 100644
--- a/ui/gfx/OWNERS
+++ b/ui/gfx/OWNERS
@@ -22,6 +22,7 @@
 
 # Skia geometry helpers.
 per-file skia_util*=danakj@chromium.org
+per-file skia_paint_util*=danakj@chromium.org
 
 # GPU memory buffer and GpuFence interfaces.
 per-file gpu_fence*=reveman@chromium.org
diff --git a/ui/views/bubble/bubble_frame_view.cc b/ui/views/bubble/bubble_frame_view.cc
index 50fce2dd..530e809 100644
--- a/ui/views/bubble/bubble_frame_view.cc
+++ b/ui/views/bubble/bubble_frame_view.cc
@@ -272,6 +272,7 @@
                                !delegate->GetWindowTitle().empty());
     default_title_->SetText(delegate->GetWindowTitle());
   }  // custom_title_'s updates are handled by its creator.
+  Layout();
 }
 
 void BubbleFrameView::SizeConstraintsChanged() {}
diff --git a/ui/views/controls/menu/menu_config_mac.mm b/ui/views/controls/menu/menu_config_mac.mm
index b838f66..9093926 100644
--- a/ui/views/controls/menu/menu_config_mac.mm
+++ b/ui/views/controls/menu/menu_config_mac.mm
@@ -16,18 +16,18 @@
   // images linked from that bug.
   config->menu_horizontal_border_size = 0;
   config->submenu_horizontal_inset = 0;
-  config->minimum_text_item_height = 32;
-  config->minimum_container_item_height = 48;
+  config->minimum_text_item_height = 28;
+  config->minimum_container_item_height = 40;
   config->minimum_menu_width = 320;
   config->label_to_arrow_padding = 0;
   config->arrow_to_edge_padding = 16;
   config->check_width = 16;
   config->check_height = 16;
   config->arrow_width = 8;
-  config->separator_height = 17;
-  config->separator_lower_height = 9;
-  config->separator_upper_height = 9;
-  config->separator_spacing_height = 9;
+  config->separator_height = 9;
+  config->separator_lower_height = 4;
+  config->separator_upper_height = 4;
+  config->separator_spacing_height = 5;
   config->separator_thickness = 1;
   config->align_arrow_and_shortcut = true;
   config->use_outer_border = false;
diff --git a/ui/views/controls/scroll_view_unittest.cc b/ui/views/controls/scroll_view_unittest.cc
index 4da3917..bd84fa3 100644
--- a/ui/views/controls/scroll_view_unittest.cc
+++ b/ui/views/controls/scroll_view_unittest.cc
@@ -1654,8 +1654,9 @@
   EXPECT_TRUE(compositor);
 
   // But setting on the impl side should fail since the layer isn't committed.
-  int layer_id = container->layer()->cc_layer_for_testing()->id();
-  EXPECT_FALSE(compositor->ScrollLayerTo(layer_id, gfx::ScrollOffset(0, 0)));
+  cc::ElementId element_id =
+      container->layer()->cc_layer_for_testing()->element_id();
+  EXPECT_FALSE(compositor->ScrollLayerTo(element_id, gfx::ScrollOffset(0, 0)));
   EXPECT_EQ(gfx::ScrollOffset(0, offset.y()), test_api.CurrentOffset());
 
   WaitForCommit();
@@ -1663,13 +1664,13 @@
 
   // Upon commit, the impl side should report the same value too.
   gfx::ScrollOffset impl_offset;
-  EXPECT_TRUE(compositor->GetScrollOffsetForLayer(layer_id, &impl_offset));
+  EXPECT_TRUE(compositor->GetScrollOffsetForLayer(element_id, &impl_offset));
   EXPECT_EQ(gfx::ScrollOffset(0, offset.y()), impl_offset);
 
   // Now impl-side scrolling should work, and also update the ScrollView.
   offset.set_y(kDefaultHeight * 3);
   EXPECT_TRUE(
-      compositor->ScrollLayerTo(layer_id, gfx::ScrollOffset(0, offset.y())));
+      compositor->ScrollLayerTo(element_id, gfx::ScrollOffset(0, offset.y())));
   EXPECT_EQ(gfx::ScrollOffset(0, offset.y()), test_api.CurrentOffset());
 
   // Scroll via ScrollView API. Should be reflected on the impl side.
@@ -1677,7 +1678,7 @@
   scroll_view->contents()->ScrollRectToVisible(offset);
   EXPECT_EQ(gfx::ScrollOffset(0, offset.y()), test_api.CurrentOffset());
 
-  EXPECT_TRUE(compositor->GetScrollOffsetForLayer(layer_id, &impl_offset));
+  EXPECT_TRUE(compositor->GetScrollOffsetForLayer(element_id, &impl_offset));
   EXPECT_EQ(gfx::ScrollOffset(0, offset.y()), impl_offset);
 
   // Test horizontal scrolling.
@@ -1686,7 +1687,7 @@
   EXPECT_EQ(gfx::ScrollOffset(offset.x(), offset.y()),
             test_api.CurrentOffset());
 
-  EXPECT_TRUE(compositor->GetScrollOffsetForLayer(layer_id, &impl_offset));
+  EXPECT_TRUE(compositor->GetScrollOffsetForLayer(element_id, &impl_offset));
   EXPECT_EQ(gfx::ScrollOffset(offset.x(), offset.y()), impl_offset);
 }
 
diff --git a/ui/views/view_properties.cc b/ui/views/view_properties.cc
index d579a16..994fe8c 100644
--- a/ui/views/view_properties.cc
+++ b/ui/views/view_properties.cc
@@ -4,6 +4,7 @@
 
 #include "ui/views/view_properties.h"
 
+#include "ui/base/hit_test.h"
 #include "ui/gfx/geometry/insets.h"
 #include "ui/views/bubble/bubble_dialog_delegate.h"
 
@@ -19,6 +20,7 @@
 
 namespace views {
 
+DEFINE_UI_CLASS_PROPERTY_KEY(int, kHitTestComponentKey, HTNOWHERE);
 DEFINE_OWNED_UI_CLASS_PROPERTY_KEY(gfx::Insets, kMarginsKey, nullptr);
 DEFINE_UI_CLASS_PROPERTY_KEY(views::BubbleDialogDelegateView*,
                              kAnchoredDialogKey,
diff --git a/ui/views/view_properties.h b/ui/views/view_properties.h
index 4e706ec..2896ee9 100644
--- a/ui/views/view_properties.h
+++ b/ui/views/view_properties.h
@@ -16,6 +16,10 @@
 
 class BubbleDialogDelegateView;
 
+// The hit test component (e.g. HTCLIENT) for a View in a window frame. Defaults
+// to HTNOWHERE.
+VIEWS_EXPORT extern const ui::ClassProperty<int>* const kHitTestComponentKey;
+
 // A property to store margins around the outer perimeter of the view. Margins
 // are outside the bounds of the view. This is used by various layout managers
 // to position views with the proper spacing between them.
diff --git a/ui/views/widget/widget.cc b/ui/views/widget/widget.cc
index e4e7fc6..a4a01235 100644
--- a/ui/views/widget/widget.cc
+++ b/ui/views/widget/widget.cc
@@ -836,10 +836,6 @@
     return;
 
   non_client_view_->UpdateWindowTitle();
-
-  // If the non-client view is rendering its own title, it'll need to relayout
-  // now and to get a paint update later on.
-  non_client_view_->Layout();
 }
 
 void Widget::UpdateWindowIcon() {
diff --git a/ui/views/window/custom_frame_view.cc b/ui/views/window/custom_frame_view.cc
index 22d0bed..0ae8ebd 100644
--- a/ui/views/window/custom_frame_view.cc
+++ b/ui/views/window/custom_frame_view.cc
@@ -197,8 +197,12 @@
 }
 
 void CustomFrameView::UpdateWindowTitle() {
-  if (frame_->widget_delegate()->ShouldShowWindowTitle())
+  if (frame_->widget_delegate()->ShouldShowWindowTitle() &&
+      // If this is still unset, we haven't laid out window controls yet.
+      maximum_title_bar_x_ > -1) {
+    LayoutTitleBar();
     SchedulePaintInRect(title_bounds_);
+  }
 }
 
 void CustomFrameView::SizeConstraintsChanged() {
diff --git a/ui/wm/core/window_util.cc b/ui/wm/core/window_util.cc
index ec6ec57e..ed0f762 100644
--- a/ui/wm/core/window_util.cc
+++ b/ui/wm/core/window_util.cc
@@ -212,15 +212,31 @@
 void SnapWindowToPixelBoundary(aura::Window* window) {
   // TODO(malaykeshav): We want to snap each window layer to its parent window
   // layer. See https://crbug.com/863268 for more info.
-  window->SetProperty(wm::kSnapChildrenToPixelBoundary, true);
-  aura::Window* snapped_ancestor = window->parent();
-  while (snapped_ancestor) {
-    if (snapped_ancestor->GetProperty(wm::kSnapChildrenToPixelBoundary)) {
-      ui::SnapLayerToPhysicalPixelBoundary(snapped_ancestor->layer(),
+
+  // Root window is already snapped by default.
+  if (window->IsRootWindow()) {
+    window->SetProperty(wm::kSnapChildrenToPixelBoundary, true);
+    return;
+  }
+
+  aura::Window* ancestor_window = window->parent();
+  while (ancestor_window) {
+    bool is_ancestor_window_snapped =
+        ancestor_window->GetProperty(wm::kSnapChildrenToPixelBoundary);
+
+    // Root windows are already snapped by default. Just mark them as snapped.
+    if (ancestor_window->IsRootWindow() && !is_ancestor_window_snapped) {
+      ancestor_window->SetProperty(wm::kSnapChildrenToPixelBoundary, true);
+      is_ancestor_window_snapped = true;
+    }
+
+    if (is_ancestor_window_snapped) {
+      window->SetProperty(wm::kSnapChildrenToPixelBoundary, true);
+      ui::SnapLayerToPhysicalPixelBoundary(ancestor_window->layer(),
                                            window->layer());
       return;
     }
-    snapped_ancestor = snapped_ancestor->parent();
+    ancestor_window = ancestor_window->parent();
   }
 }
 
diff --git a/ui/wm/core/window_util_unittest.cc b/ui/wm/core/window_util_unittest.cc
index 10de1ca..c9e87e0 100644
--- a/ui/wm/core/window_util_unittest.cc
+++ b/ui/wm/core/window_util_unittest.cc
@@ -12,6 +12,7 @@
 #include "ui/aura/window.h"
 #include "ui/compositor/layer.h"
 #include "ui/compositor/layer_tree_owner.h"
+#include "ui/wm/core/window_properties.h"
 
 namespace wm {
 
@@ -99,4 +100,22 @@
   EXPECT_EQ(window12->layer(), window1->layer()->children()[1]);
 }
 
+// Test if the root window is always snapped.
+TEST_F(WindowUtilTest, CheckRootWindowAlwaysSnapped) {
+  std::unique_ptr<aura::Window> window11(
+      aura::test::CreateTestWindowWithId(1, root_window()));
+  std::unique_ptr<aura::Window> window12(
+      aura::test::CreateTestWindowWithId(2, root_window()));
+
+  EXPECT_TRUE(root_window()->IsRootWindow());
+
+  wm::SnapWindowToPixelBoundary(window12.get());
+
+  // Root window is always marked as snapped.
+  EXPECT_TRUE(root_window()->GetProperty(wm::kSnapChildrenToPixelBoundary));
+
+  EXPECT_TRUE(window12->GetProperty(wm::kSnapChildrenToPixelBoundary));
+  EXPECT_FALSE(window11->GetProperty(wm::kSnapChildrenToPixelBoundary));
+}
+
 }  // namespace wm