diff --git a/android_webview/browser/DEPS b/android_webview/browser/DEPS
index 487557a..1cce4b6a 100644
--- a/android_webview/browser/DEPS
+++ b/android_webview/browser/DEPS
@@ -53,6 +53,7 @@
 
   "+printing",
 
+  "+services/network/public/cpp",
   "+services/service_manager/public/cpp",
 
   "+storage/browser/quota",
diff --git a/android_webview/browser/aw_contents.cc b/android_webview/browser/aw_contents.cc
index 3f89e94..d8db2027 100644
--- a/android_webview/browser/aw_contents.cc
+++ b/android_webview/browser/aw_contents.cc
@@ -1155,8 +1155,9 @@
                               jlong duration_ms) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
-  float scale = browser_view_renderer_.dip_scale() *
-                browser_view_renderer_.page_scale_factor();
+  float scale = browser_view_renderer_.page_scale_factor();
+  if (!content::UseZoomForDSFEnabled())
+    scale *= browser_view_renderer_.dip_scale();
   render_view_host_ext_->SmoothScroll(target_x / scale, target_y / scale,
                                       duration_ms);
 }
diff --git a/android_webview/browser/browser_view_renderer.cc b/android_webview/browser/browser_view_renderer.cc
index 4052b973..e955e2f 100644
--- a/android_webview/browser/browser_view_renderer.cc
+++ b/android_webview/browser/browser_view_renderer.cc
@@ -361,17 +361,21 @@
   SkPictureRecorder recorder;
   SkCanvas* rec_canvas = recorder.beginRecording(width, height, NULL, 0);
   if (compositor_) {
+    gfx::Vector2dF scroll_offset =
+        content::UseZoomForDSFEnabled()
+            ? gfx::ScaleVector2d(scroll_offset_dip_, dip_scale_)
+            : scroll_offset_dip_;
     {
       // Reset scroll back to the origin, will go back to the old
       // value when scroll_reset is out of scope.
-      base::AutoReset<gfx::Vector2dF> scroll_reset(&scroll_offset_dip_,
+      base::AutoReset<gfx::Vector2dF> scroll_reset(&scroll_offset,
                                                    gfx::Vector2dF());
       compositor_->DidChangeRootLayerScrollOffset(
-          gfx::ScrollOffset(scroll_offset_dip_));
+          gfx::ScrollOffset(scroll_offset));
       CompositeSW(rec_canvas);
     }
     compositor_->DidChangeRootLayerScrollOffset(
-        gfx::ScrollOffset(scroll_offset_dip_));
+        gfx::ScrollOffset(scroll_offset));
   }
   return recorder.finishRecordingAsPicture();
 }
@@ -551,8 +555,12 @@
           FindCompositor(compositor_id)) {
     compositor_ = compositor;
     UpdateMemoryPolicy();
+    gfx::Vector2dF scroll_offset =
+        content::UseZoomForDSFEnabled()
+            ? gfx::ScaleVector2d(scroll_offset_dip_, dip_scale_)
+            : scroll_offset_dip_;
     compositor_->DidChangeRootLayerScrollOffset(
-        gfx::ScrollOffset(scroll_offset_dip_));
+        gfx::ScrollOffset(scroll_offset));
   } else {
     compositor_ = nullptr;
   }
@@ -609,8 +617,8 @@
                scroll_offset_dip.y());
 
   if (compositor_) {
-    compositor_->DidChangeRootLayerScrollOffset(
-        gfx::ScrollOffset(scroll_offset_dip_));
+    compositor_->DidChangeRootLayerScrollOffset(gfx::ScrollOffset(
+        content::UseZoomForDSFEnabled() ? scroll_offset : scroll_offset_dip_));
   }
 }
 
diff --git a/android_webview/browser/browser_view_renderer.h b/android_webview/browser/browser_view_renderer.h
index fa566ca..f68131c 100644
--- a/android_webview/browser/browser_view_renderer.h
+++ b/android_webview/browser/browser_view_renderer.h
@@ -226,11 +226,9 @@
 
   gfx::SizeF scrollable_size_dip_;
 
-  // Current scroll offset in CSS pixels.
   // TODO(miletus): Make scroll_offset_dip_ a gfx::ScrollOffset.
   gfx::Vector2dF scroll_offset_dip_;
 
-  // Max scroll offset in CSS pixels.
   // TODO(miletus): Make max_scroll_offset_dip_ a gfx::ScrollOffset.
   gfx::Vector2dF max_scroll_offset_dip_;
 
diff --git a/android_webview/browser/net/aw_url_request_context_getter.cc b/android_webview/browser/net/aw_url_request_context_getter.cc
index 76eb6fd7..21ef1725 100644
--- a/android_webview/browser/net/aw_url_request_context_getter.cc
+++ b/android_webview/browser/net/aw_url_request_context_getter.cc
@@ -63,6 +63,7 @@
 #include "net/url_request/url_request_context_builder.h"
 #include "net/url_request/url_request_intercepting_job_factory.h"
 #include "net/url_request/url_request_interceptor.h"
+#include "services/network/public/cpp/network_switches.h"
 
 using base::FilePath;
 using content::BrowserThread;
@@ -85,12 +86,12 @@
     net::MappedHostResolver* host_resolver) {
   const base::CommandLine& command_line =
       *base::CommandLine::ForCurrentProcess();
-  if (command_line.HasSwitch(switches::kHostResolverRules)) {
+  if (command_line.HasSwitch(network::switches::kHostResolverRules)) {
     // If hostname remappings were specified on the command-line, layer these
     // rules on top of the real host resolver. This allows forwarding all
     // requests through a designated test server.
-    host_resolver->SetRulesFromString(
-        command_line.GetSwitchValueASCII(switches::kHostResolverRules));
+    host_resolver->SetRulesFromString(command_line.GetSwitchValueASCII(
+        network::switches::kHostResolverRules));
   }
 }
 
@@ -235,10 +236,11 @@
   // always be truncated.
   const base::CommandLine& command_line =
       *base::CommandLine::ForCurrentProcess();
-  if (command_line.HasSwitch(switches::kLogNetLog)) {
+  if (command_line.HasSwitch(network::switches::kLogNetLog)) {
     FilePath net_log_path;
     PathService::Get(base::DIR_ANDROID_APP_DATA, &net_log_path);
-    FilePath log_name = command_line.GetSwitchValuePath(switches::kLogNetLog);
+    FilePath log_name =
+        command_line.GetSwitchValuePath(network::switches::kLogNetLog);
     net_log_path = net_log_path.Append(log_name);
 
     std::unique_ptr<base::DictionaryValue> constants_dict =
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/AndroidScrollIntegrationTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/AndroidScrollIntegrationTest.java
index 8531e73..2619b57 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/AndroidScrollIntegrationTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/AndroidScrollIntegrationTest.java
@@ -32,6 +32,7 @@
 import org.chromium.base.test.util.parameter.SkipCommandLineParameterization;
 import org.chromium.content_public.browser.GestureListenerManager;
 import org.chromium.content_public.browser.GestureStateListener;
+import org.chromium.content_public.common.UseZoomForDSFPolicy;
 import org.chromium.net.test.util.TestWebServer;
 import org.chromium.ui.display.DisplayAndroid;
 
@@ -45,6 +46,8 @@
  */
 @RunWith(AwJUnit4ClassRunner.class)
 public class AndroidScrollIntegrationTest {
+    private static final double EPSILON = 1e-5;
+
     @Rule
     public AwActivityTestRule mActivityTestRule = new AwActivityTestRule() {
         @Override
@@ -255,15 +258,18 @@
     }
 
     private void assertScrollInJs(final AwContents awContents,
-            final TestAwContentsClient contentsClient,
-            final int xCss, final int yCss) throws Exception {
+            final TestAwContentsClient contentsClient, final double xCss, final double yCss)
+            throws Exception {
         AwActivityTestRule.pollInstrumentationThread(() -> {
             String x = mActivityTestRule.executeJavaScriptAndWaitForResult(
                     awContents, contentsClient, "window.scrollX");
             String y = mActivityTestRule.executeJavaScriptAndWaitForResult(
                     awContents, contentsClient, "window.scrollY");
-            return (Integer.toString(xCss).equals(x)
-                    && Integer.toString(yCss).equals(y));
+
+            double scrollX = Double.parseDouble(x);
+            double scrollY = Double.parseDouble(y);
+
+            return Math.abs(xCss - scrollX) < EPSILON && Math.abs(yCss - scrollY) < EPSILON;
         });
     }
 
@@ -460,8 +466,12 @@
         // Make sure we can't hit these values simply as a result of scrolling.
         assert (maxScrollXPix % dragStepSize) != 0;
         assert (maxScrollYPix % dragStepSize) != 0;
-        final int maxScrollXCss = (int) Math.round(maxScrollXPix / deviceDIPScale);
-        final int maxScrollYCss = (int) Math.round(maxScrollYPix / deviceDIPScale);
+        double maxScrollXCss = maxScrollXPix / deviceDIPScale;
+        double maxScrollYCss = maxScrollYPix / deviceDIPScale;
+        if (!UseZoomForDSFPolicy.isUseZoomForDSFEnabled()) {
+            maxScrollXCss = Math.round(maxScrollXCss);
+            maxScrollYCss = Math.round(maxScrollYCss);
+        }
 
         setMaxScrollOnMainSync(testContainerView, maxScrollXPix, maxScrollYPix);
 
diff --git a/android_webview/renderer/aw_print_render_frame_helper_delegate.cc b/android_webview/renderer/aw_print_render_frame_helper_delegate.cc
index dfa8fd2..dbc4dd8 100644
--- a/android_webview/renderer/aw_print_render_frame_helper_delegate.cc
+++ b/android_webview/renderer/aw_print_render_frame_helper_delegate.cc
@@ -8,7 +8,9 @@
 
 namespace android_webview {
 
-AwPrintRenderFrameHelperDelegate::~AwPrintRenderFrameHelperDelegate() {}
+AwPrintRenderFrameHelperDelegate::AwPrintRenderFrameHelperDelegate() = default;
+
+AwPrintRenderFrameHelperDelegate::~AwPrintRenderFrameHelperDelegate() = default;
 
 bool AwPrintRenderFrameHelperDelegate::CancelPrerender(
     content::RenderFrame* render_frame) {
diff --git a/android_webview/renderer/aw_print_render_frame_helper_delegate.h b/android_webview/renderer/aw_print_render_frame_helper_delegate.h
index a17e831..5448f8aae 100644
--- a/android_webview/renderer/aw_print_render_frame_helper_delegate.h
+++ b/android_webview/renderer/aw_print_render_frame_helper_delegate.h
@@ -5,6 +5,7 @@
 #ifndef ANDROID_WEBVIEW_RENDERER_AW_PRINT_RENDER_FRAME_HELPER_DELEGATE_H_
 #define ANDROID_WEBVIEW_RENDERER_AW_PRINT_RENDER_FRAME_HELPER_DELEGATE_H_
 
+#include "base/macros.h"
 #include "components/printing/renderer/print_render_frame_helper.h"
 
 namespace android_webview {
@@ -12,6 +13,7 @@
 class AwPrintRenderFrameHelperDelegate
     : public printing::PrintRenderFrameHelper::Delegate {
  public:
+  AwPrintRenderFrameHelperDelegate();
   ~AwPrintRenderFrameHelperDelegate() override;
 
  private:
@@ -21,6 +23,8 @@
   bool IsPrintPreviewEnabled() override;
   bool IsScriptedPrintEnabled() override;
   bool OverridePrint(blink::WebLocalFrame* frame) override;
+
+  DISALLOW_COPY_AND_ASSIGN(AwPrintRenderFrameHelperDelegate);
 };
 
 }  // namespace android_webview
diff --git a/ash/BUILD.gn b/ash/BUILD.gn
index 4f0b48a..acb4f9f 100644
--- a/ash/BUILD.gn
+++ b/ash/BUILD.gn
@@ -576,8 +576,6 @@
     "system/power/backlights_forced_off_setter.h",
     "system/power/battery_notification.cc",
     "system/power/battery_notification.h",
-    "system/power/convertible_power_button_controller.cc",
-    "system/power/convertible_power_button_controller.h",
     "system/power/dual_role_notification.cc",
     "system/power/dual_role_notification.h",
     "system/power/peripheral_battery_notifier.cc",
@@ -588,8 +586,6 @@
     "system/power/power_button_display_controller.h",
     "system/power/power_button_screenshot_controller.cc",
     "system/power/power_button_screenshot_controller.h",
-    "system/power/power_button_util.cc",
-    "system/power/power_button_util.h",
     "system/power/power_event_observer.cc",
     "system/power/power_event_observer.h",
     "system/power/power_status.cc",
@@ -598,6 +594,8 @@
     "system/power/power_status_view.h",
     "system/power/scoped_backlights_forced_off.cc",
     "system/power/scoped_backlights_forced_off.h",
+    "system/power/tablet_power_button_controller.cc",
+    "system/power/tablet_power_button_controller.h",
     "system/power/tray_power.cc",
     "system/power/tray_power.h",
     "system/power/video_activity_notifier.cc",
@@ -1464,12 +1462,12 @@
     "system/palette/tools/metalayer_unittest.cc",
     "system/palette/tools/screenshot_unittest.cc",
     "system/power/backlights_forced_off_setter_unittest.cc",
-    "system/power/convertible_power_button_controller_unittest.cc",
     "system/power/peripheral_battery_notifier_unittest.cc",
     "system/power/power_button_screenshot_controller_unittest.cc",
     "system/power/power_event_observer_unittest.cc",
     "system/power/power_status_unittest.cc",
     "system/power/power_status_view_unittest.cc",
+    "system/power/tablet_power_button_controller_unittest.cc",
     "system/power/tray_power_unittest.cc",
     "system/power/video_activity_notifier_unittest.cc",
     "system/rotation/tray_rotation_lock_unittest.cc",
@@ -1789,12 +1787,12 @@
     "system/cast/tray_cast_test_api.h",
     "system/palette/palette_tray_test_api.cc",
     "system/palette/palette_tray_test_api.h",
-    "system/power/convertible_power_button_controller_test_api.cc",
-    "system/power/convertible_power_button_controller_test_api.h",
     "system/power/power_button_screenshot_controller_test_api.cc",
     "system/power/power_button_screenshot_controller_test_api.h",
     "system/power/power_button_test_base.cc",
     "system/power/power_button_test_base.h",
+    "system/power/tablet_power_button_controller_test_api.cc",
+    "system/power/tablet_power_button_controller_test_api.h",
     "system/status_area_widget_test_helper.cc",
     "system/status_area_widget_test_helper.h",
     "system/tray/system_tray_test_api.cc",
diff --git a/ash/app_list/app_list_presenter_delegate.cc b/ash/app_list/app_list_presenter_delegate.cc
index c263438..721cba6 100644
--- a/ash/app_list/app_list_presenter_delegate.cc
+++ b/ash/app_list/app_list_presenter_delegate.cc
@@ -32,32 +32,6 @@
 namespace ash {
 namespace {
 
-// Gets the point at the center of the display containing the given |window|.
-// This calculation excludes the virtual keyboard area. If the height of the
-// display area is less than |minimum_height|, its bottom will be extended to
-// that height (so that the app list never starts above the top of the screen).
-gfx::Point GetCenterOfDisplayForWindow(aura::Window* window,
-                                       int minimum_height) {
-  DCHECK(window);
-  gfx::Rect bounds = screen_util::GetDisplayBoundsWithShelf(window);
-  ::wm::ConvertRectToScreen(window->GetRootWindow(), &bounds);
-
-  // If the virtual keyboard is active, subtract it from the display bounds, so
-  // that the app list is centered in the non-keyboard area of the display.
-  // (Note that work_area excludes the keyboard, but it doesn't get updated
-  // until after this function is called.)
-  keyboard::KeyboardController* keyboard_controller =
-      keyboard::KeyboardController::GetInstance();
-  if (keyboard_controller)
-    bounds.Subtract(keyboard_controller->GetWorkspaceObscuringBounds());
-
-  // Apply the |minimum_height|.
-  if (bounds.height() < minimum_height)
-    bounds.set_height(minimum_height);
-
-  return bounds.CenterPoint();
-}
-
 // Whether the shelf is oriented on the side, not on the bottom.
 bool IsSideShelf(aura::Window* root_window) {
   Shelf* shelf = Shelf::ForWindow(root_window);
@@ -90,10 +64,6 @@
 
 AppListPresenterDelegate::~AppListPresenterDelegate() {
   DCHECK(view_);
-  keyboard::KeyboardController* keyboard_controller =
-      keyboard::KeyboardController::GetInstance();
-  if (keyboard_controller)
-    keyboard_controller->RemoveObserver(this);
   if (Shell::Get()->tablet_mode_controller())
     Shell::Get()->tablet_mode_controller()->RemoveObserver(this);
   Shell::Get()->RemovePreTargetHandler(this);
@@ -125,16 +95,8 @@
   params.is_side_shelf = IsSideShelf(root_window);
   view->Initialize(params);
 
-  if (!is_fullscreen_app_list_enabled_) {
-    view->MaybeSetAnchorPoint(GetCenterOfDisplayForWindow(
-        root_window, GetMinimumBoundsHeightForAppList(view)));
-  }
   wm::GetWindowState(view->GetWidget()->GetNativeWindow())
       ->set_ignored_by_shelf(true);
-  keyboard::KeyboardController* keyboard_controller =
-      keyboard::KeyboardController::GetInstance();
-  if (keyboard_controller)
-    keyboard_controller->AddObserver(this);
   Shell::Get()->AddPreTargetHandler(this);
 
   // By setting us as DnD recipient, the app list knows that we can
@@ -154,16 +116,6 @@
   is_visible_ = false;
 }
 
-void AppListPresenterDelegate::UpdateBounds() {
-  if (!view_ || !is_visible_)
-    return;
-
-  view_->UpdateBounds();
-  view_->MaybeSetAnchorPoint(
-      GetCenterOfDisplayForWindow(view_->GetWidget()->GetNativeWindow(),
-                                  GetMinimumBoundsHeightForAppList(view_)));
-}
-
 gfx::Vector2d AppListPresenterDelegate::GetVisibilityAnimationOffset(
     aura::Window* root_window) {
   DCHECK(Shell::HasInstance());
@@ -257,15 +209,6 @@
 }
 
 ////////////////////////////////////////////////////////////////////////////////
-// AppListPresenterDelegate, keyboard::KeyboardControllerObserver
-// implementation:
-
-void AppListPresenterDelegate::OnKeyboardWorkspaceOccludedBoundsChanging(
-    const gfx::Rect& new_bounds) {
-  UpdateBounds();
-}
-
-////////////////////////////////////////////////////////////////////////////////
 // AppListPresenterDelegate, ShellObserver implementation:
 void AppListPresenterDelegate::OnOverviewModeStarting() {
   if (is_visible_)
diff --git a/ash/app_list/app_list_presenter_delegate.h b/ash/app_list/app_list_presenter_delegate.h
index 3dc3f56..7ec509f 100644
--- a/ash/app_list/app_list_presenter_delegate.h
+++ b/ash/app_list/app_list_presenter_delegate.h
@@ -35,7 +35,6 @@
 class ASH_EXPORT AppListPresenterDelegate
     : public app_list::AppListPresenterDelegate,
       public ui::EventHandler,
-      public keyboard::KeyboardControllerObserver,
       public ShellObserver,
       public TabletModeObserver {
  public:
@@ -51,7 +50,6 @@
             int current_apps_page) override;
   void OnShown(int64_t display_id) override;
   void OnDismissed() override;
-  void UpdateBounds() override;
   gfx::Vector2d GetVisibilityAnimationOffset(
       aura::Window* root_window) override;
   base::TimeDelta GetVisibilityAnimationDuration(aura::Window* root_window,
@@ -64,10 +62,6 @@
   void OnMouseEvent(ui::MouseEvent* event) override;
   void OnGestureEvent(ui::GestureEvent* event) override;
 
-  // KeyboardControllerObserver overrides:
-  void OnKeyboardWorkspaceOccludedBoundsChanging(
-      const gfx::Rect& new_bounds) override;
-
   // ShellObserver overrides:
   void OnOverviewModeStarting() override;
 
diff --git a/ash/app_list/model/BUILD.gn b/ash/app_list/model/BUILD.gn
index 6c1a974..8a86493 100644
--- a/ash/app_list/model/BUILD.gn
+++ b/ash/app_list/model/BUILD.gn
@@ -49,25 +49,9 @@
   defines = [ "APP_LIST_MODEL_IMPLEMENTATION" ]
 
   deps = [
-    ":speech_ui_model",
     "//ash/public/cpp:cpp",
     "//base:i18n",
     "//ui/base",
     "//ui/gfx",
   ]
 }
-
-component("speech_ui_model") {
-  sources = [
-    "speech/speech_ui_model.cc",
-    "speech/speech_ui_model.h",
-    "speech/speech_ui_model_observer.h",
-  ]
-
-  defines = [ "APP_LIST_MODEL_IMPLEMENTATION" ]
-
-  deps = [
-    "//base",
-    "//ui/gfx",
-  ]
-}
diff --git a/ash/app_list/model/search/search_box_model.cc b/ash/app_list/model/search/search_box_model.cc
index b683ebd..9d9db819 100644
--- a/ash/app_list/model/search/search_box_model.cc
+++ b/ash/app_list/model/search/search_box_model.cc
@@ -12,36 +12,10 @@
 
 namespace app_list {
 
-namespace {
-
-std::unique_ptr<SearchBoxModel::SpeechButtonProperty> CreateNewProperty(
-    SpeechRecognitionState state) {
-  // Currently no speech support in app list.
-  // TODO(xiaohuic): when implementing speech support in new app list, we should
-  // either reuse this and related logic or delete them.
-  return nullptr;
-}
-
-}  // namespace
-
-SearchBoxModel::SpeechButtonProperty::SpeechButtonProperty(
-    const gfx::ImageSkia& icon,
-    const base::string16& tooltip,
-    const base::string16& accessible_name)
-    : icon(icon), tooltip(tooltip), accessible_name(accessible_name) {}
-
-SearchBoxModel::SpeechButtonProperty::~SpeechButtonProperty() = default;
-
 SearchBoxModel::SearchBoxModel() : is_tablet_mode_(false) {}
 
 SearchBoxModel::~SearchBoxModel() = default;
 
-void SearchBoxModel::SetSpeechRecognitionButton(SpeechRecognitionState state) {
-  speech_button_ = CreateNewProperty(state);
-  for (auto& observer : observers_)
-    observer.SpeechRecognitionButtonPropChanged();
-}
-
 void SearchBoxModel::SetHintText(const base::string16& hint_text) {
   if (hint_text_ == hint_text)
     return;
diff --git a/ash/app_list/model/search/search_box_model.h b/ash/app_list/model/search/search_box_model.h
index cdfc817..d8bc76c2 100644
--- a/ash/app_list/model/search/search_box_model.h
+++ b/ash/app_list/model/search/search_box_model.h
@@ -8,7 +8,6 @@
 #include <memory>
 
 #include "ash/app_list/model/app_list_model_export.h"
-#include "ash/app_list/model/speech/speech_ui_model_observer.h"
 #include "base/macros.h"
 #include "base/observer_list.h"
 #include "base/strings/string16.h"
@@ -26,29 +25,9 @@
 // text, cursor position and selected text in edit control.
 class APP_LIST_MODEL_EXPORT SearchBoxModel {
  public:
-  // The properties of the speech button.
-  struct APP_LIST_MODEL_EXPORT SpeechButtonProperty {
-    SpeechButtonProperty(const gfx::ImageSkia& icon,
-                         const base::string16& tooltip,
-                         const base::string16& accessible_name);
-    ~SpeechButtonProperty();
-
-    gfx::ImageSkia icon;
-    base::string16 tooltip;
-
-    // The accessibility name of the button.
-    base::string16 accessible_name;
-  };
-
   SearchBoxModel();
   ~SearchBoxModel();
 
-  // Sets/gets the properties for the button of speech recognition.
-  void SetSpeechRecognitionButton(SpeechRecognitionState state);
-  const SpeechButtonProperty* speech_button() const {
-    return speech_button_.get();
-  }
-
   // Sets/gets the hint text to display when there is in input.
   void SetHintText(const base::string16& hint_text);
   const base::string16& hint_text() const { return hint_text_; }
@@ -82,7 +61,6 @@
   void RemoveObserver(SearchBoxModelObserver* observer);
 
  private:
-  std::unique_ptr<SpeechButtonProperty> speech_button_;
   base::string16 hint_text_;
   base::string16 tablet_accessible_name_;
   base::string16 clamshell_accessible_name_;
diff --git a/ash/app_list/model/search/search_box_model_observer.h b/ash/app_list/model/search/search_box_model_observer.h
index 7a31642..5b7dbcf2 100644
--- a/ash/app_list/model/search/search_box_model_observer.h
+++ b/ash/app_list/model/search/search_box_model_observer.h
@@ -11,10 +11,6 @@
 
 class APP_LIST_MODEL_EXPORT SearchBoxModelObserver {
  public:
-  // Invoked when the some properties of the speech recognition button is
-  // changed.
-  virtual void SpeechRecognitionButtonPropChanged() = 0;
-
   // Invoked when hint text is changed.
   virtual void HintTextChanged() = 0;
 
diff --git a/ash/app_list/model/speech/speech_ui_model.cc b/ash/app_list/model/speech/speech_ui_model.cc
deleted file mode 100644
index 2c557e2..0000000
--- a/ash/app_list/model/speech/speech_ui_model.cc
+++ /dev/null
@@ -1,108 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ash/app_list/model/speech/speech_ui_model.h"
-
-#include <stdint.h>
-
-#include <algorithm>
-#include <limits>
-
-#include "ash/app_list/model/speech/speech_ui_model_observer.h"
-
-namespace app_list {
-
-namespace {
-
-// The default sound level, just gotten from the developer device.
-const int16_t kDefaultSoundLevel = 200;
-
-}  // namespace
-
-SpeechUIModel::SpeechUIModel()
-    : is_final_(false),
-      sound_level_(0),
-      state_(app_list::SPEECH_RECOGNITION_OFF),
-      minimum_sound_level_(kDefaultSoundLevel),
-      maximum_sound_level_(kDefaultSoundLevel) {}
-
-SpeechUIModel::~SpeechUIModel() {}
-
-void SpeechUIModel::SetSpeechResult(const base::string16& result,
-                                    bool is_final) {
-  if (result_ == result && is_final_ == is_final)
-    return;
-
-  result_ = result;
-  is_final_ = is_final;
-  for (auto& observer : observers_)
-    observer.OnSpeechResult(result, is_final);
-}
-
-void SpeechUIModel::UpdateSoundLevel(int16_t level) {
-  if (sound_level_ == level)
-    return;
-
-  sound_level_ = level;
-
-  // Tweak the sound level limits adaptively.
-  // - min is the minimum value during the speech recognition starts but speech
-  //   itself hasn't started.
-  // - max is the maximum value when the user speaks.
-  if (state_ == SPEECH_RECOGNITION_IN_SPEECH)
-    maximum_sound_level_ = std::max(level, maximum_sound_level_);
-  else
-    minimum_sound_level_ = std::min(level, minimum_sound_level_);
-
-  if (maximum_sound_level_ < minimum_sound_level_) {
-    maximum_sound_level_ = std::max(
-        static_cast<int16_t>(minimum_sound_level_ + kDefaultSoundLevel),
-        std::numeric_limits<int16_t>::max());
-  }
-
-  int16_t range = maximum_sound_level_ - minimum_sound_level_;
-  uint8_t visible_level = 0;
-  if (range > 0) {
-    int16_t visible_level_in_range = std::min(
-        std::max(minimum_sound_level_, sound_level_), maximum_sound_level_);
-    visible_level = (visible_level_in_range - minimum_sound_level_) *
-                    std::numeric_limits<uint8_t>::max() / range;
-  }
-
-  for (auto& observer : observers_)
-    observer.OnSpeechSoundLevelChanged(visible_level);
-}
-
-void SpeechUIModel::SetSpeechRecognitionState(SpeechRecognitionState new_state,
-                                              bool always_show_ui) {
-  // Don't show the speech view on a change to a network error or if the state
-  // has not changed, unless |always_show_ui| is true.
-  if (!always_show_ui &&
-      (state_ == new_state || new_state == SPEECH_RECOGNITION_NETWORK_ERROR)) {
-    state_ = new_state;
-    return;
-  }
-
-  state_ = new_state;
-
-  // Revert the min/max sound level to the default.
-  if (state_ != SPEECH_RECOGNITION_RECOGNIZING &&
-      state_ != SPEECH_RECOGNITION_IN_SPEECH) {
-    minimum_sound_level_ = kDefaultSoundLevel;
-    maximum_sound_level_ = kDefaultSoundLevel;
-  }
-
-  for (auto& observer : observers_)
-    observer.OnSpeechRecognitionStateChanged(new_state);
-}
-
-void SpeechUIModel::AddObserver(SpeechUIModelObserver* observer) {
-  observers_.AddObserver(observer);
-}
-
-void SpeechUIModel::RemoveObserver(SpeechUIModelObserver* observer) {
-  observers_.RemoveObserver(observer);
-}
-
-}  // namespace app_list
diff --git a/ash/app_list/model/speech/speech_ui_model.h b/ash/app_list/model/speech/speech_ui_model.h
deleted file mode 100644
index 2e2fa14db..0000000
--- a/ash/app_list/model/speech/speech_ui_model.h
+++ /dev/null
@@ -1,74 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef ASH_APP_LIST_MODEL_SPEECH_SPEECH_UI_MODEL_H_
-#define ASH_APP_LIST_MODEL_SPEECH_SPEECH_UI_MODEL_H_
-
-#include <stdint.h>
-
-#include "ash/app_list/model/app_list_model_export.h"
-#include "base/macros.h"
-#include "base/observer_list.h"
-#include "base/strings/string16.h"
-#include "ui/gfx/image/image_skia.h"
-
-namespace app_list {
-
-class SpeechUIModelObserver;
-
-enum SpeechRecognitionState {
-  SPEECH_RECOGNITION_OFF = 0,
-  SPEECH_RECOGNITION_READY,
-  SPEECH_RECOGNITION_RECOGNIZING,
-  SPEECH_RECOGNITION_IN_SPEECH,
-  SPEECH_RECOGNITION_STOPPING,
-  SPEECH_RECOGNITION_NETWORK_ERROR,
-};
-
-// SpeechUIModel provides the interface to update the UI for speech recognition.
-class APP_LIST_MODEL_EXPORT SpeechUIModel {
- public:
-  // Construct the model, initially in state SPEECH_RECOGNITION_OFF.
-  SpeechUIModel();
-  virtual ~SpeechUIModel();
-
-  void SetSpeechResult(const base::string16& result, bool is_final);
-  void UpdateSoundLevel(int16_t level);
-  // Sets the speech recognition state. If |always_show_ui| is true,
-  // sends the state change to the UI observers regardless of whether
-  // the |new_state| is different from the old one.
-  void SetSpeechRecognitionState(SpeechRecognitionState new_state,
-                                 bool always_show_ui);
-
-  void AddObserver(SpeechUIModelObserver* observer);
-  void RemoveObserver(SpeechUIModelObserver* observer);
-
-  const base::string16& result() const { return result_; }
-  bool is_final() const { return is_final_; }
-  int16_t sound_level() const { return sound_level_; }
-  SpeechRecognitionState state() const { return state_; }
-  const gfx::ImageSkia& logo() const { return logo_; }
-  void set_logo(const gfx::ImageSkia& logo) { logo_ = logo; }
-
- private:
-  base::string16 result_;
-  bool is_final_;
-  int16_t sound_level_;
-  SpeechRecognitionState state_;
-
-  // The logo image which the speech UI will show at the top-left.
-  gfx::ImageSkia logo_;
-
-  // The sound level range to compute visible sound-level.
-  int16_t minimum_sound_level_;
-  int16_t maximum_sound_level_;
-
-  base::ObserverList<SpeechUIModelObserver> observers_;
-
-  DISALLOW_COPY_AND_ASSIGN(SpeechUIModel);
-};
-
-}  // namespace app_list
-
-#endif  // ASH_APP_LIST_MODEL_SPEECH_SPEECH_UI_MODEL_H_
diff --git a/ash/app_list/model/speech/speech_ui_model_observer.h b/ash/app_list/model/speech/speech_ui_model_observer.h
deleted file mode 100644
index c688338..0000000
--- a/ash/app_list/model/speech/speech_ui_model_observer.h
+++ /dev/null
@@ -1,36 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef ASH_APP_LIST_MODEL_SPEECH_SPEECH_UI_MODEL_OBSERVER_H_
-#define ASH_APP_LIST_MODEL_SPEECH_SPEECH_UI_MODEL_OBSERVER_H_
-
-#include <stdint.h>
-
-#include "ash/app_list/model/app_list_model_export.h"
-#include "ash/app_list/model/speech/speech_ui_model.h"
-#include "base/strings/string16.h"
-
-namespace app_list {
-
-class APP_LIST_MODEL_EXPORT SpeechUIModelObserver {
- public:
-  // Invoked when sound level for the speech recognition has changed. |level|
-  // represents the current sound-level in the range of [0, 255].
-  virtual void OnSpeechSoundLevelChanged(uint8_t level) {}
-
-  // Invoked when a speech result arrives. |is_final| is true only when the
-  // speech result is final.
-  virtual void OnSpeechResult(const base::string16& result, bool is_final) {}
-
-  // Invoked when the state of speech recognition is changed.
-  virtual void OnSpeechRecognitionStateChanged(
-      SpeechRecognitionState new_state) {}
-
- protected:
-  virtual ~SpeechUIModelObserver() {}
-};
-
-}  // namespace app_list
-
-#endif  // ASH_APP_LIST_MODEL_SPEECH_SPEECH_UI_MODEL_OBSERVER_H_
diff --git a/ash/public/cpp/ash_switches.cc b/ash/public/cpp/ash_switches.cc
index 2d4ee22..d29c1c7 100644
--- a/ash/public/cpp/ash_switches.cc
+++ b/ash/public/cpp/ash_switches.cc
@@ -43,9 +43,9 @@
 const char kAshDisableTouchExplorationMode[] =
     "ash-disable-touch-exploration-mode";
 
-// Disables Backbutton on frame for v1 apps.
+// Enables Backbutton on frame for v1 apps.
 // TODO(oshima): Remove this once the feature is launched. crbug.com/749713.
-const char kAshDisableV1AppBackButton[] = "ash-disable-v1-app-back-button";
+const char kAshEnableV1AppBackButton[] = "ash-enable-v1-app-back-button";
 
 // Enables move window between displays accelerators.
 // TODO(warx): Remove this once the feature is launched. crbug.com/773749.
diff --git a/ash/public/cpp/ash_switches.h b/ash/public/cpp/ash_switches.h
index 0dc1a45..f504216 100644
--- a/ash/public/cpp/ash_switches.h
+++ b/ash/public/cpp/ash_switches.h
@@ -24,7 +24,7 @@
 ASH_PUBLIC_EXPORT extern const char kAshDisableSmoothScreenRotation[];
 ASH_PUBLIC_EXPORT extern const char kAshDisableTabletAutohideTitlebars[];
 ASH_PUBLIC_EXPORT extern const char kAshDisableTouchExplorationMode[];
-ASH_PUBLIC_EXPORT extern const char kAshDisableV1AppBackButton[];
+ASH_PUBLIC_EXPORT extern const char kAshEnableV1AppBackButton[];
 ASH_PUBLIC_EXPORT extern const char kAshEnableDisplayMoveWindowAccels[];
 ASH_PUBLIC_EXPORT extern const char kAshEnableKeyboardShortcutViewer[];
 ASH_PUBLIC_EXPORT extern const char kAshEnableMagnifierKeyScroller[];
diff --git a/ash/shell/app_list.cc b/ash/shell/app_list.cc
index 472dc07..f1fc7622 100644
--- a/ash/shell/app_list.cc
+++ b/ash/shell/app_list.cc
@@ -13,7 +13,6 @@
 #include "ash/app_list/model/search/search_box_model.h"
 #include "ash/app_list/model/search/search_model.h"
 #include "ash/app_list/model/search/search_result.h"
-#include "ash/app_list/model/speech/speech_ui_model.h"
 #include "ash/session/session_controller.h"
 #include "ash/shell.h"
 #include "ash/shell/example_factory.h"
@@ -228,8 +227,6 @@
     return search_model_.get();
   }
 
-  app_list::SpeechUIModel* GetSpeechUI() override { return &speech_ui_; }
-
   void OpenSearchResult(app_list::SearchResult* result,
                         int event_flags) override {
     const ExampleSearchResult* example_result =
@@ -279,15 +276,10 @@
     // Nothing needs to be done.
   }
 
-  void StartSpeechRecognition() override { NOTIMPLEMENTED(); }
-  void StopSpeechRecognition() override { NOTIMPLEMENTED(); }
-
   views::View* CreateStartPageWebView(const gfx::Size& size) override {
     return NULL;
   }
 
-  bool IsSpeechRecognitionEnabled() override { return false; }
-
   void GetWallpaperProminentColors(std::vector<SkColor>* colors) override {
     NOTIMPLEMENTED();
   }
@@ -315,7 +307,6 @@
 
   std::unique_ptr<app_list::AppListModel> model_;
   std::unique_ptr<app_list::SearchModel> search_model_;
-  app_list::SpeechUIModel speech_ui_;
 
   DISALLOW_COPY_AND_ASSIGN(ExampleAppListViewDelegate);
 };
diff --git a/ash/system/power/convertible_power_button_controller_test_api.cc b/ash/system/power/convertible_power_button_controller_test_api.cc
deleted file mode 100644
index 65f7f76..0000000
--- a/ash/system/power/convertible_power_button_controller_test_api.cc
+++ /dev/null
@@ -1,39 +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.
-
-#include "ash/system/power/convertible_power_button_controller_test_api.h"
-
-#include "ash/system/power/convertible_power_button_controller.h"
-#include "ash/system/power/power_button_display_controller.h"
-
-namespace ash {
-
-ConvertiblePowerButtonControllerTestApi::
-    ConvertiblePowerButtonControllerTestApi(
-        ConvertiblePowerButtonController* controller)
-    : controller_(controller) {}
-
-ConvertiblePowerButtonControllerTestApi::
-    ~ConvertiblePowerButtonControllerTestApi() = default;
-
-bool ConvertiblePowerButtonControllerTestApi::ShutdownTimerIsRunning() const {
-  return controller_->shutdown_timer_.IsRunning();
-}
-
-bool ConvertiblePowerButtonControllerTestApi::TriggerShutdownTimeout() {
-  if (!controller_->shutdown_timer_.IsRunning())
-    return false;
-
-  base::Closure task = controller_->shutdown_timer_.user_task();
-  controller_->shutdown_timer_.Stop();
-  task.Run();
-  return true;
-}
-
-void ConvertiblePowerButtonControllerTestApi::SendKeyEvent(
-    ui::KeyEvent* event) {
-  controller_->display_controller_->OnKeyEvent(event);
-}
-
-}  // namespace ash
diff --git a/ash/system/power/convertible_power_button_controller_test_api.h b/ash/system/power/convertible_power_button_controller_test_api.h
deleted file mode 100644
index 71d0438..0000000
--- a/ash/system/power/convertible_power_button_controller_test_api.h
+++ /dev/null
@@ -1,45 +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.
-
-#ifndef ASH_SYSTEM_POWER_CONVERTIBLE_POWER_BUTTON_CONTROLLER_TEST_API_H_
-#define ASH_SYSTEM_POWER_CONVERTIBLE_POWER_BUTTON_CONTROLLER_TEST_API_H_
-
-#include "base/compiler_specific.h"
-#include "base/macros.h"
-
-namespace ui {
-class KeyEvent;
-}  // namespace ui
-
-namespace ash {
-
-class ConvertiblePowerButtonController;
-
-// Helper class used by tests to access ConvertiblePowerButtonController's
-// internal state.
-class ConvertiblePowerButtonControllerTestApi {
- public:
-  explicit ConvertiblePowerButtonControllerTestApi(
-      ConvertiblePowerButtonController* controller);
-  ~ConvertiblePowerButtonControllerTestApi();
-
-  // Returns true when |controller_->shutdown_timer_| is running.
-  bool ShutdownTimerIsRunning() const;
-
-  // If |controller_->shutdown_timer_| is running, stops it, runs its task, and
-  // returns true. Otherwise, returns false.
-  bool TriggerShutdownTimeout() WARN_UNUSED_RESULT;
-
-  // Sends |event| to |controller_->display_controller_|.
-  void SendKeyEvent(ui::KeyEvent* event);
-
- private:
-  ConvertiblePowerButtonController* controller_;  // Not owned.
-
-  DISALLOW_COPY_AND_ASSIGN(ConvertiblePowerButtonControllerTestApi);
-};
-
-}  // namespace ash
-
-#endif  // ASH_SYSTEM_POWER_CONVERTIBLE_POWER_BUTTON_CONTROLLER_TEST_API_H_
diff --git a/ash/system/power/power_button_controller.cc b/ash/system/power/power_button_controller.cc
index df710db6..91e3299 100644
--- a/ash/system/power/power_button_controller.cc
+++ b/ash/system/power/power_button_controller.cc
@@ -12,9 +12,9 @@
 #include "ash/session/session_controller.h"
 #include "ash/shell.h"
 #include "ash/shutdown_reason.h"
-#include "ash/system/power/convertible_power_button_controller.h"
 #include "ash/system/power/power_button_display_controller.h"
 #include "ash/system/power/power_button_screenshot_controller.h"
+#include "ash/system/power/tablet_power_button_controller.h"
 #include "ash/wm/lock_state_controller.h"
 #include "ash/wm/session_state_animator.h"
 #include "base/command_line.h"
@@ -187,7 +187,7 @@
     return;
 
   // PowerButtonDisplayController ignores power button events, so tell it to
-  // stop forcing the display off if ConvertiblePowerButtonController isn't
+  // stop forcing the display off if TabletPowerButtonController isn't
   // being used.
   if (down && force_clamshell_power_button_)
     display_controller_->SetBacklightsForcedOff(false);
@@ -199,8 +199,8 @@
   }
 
   // Handle tablet power button behavior.
-  if (button_type_ == ButtonType::NORMAL && convertible_controller_) {
-    convertible_controller_->OnPowerButtonEvent(down, timestamp);
+  if (button_type_ == ButtonType::NORMAL && tablet_controller_) {
+    tablet_controller_->OnPowerButtonEvent(down, timestamp);
     return;
   }
 
@@ -215,16 +215,14 @@
   // tablet mode, which must have seen accelerometer data before user actions.
   if (!enable_tablet_mode_)
     return;
-  if (!force_clamshell_power_button_ && !convertible_controller_) {
-    convertible_controller_ =
-        std::make_unique<ConvertiblePowerButtonController>(
-            display_controller_.get(), show_power_button_menu_,
-            tick_clock_.get());
+  if (!force_clamshell_power_button_ && !tablet_controller_) {
+    tablet_controller_ = std::make_unique<TabletPowerButtonController>(
+        display_controller_.get(), show_power_button_menu_, tick_clock_.get());
   }
 
   if (!screenshot_controller_) {
     screenshot_controller_ = std::make_unique<PowerButtonScreenshotController>(
-        convertible_controller_.get(), tick_clock_.get(),
+        tablet_controller_.get(), tick_clock_.get(),
         force_clamshell_power_button_);
   }
 }
diff --git a/ash/system/power/power_button_controller.h b/ash/system/power/power_button_controller.h
index 58b54b9..656ec23 100644
--- a/ash/system/power/power_button_controller.h
+++ b/ash/system/power/power_button_controller.h
@@ -23,14 +23,14 @@
 namespace ash {
 
 class BacklightsForcedOffSetter;
-class ConvertiblePowerButtonController;
 class LockStateController;
 class PowerButtonDisplayController;
 class PowerButtonScreenshotController;
+class TabletPowerButtonController;
 
-// Handles power button and lock button events. For convertible devices,
-// power button events are handled by ConvertiblePowerButtonController to
-// perform corresponding power button behavior, except forced clamshell set by
+// Handles power button and lock button events. For convertible/tablet devices,
+// power button events are handled by TabletPowerButtonController to
+// perform tablet power button behavior, except forced clamshell set by
 // command line. For clamshell devices, power button acts locking or shutdown.
 // On tablet mode, power button may also be consumed to take a screenshot.
 class ASH_EXPORT PowerButtonController
@@ -88,9 +88,8 @@
     return screenshot_controller_.get();
   }
 
-  ConvertiblePowerButtonController*
-  convertible_power_button_controller_for_test() {
-    return convertible_controller_.get();
+  TabletPowerButtonController* tablet_power_button_controller_for_test() {
+    return tablet_controller_.get();
   }
 
   void set_power_button_type_for_test(ButtonType button_type) {
@@ -151,8 +150,8 @@
   // Handles events for power button screenshot.
   std::unique_ptr<PowerButtonScreenshotController> screenshot_controller_;
 
-  // Handles events for convertible devices.
-  std::unique_ptr<ConvertiblePowerButtonController> convertible_controller_;
+  // Handles events for convertible/tablet devices.
+  std::unique_ptr<TabletPowerButtonController> tablet_controller_;
 
   // Used to run ForceDisplayOffAfterLock() shortly after the screen is locked.
   // Only started when |force_clamshell_power_button_| is true.
diff --git a/ash/system/power/power_button_screenshot_controller.cc b/ash/system/power/power_button_screenshot_controller.cc
index a21a91f..7208eb8b51 100644
--- a/ash/system/power/power_button_screenshot_controller.cc
+++ b/ash/system/power/power_button_screenshot_controller.cc
@@ -6,8 +6,8 @@
 
 #include "ash/accelerators/accelerator_controller.h"
 #include "ash/shell.h"
-#include "ash/system/power/convertible_power_button_controller.h"
 #include "ash/system/power/power_button_controller.h"
+#include "ash/system/power/tablet_power_button_controller.h"
 #include "ash/wm/tablet_mode/tablet_mode_controller.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/metrics/user_metrics.h"
@@ -30,10 +30,10 @@
     PowerButtonScreenshotController::kScreenshotChordDelay;
 
 PowerButtonScreenshotController::PowerButtonScreenshotController(
-    ConvertiblePowerButtonController* convertible_controller,
+    TabletPowerButtonController* tablet_controller,
     base::TickClock* tick_clock,
     bool force_clamshell_power_button)
-    : convertible_controller_(convertible_controller),
+    : tablet_controller_(tablet_controller),
       tick_clock_(tick_clock),
       force_clamshell_power_button_(force_clamshell_power_button) {
   DCHECK(tick_clock_);
@@ -113,11 +113,11 @@
   if (key_code == ui::VKEY_VOLUME_UP)
     volume_up_key_pressed_ = event->type() == ui::ET_KEY_PRESSED;
 
-  // When volume key is pressed, cancel the ongoing convertible power button
+  // When volume key is pressed, cancel the ongoing tablet power button
   // behavior.
   if ((volume_down_key_pressed_ || volume_up_key_pressed_) &&
-      convertible_controller_) {
-    convertible_controller_->CancelTabletPowerButton();
+      tablet_controller_) {
+    tablet_controller_->CancelTabletPowerButton();
   }
 
   // On volume down key pressed while power button not pressed yet state, do not
diff --git a/ash/system/power/power_button_screenshot_controller.h b/ash/system/power/power_button_screenshot_controller.h
index 69b56fd..42c2935 100644
--- a/ash/system/power/power_button_screenshot_controller.h
+++ b/ash/system/power/power_button_screenshot_controller.h
@@ -19,7 +19,7 @@
 
 namespace ash {
 
-class ConvertiblePowerButtonController;
+class TabletPowerButtonController;
 
 // Handles power button screenshot accelerator. The screenshot condition is
 // pressing power button and volume down key simultaneously, similar to Android
@@ -32,7 +32,7 @@
       base::TimeDelta::FromMilliseconds(150);
 
   PowerButtonScreenshotController(
-      ConvertiblePowerButtonController* tablet_controller,
+      TabletPowerButtonController* tablet_controller,
       base::TickClock* tick_clock,
       bool force_clamshell_power_button);
   ~PowerButtonScreenshotController() override;
@@ -86,7 +86,7 @@
   // Runs OnClamshellTimeout to start clamshell power button behavior.
   base::OneShotTimer clamshell_power_button_timer_;
 
-  ConvertiblePowerButtonController* convertible_controller_;  // Not owned.
+  TabletPowerButtonController* tablet_controller_;  // Not owned.
 
   // Time source for performed action times.
   base::TickClock* tick_clock_;  // Not owned.
diff --git a/ash/system/power/power_button_screenshot_controller_unittest.cc b/ash/system/power/power_button_screenshot_controller_unittest.cc
index dab32b3..3115fbe 100644
--- a/ash/system/power/power_button_screenshot_controller_unittest.cc
+++ b/ash/system/power/power_button_screenshot_controller_unittest.cc
@@ -8,10 +8,10 @@
 
 #include "ash/login_status.h"
 #include "ash/shell.h"
-#include "ash/system/power/convertible_power_button_controller_test_api.h"
 #include "ash/system/power/power_button_controller.h"
 #include "ash/system/power/power_button_screenshot_controller_test_api.h"
 #include "ash/system/power/power_button_test_base.h"
+#include "ash/system/power/tablet_power_button_controller_test_api.h"
 #include "ash/test_screenshot_delegate.h"
 #include "ash/wm/lock_state_controller_test_api.h"
 #include "base/test/simple_test_tick_clock.h"
@@ -183,16 +183,16 @@
        PowerButtonPressedFirst_VolumeKeyCancelConvertiblePowerButton) {
   // Tests volume down key can stop convertible power button's shutdown timer.
   PressPowerButton();
-  EXPECT_TRUE(convertible_test_api_->ShutdownTimerIsRunning());
+  EXPECT_TRUE(tablet_test_api_->ShutdownTimerIsRunning());
   PressKey(ui::VKEY_VOLUME_DOWN);
-  EXPECT_FALSE(convertible_test_api_->ShutdownTimerIsRunning());
+  EXPECT_FALSE(tablet_test_api_->ShutdownTimerIsRunning());
   ReleasePowerButton();
   ReleaseKey(ui::VKEY_VOLUME_DOWN);
   EXPECT_FALSE(power_manager_client_->backlights_forced_off());
 
   // Tests volume down key can stop shutdown animation timer.
   PressPowerButton();
-  EXPECT_TRUE(convertible_test_api_->TriggerShutdownTimeout());
+  EXPECT_TRUE(tablet_test_api_->TriggerShutdownTimeout());
   EXPECT_TRUE(lock_state_test_api_->shutdown_timer_is_running());
   PressKey(ui::VKEY_VOLUME_DOWN);
   EXPECT_FALSE(lock_state_test_api_->shutdown_timer_is_running());
@@ -203,10 +203,10 @@
   // Tests volume up key can stop convertible power button's shutdown timer.
   // Also tests that volume up key is not consumed.
   PressPowerButton();
-  EXPECT_TRUE(convertible_test_api_->ShutdownTimerIsRunning());
+  EXPECT_TRUE(tablet_test_api_->ShutdownTimerIsRunning());
   PressKey(ui::VKEY_VOLUME_UP);
   EXPECT_FALSE(LastKeyConsumed());
-  EXPECT_FALSE(convertible_test_api_->ShutdownTimerIsRunning());
+  EXPECT_FALSE(tablet_test_api_->ShutdownTimerIsRunning());
   ReleasePowerButton();
   ReleaseKey(ui::VKEY_VOLUME_UP);
   EXPECT_FALSE(power_manager_client_->backlights_forced_off());
@@ -215,7 +215,7 @@
   // Tests volume up key can stop shutdown animation timer.
   // Also tests that volume up key is not consumed.
   PressPowerButton();
-  EXPECT_TRUE(convertible_test_api_->TriggerShutdownTimeout());
+  EXPECT_TRUE(tablet_test_api_->TriggerShutdownTimeout());
   EXPECT_TRUE(lock_state_test_api_->shutdown_timer_is_running());
   PressKey(ui::VKEY_VOLUME_UP);
   EXPECT_FALSE(LastKeyConsumed());
@@ -299,7 +299,7 @@
   // Tests volume down key invalidates convertible power button behavior.
   PressKey(ui::VKEY_VOLUME_DOWN);
   PressPowerButton();
-  EXPECT_FALSE(convertible_test_api_->ShutdownTimerIsRunning());
+  EXPECT_FALSE(tablet_test_api_->ShutdownTimerIsRunning());
   ReleasePowerButton();
   ReleaseKey(ui::VKEY_VOLUME_DOWN);
   EXPECT_FALSE(power_manager_client_->backlights_forced_off());
@@ -309,7 +309,7 @@
   PressKey(ui::VKEY_VOLUME_UP);
   PressPowerButton();
   EXPECT_FALSE(LastKeyConsumed());
-  EXPECT_FALSE(convertible_test_api_->ShutdownTimerIsRunning());
+  EXPECT_FALSE(tablet_test_api_->ShutdownTimerIsRunning());
   ReleasePowerButton();
   ReleaseKey(ui::VKEY_VOLUME_UP);
   EXPECT_FALSE(power_manager_client_->backlights_forced_off());
diff --git a/ash/system/power/power_button_test_base.cc b/ash/system/power/power_button_test_base.cc
index 7a786866..177512e 100644
--- a/ash/system/power/power_button_test_base.cc
+++ b/ash/system/power/power_button_test_base.cc
@@ -9,8 +9,8 @@
 #include "ash/session/test_session_controller_client.h"
 #include "ash/shell.h"
 #include "ash/shell_test_api.h"
-#include "ash/system/power/convertible_power_button_controller_test_api.h"
 #include "ash/system/power/power_button_controller.h"
+#include "ash/system/power/tablet_power_button_controller_test_api.h"
 #include "ash/wm/lock_state_controller.h"
 #include "ash/wm/lock_state_controller_test_api.h"
 #include "ash/wm/tablet_mode/tablet_mode_controller.h"
@@ -69,17 +69,15 @@
 
   if (send_accelerometer_update) {
     SendAccelerometerUpdate(kSidewaysVector, kUpVector);
-    convertible_controller_ =
-        power_button_controller_
-            ->convertible_power_button_controller_for_test();
-    convertible_test_api_ =
-        std::make_unique<ConvertiblePowerButtonControllerTestApi>(
-            convertible_controller_);
+    tablet_controller_ =
+        power_button_controller_->tablet_power_button_controller_for_test();
+    tablet_test_api_ = std::make_unique<TabletPowerButtonControllerTestApi>(
+        tablet_controller_);
     screenshot_controller_ =
         power_button_controller_->screenshot_controller_for_test();
   } else {
-    convertible_test_api_ = nullptr;
-    convertible_controller_ = nullptr;
+    tablet_test_api_ = nullptr;
+    tablet_controller_ = nullptr;
     screenshot_controller_ = nullptr;
   }
 }
@@ -95,8 +93,8 @@
               keyboard.y(), keyboard.z());
 
   power_button_controller_->OnAccelerometerUpdated(update);
-  convertible_controller_ =
-      power_button_controller_->convertible_power_button_controller_for_test();
+  tablet_controller_ =
+      power_button_controller_->tablet_power_button_controller_for_test();
   screenshot_controller_ =
       power_button_controller_->screenshot_controller_for_test();
 }
diff --git a/ash/system/power/power_button_test_base.h b/ash/system/power/power_button_test_base.h
index 0930f61..08b2ec1 100644
--- a/ash/system/power/power_button_test_base.h
+++ b/ash/system/power/power_button_test_base.h
@@ -7,8 +7,8 @@
 
 #include <memory>
 
-#include "ash/system/power/convertible_power_button_controller.h"
 #include "ash/system/power/power_button_controller.h"
+#include "ash/system/power/tablet_power_button_controller.h"
 #include "ash/test/ash_test_base.h"
 #include "ui/events/keycodes/keyboard_codes_posix.h"
 
@@ -27,10 +27,10 @@
 
 namespace ash {
 
-class ConvertiblePowerButtonControllerTestApi;
 class LockStateController;
 class LockStateControllerTestApi;
 class PowerButtonScreenshotController;
+class TabletPowerButtonControllerTestApi;
 enum class LoginStatus;
 
 // Base test fixture and utils for testing power button related functions.
@@ -43,15 +43,15 @@
 
   // Vector pointing up (e.g. keyboard in clamshell).
   static constexpr gfx::Vector3dF kUpVector = {
-      0, 0, ConvertiblePowerButtonController::kGravity};
+      0, 0, TabletPowerButtonController::kGravity};
 
   // Vector pointing down (e.g. keyboard in tablet sitting on table).
   static constexpr gfx::Vector3dF kDownVector = {
-      0, 0, -ConvertiblePowerButtonController::kGravity};
+      0, 0, -TabletPowerButtonController::kGravity};
 
   // Vector pointing sideways (e.g. screen in 90-degree clamshell).
   static constexpr gfx::Vector3dF kSidewaysVector = {
-      0, ConvertiblePowerButtonController::kGravity, 0};
+      0, TabletPowerButtonController::kGravity, 0};
 
   // AshTestBase:
   void SetUp() override;
@@ -62,7 +62,7 @@
 
   // Initializes |power_button_controller_| and other members that point at
   // objects owned by it. If |send_accelerometer_update| is true, an
-  // accelerometer update is sent to create ConvertiblePowerButtonController and
+  // accelerometer update is sent to create TabletPowerButtonController and
   // PowerButtonScreenshotController.
   void InitPowerButtonControllerMembers(bool send_accelerometer_update);
 
@@ -113,13 +113,11 @@
 
   PowerButtonController* power_button_controller_ = nullptr;  // Not owned.
   LockStateController* lock_state_controller_ = nullptr;      // Not owned.
-  ConvertiblePowerButtonController* convertible_controller_ =
-      nullptr;  // Not owned.
+  TabletPowerButtonController* tablet_controller_ = nullptr;  // Not owned.
   PowerButtonScreenshotController* screenshot_controller_ =
       nullptr;  // Not owned.
   std::unique_ptr<LockStateControllerTestApi> lock_state_test_api_;
-  std::unique_ptr<ConvertiblePowerButtonControllerTestApi>
-      convertible_test_api_;
+  std::unique_ptr<TabletPowerButtonControllerTestApi> tablet_test_api_;
   base::SimpleTestTickClock* tick_clock_ = nullptr;  // Not owned.
 
   // Indicates whether switches::kAshEnableTabletMode is appended.
diff --git a/ash/system/power/power_button_util.cc b/ash/system/power/power_button_util.cc
deleted file mode 100644
index 986223f..0000000
--- a/ash/system/power/power_button_util.cc
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ash/system/power/power_button_util.h"
-
-#include "ash/session/session_controller.h"
-#include "ash/shell.h"
-#include "ash/wm/lock_state_controller.h"
-
-namespace power_button_util {
-
-void LockScreenIfRequired(ash::SessionController* session_controller,
-                          ash::LockStateController* lock_state_controller) {
-  if (session_controller->ShouldLockScreenAutomatically() &&
-      session_controller->CanLockScreen() &&
-      !session_controller->IsUserSessionBlocked() &&
-      !lock_state_controller->LockRequested()) {
-    lock_state_controller->LockWithoutAnimation();
-  }
-}
-
-}  // namespace power_button_util
diff --git a/ash/system/power/power_button_util.h b/ash/system/power/power_button_util.h
deleted file mode 100644
index c8d4c87..0000000
--- a/ash/system/power/power_button_util.h
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef ASH_SYSTEM_POWER_POWER_BUTTON_UTIL_H_
-#define ASH_SYSTEM_POWER_POWER_BUTTON_UTIL_H_
-
-#include "base/time/time.h"
-
-namespace ash {
-class LockStateController;
-class SessionController;
-}  // namespace ash
-
-namespace power_button_util {
-
-// Ignore button-up events occurring within this many milliseconds of the
-// previous button-up event. This prevents us from falling behind if the power
-// button is pressed repeatedly.
-static constexpr base::TimeDelta kIgnoreRepeatedButtonUpDelay =
-    base::TimeDelta::FromMilliseconds(500);
-
-// Amount of time since last screen state change that power button event needs
-// to be ignored.
-static constexpr base::TimeDelta kScreenStateChangeDelay =
-    base::TimeDelta::FromMilliseconds(500);
-
-// Amount of time since last SuspendDone() that power button event needs to be
-// ignored.
-static constexpr base::TimeDelta kIgnorePowerButtonAfterResumeDelay =
-    base::TimeDelta::FromSeconds(2);
-
-// Locks the screen if the "Show lock screen when waking from sleep" pref is set
-// and locking is possible.
-void LockScreenIfRequired(ash::SessionController* session_controller,
-                          ash::LockStateController* lock_state_controller);
-
-}  // namespace power_button_util
-
-#endif  // ASH_SYSTEM_POWER_POWER_BUTTON_UTIL_H_
diff --git a/ash/system/power/convertible_power_button_controller.cc b/ash/system/power/tablet_power_button_controller.cc
similarity index 75%
rename from ash/system/power/convertible_power_button_controller.cc
rename to ash/system/power/tablet_power_button_controller.cc
index 7858376..6b1f9124 100644
--- a/ash/system/power/convertible_power_button_controller.cc
+++ b/ash/system/power/tablet_power_button_controller.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ash/system/power/convertible_power_button_controller.h"
+#include "ash/system/power/tablet_power_button_controller.h"
 
 #include "ash/accessibility/accessibility_delegate.h"
 #include "ash/public/cpp/ash_switches.h"
@@ -11,7 +11,6 @@
 #include "ash/shell_delegate.h"
 #include "ash/shutdown_reason.h"
 #include "ash/system/power/power_button_display_controller.h"
-#include "ash/system/power/power_button_util.h"
 #include "ash/wm/lock_state_controller.h"
 #include "ash/wm/tablet_mode/tablet_mode_controller.h"
 #include "base/logging.h"
@@ -39,13 +38,24 @@
 constexpr base::TimeDelta kShutdownWhenScreenOffTimeout =
     base::TimeDelta::FromMilliseconds(2000);
 
+// Amount of time since last SuspendDone() that power button event needs to be
+// ignored.
+static constexpr base::TimeDelta kIgnorePowerButtonAfterResumeDelay =
+    base::TimeDelta::FromSeconds(2);
+
 // Time that power button should be pressed before starting to show the power
 // off menu animation.
 constexpr base::TimeDelta kStartPowerButtonMenuAnimationTimeout =
     base::TimeDelta::FromMilliseconds(500);
+
 }  // namespace
 
-ConvertiblePowerButtonController::ConvertiblePowerButtonController(
+constexpr base::TimeDelta TabletPowerButtonController::kScreenStateChangeDelay;
+
+constexpr base::TimeDelta
+    TabletPowerButtonController::kIgnoreRepeatedButtonUpDelay;
+
+TabletPowerButtonController::TabletPowerButtonController(
     PowerButtonDisplayController* display_controller,
     bool show_power_button_menu,
     base::TickClock* tick_clock)
@@ -58,14 +68,14 @@
   Shell::Get()->tablet_mode_controller()->AddObserver(this);
 }
 
-ConvertiblePowerButtonController::~ConvertiblePowerButtonController() {
+TabletPowerButtonController::~TabletPowerButtonController() {
   if (Shell::Get()->tablet_mode_controller())
     Shell::Get()->tablet_mode_controller()->RemoveObserver(this);
   chromeos::DBusThreadManager::Get()->GetPowerManagerClient()->RemoveObserver(
       this);
 }
 
-void ConvertiblePowerButtonController::OnPowerButtonEvent(
+void TabletPowerButtonController::OnPowerButtonEvent(
     bool down,
     const base::TimeTicks& timestamp) {
   if (down) {
@@ -76,8 +86,7 @@
     // backlight has been turned back on before seeing the power button events
     // that woke the system. Avoid forcing off display just after resuming to
     // ensure that we don't turn the display off in response to the events.
-    if (timestamp - last_resume_time_ <=
-        power_button_util::kIgnorePowerButtonAfterResumeDelay)
+    if (timestamp - last_resume_time_ <= kIgnorePowerButtonAfterResumeDelay)
       force_off_on_button_up_ = false;
 
     // The actual display may remain off for a short period after powerd asks
@@ -85,7 +94,7 @@
     // this time, they probably intend to turn the display on. Avoid forcing off
     // in this case.
     if (timestamp - display_controller_->screen_state_last_changed() <=
-        power_button_util::kScreenStateChangeDelay) {
+        kScreenStateChangeDelay) {
       force_off_on_button_up_ = false;
     }
 
@@ -94,7 +103,7 @@
     if (show_power_button_menu_) {
       power_button_menu_timer_.Start(
           FROM_HERE, kStartPowerButtonMenuAnimationTimeout, this,
-          &ConvertiblePowerButtonController::OnPowerButtonMenuTimeout);
+          &TabletPowerButtonController::OnPowerButtonMenuTimeout);
     } else {
       StartShutdownTimer();
     }
@@ -108,8 +117,7 @@
       lock_state_controller_->CancelShutdownAnimation();
 
     // Ignore the event if it comes too soon after the last one.
-    if (timestamp - previous_up_time <=
-        power_button_util::kIgnoreRepeatedButtonUpDelay) {
+    if (timestamp - previous_up_time <= kIgnoreRepeatedButtonUpDelay) {
       shutdown_timer_.Stop();
       return;
     }
@@ -118,50 +126,59 @@
       shutdown_timer_.Stop();
       if (!screen_off_when_power_button_down_ && force_off_on_button_up_) {
         display_controller_->SetBacklightsForcedOff(true);
-        power_button_util::LockScreenIfRequired(
-            Shell::Get()->session_controller(), lock_state_controller_);
+        LockScreenIfRequired();
       }
     }
   }
 }
 
-void ConvertiblePowerButtonController::SuspendDone(
+void TabletPowerButtonController::SuspendDone(
     const base::TimeDelta& sleep_duration) {
   last_resume_time_ = tick_clock_->NowTicks();
 }
 
-void ConvertiblePowerButtonController::OnTabletModeStarted() {
+void TabletPowerButtonController::OnTabletModeStarted() {
   shutdown_timer_.Stop();
   if (lock_state_controller_->CanCancelShutdownAnimation())
     lock_state_controller_->CancelShutdownAnimation();
 }
 
-void ConvertiblePowerButtonController::OnTabletModeEnded() {
+void TabletPowerButtonController::OnTabletModeEnded() {
   shutdown_timer_.Stop();
   if (lock_state_controller_->CanCancelShutdownAnimation())
     lock_state_controller_->CancelShutdownAnimation();
 }
 
-void ConvertiblePowerButtonController::CancelTabletPowerButton() {
+void TabletPowerButtonController::CancelTabletPowerButton() {
   if (lock_state_controller_->CanCancelShutdownAnimation())
     lock_state_controller_->CancelShutdownAnimation();
   force_off_on_button_up_ = false;
   shutdown_timer_.Stop();
 }
 
-void ConvertiblePowerButtonController::StartShutdownTimer() {
+void TabletPowerButtonController::StartShutdownTimer() {
   base::TimeDelta timeout = screen_off_when_power_button_down_
                                 ? kShutdownWhenScreenOffTimeout
                                 : kShutdownWhenScreenOnTimeout;
   shutdown_timer_.Start(FROM_HERE, timeout, this,
-                        &ConvertiblePowerButtonController::OnShutdownTimeout);
+                        &TabletPowerButtonController::OnShutdownTimeout);
 }
 
-void ConvertiblePowerButtonController::OnShutdownTimeout() {
+void TabletPowerButtonController::OnShutdownTimeout() {
   lock_state_controller_->StartShutdownAnimation(ShutdownReason::POWER_BUTTON);
 }
 
-void ConvertiblePowerButtonController::OnPowerButtonMenuTimeout() {
+void TabletPowerButtonController::LockScreenIfRequired() {
+  SessionController* session_controller = Shell::Get()->session_controller();
+  if (session_controller->ShouldLockScreenAutomatically() &&
+      session_controller->CanLockScreen() &&
+      !session_controller->IsUserSessionBlocked() &&
+      !lock_state_controller_->LockRequested()) {
+    lock_state_controller_->LockWithoutAnimation();
+  }
+}
+
+void TabletPowerButtonController::OnPowerButtonMenuTimeout() {
   // TODO(minch), create the power button menu.
 }
 
diff --git a/ash/system/power/convertible_power_button_controller.h b/ash/system/power/tablet_power_button_controller.h
similarity index 67%
rename from ash/system/power/convertible_power_button_controller.h
rename to ash/system/power/tablet_power_button_controller.h
index 51e0536..10e2e55 100644
--- a/ash/system/power/convertible_power_button_controller.h
+++ b/ash/system/power/tablet_power_button_controller.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef ASH_SYSTEM_POWER_CONVERTIBLE_POWER_BUTTON_CONTROLLER_H_
-#define ASH_SYSTEM_POWER_CONVERTIBLE_POWER_BUTTON_CONTROLLER_H_
+#ifndef ASH_SYSTEM_POWER_TABLET_POWER_BUTTON_CONTROLLER_H_
+#define ASH_SYSTEM_POWER_TABLET_POWER_BUTTON_CONTROLLER_H_
 
 #include <memory>
 #include <utility>
@@ -28,20 +28,30 @@
 class LockStateController;
 class PowerButtonDisplayController;
 
-// Handles power button events on convertible device. This class is
+// Handles power button events on convertible/tablet device. This class is
 // instantiated and used in PowerButtonController.
-class ASH_EXPORT ConvertiblePowerButtonController
+class ASH_EXPORT TabletPowerButtonController
     : public chromeos::PowerManagerClient::Observer,
       public TabletModeObserver {
  public:
   // Public for tests.
   static constexpr float kGravity = 9.80665f;
 
-  ConvertiblePowerButtonController(
-      PowerButtonDisplayController* display_controller,
-      bool show_power_button_menu,
-      base::TickClock* tick_clock);
-  ~ConvertiblePowerButtonController() override;
+  // Amount of time since last screen state change that power button event needs
+  // to be ignored.
+  static constexpr base::TimeDelta kScreenStateChangeDelay =
+      base::TimeDelta::FromMilliseconds(500);
+
+  // Ignore button-up events occurring within this many milliseconds of the
+  // previous button-up event. This prevents us from falling behind if the power
+  // button is pressed repeatedly.
+  static constexpr base::TimeDelta kIgnoreRepeatedButtonUpDelay =
+      base::TimeDelta::FromMilliseconds(500);
+
+  TabletPowerButtonController(PowerButtonDisplayController* display_controller,
+                              bool show_power_button_menu,
+                              base::TickClock* tick_clock);
+  ~TabletPowerButtonController() override;
 
   // Handles a power button event.
   void OnPowerButtonEvent(bool down, const base::TimeTicks& timestamp);
@@ -53,11 +63,11 @@
   void OnTabletModeStarted() override;
   void OnTabletModeEnded() override;
 
-  // Cancel the ongoing power button behavior of convertible devices.
+  // Cancel the ongoing tablet power button behavior.
   void CancelTabletPowerButton();
 
  private:
-  friend class ConvertiblePowerButtonControllerTestApi;
+  friend class TabletPowerButtonControllerTestApi;
 
   // Starts |shutdown_timer_| when the power button is pressed while in
   // tablet mode.
@@ -66,6 +76,10 @@
   // Called by |shutdown_timer_| to start the pre-shutdown animation.
   void OnShutdownTimeout();
 
+  // Locks the screen if the "Show lock screen when waking from sleep" pref is
+  // set and locking is possible.
+  void LockScreenIfRequired();
+
   // Called by |power_button_menu_timer_| to start showing the power button
   // menu.
   void OnPowerButtonMenuTimeout();
@@ -83,7 +97,7 @@
   // True if power button released should force off display.
   bool force_off_on_button_up_ = true;
 
-  // Started when the convertible power button is pressed and stopped when it's
+  // Started when the tablet power button is pressed and stopped when it's
   // released. Runs OnShutdownTimeout() to start shutdown.
   base::OneShotTimer shutdown_timer_;
 
@@ -104,9 +118,9 @@
   // Time source for performed action times.
   base::TickClock* tick_clock_;  // Not owned.
 
-  DISALLOW_COPY_AND_ASSIGN(ConvertiblePowerButtonController);
+  DISALLOW_COPY_AND_ASSIGN(TabletPowerButtonController);
 };
 
 }  // namespace ash
 
-#endif  // ASH_SYSTEM_POWER_CONVERTIBLE_POWER_BUTTON_CONTROLLER_H_
+#endif  // ASH_SYSTEM_POWER_TABLET_POWER_BUTTON_CONTROLLER_H_
diff --git a/ash/system/power/tablet_power_button_controller_test_api.cc b/ash/system/power/tablet_power_button_controller_test_api.cc
new file mode 100644
index 0000000..183217a2
--- /dev/null
+++ b/ash/system/power/tablet_power_button_controller_test_api.cc
@@ -0,0 +1,37 @@
+// 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.
+
+#include "ash/system/power/tablet_power_button_controller_test_api.h"
+
+#include "ash/system/power/power_button_display_controller.h"
+#include "ash/system/power/tablet_power_button_controller.h"
+
+namespace ash {
+
+TabletPowerButtonControllerTestApi::TabletPowerButtonControllerTestApi(
+    TabletPowerButtonController* controller)
+    : controller_(controller) {}
+
+TabletPowerButtonControllerTestApi::~TabletPowerButtonControllerTestApi() =
+    default;
+
+bool TabletPowerButtonControllerTestApi::ShutdownTimerIsRunning() const {
+  return controller_->shutdown_timer_.IsRunning();
+}
+
+bool TabletPowerButtonControllerTestApi::TriggerShutdownTimeout() {
+  if (!controller_->shutdown_timer_.IsRunning())
+    return false;
+
+  base::Closure task = controller_->shutdown_timer_.user_task();
+  controller_->shutdown_timer_.Stop();
+  task.Run();
+  return true;
+}
+
+void TabletPowerButtonControllerTestApi::SendKeyEvent(ui::KeyEvent* event) {
+  controller_->display_controller_->OnKeyEvent(event);
+}
+
+}  // namespace ash
diff --git a/ash/system/power/tablet_power_button_controller_test_api.h b/ash/system/power/tablet_power_button_controller_test_api.h
new file mode 100644
index 0000000..7abdef7b
--- /dev/null
+++ b/ash/system/power/tablet_power_button_controller_test_api.h
@@ -0,0 +1,44 @@
+// 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.
+
+#ifndef ASH_SYSTEM_POWER_TABLET_POWER_BUTTON_CONTROLLER_TEST_API_H_
+#define ASH_SYSTEM_POWER_TABLET_POWER_BUTTON_CONTROLLER_TEST_API_H_
+
+#include "base/compiler_specific.h"
+#include "base/macros.h"
+
+namespace ui {
+class KeyEvent;
+}  // namespace ui
+
+namespace ash {
+class TabletPowerButtonController;
+
+// Helper class used by tests to access TabletPowerButtonController's
+// internal state.
+class TabletPowerButtonControllerTestApi {
+ public:
+  explicit TabletPowerButtonControllerTestApi(
+      TabletPowerButtonController* controller);
+  ~TabletPowerButtonControllerTestApi();
+
+  // Returns true when |controller_->shutdown_timer_| is running.
+  bool ShutdownTimerIsRunning() const;
+
+  // If |controller_->shutdown_timer_| is running, stops it, runs its task, and
+  // returns true. Otherwise, returns false.
+  bool TriggerShutdownTimeout() WARN_UNUSED_RESULT;
+
+  // Sends |event| to |controller_->display_controller_|.
+  void SendKeyEvent(ui::KeyEvent* event);
+
+ private:
+  TabletPowerButtonController* controller_;  // Not owned.
+
+  DISALLOW_COPY_AND_ASSIGN(TabletPowerButtonControllerTestApi);
+};
+
+}  // namespace ash
+
+#endif  // ASH_SYSTEM_POWER_TABLET_POWER_BUTTON_CONTROLLER_TEST_API_H_
diff --git a/ash/system/power/convertible_power_button_controller_unittest.cc b/ash/system/power/tablet_power_button_controller_unittest.cc
similarity index 85%
rename from ash/system/power/convertible_power_button_controller_unittest.cc
rename to ash/system/power/tablet_power_button_controller_unittest.cc
index 1b2cb485..e45ebe18 100644
--- a/ash/system/power/convertible_power_button_controller_unittest.cc
+++ b/ash/system/power/tablet_power_button_controller_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ash/system/power/convertible_power_button_controller.h"
+#include "ash/system/power/tablet_power_button_controller.h"
 
 #include "ash/accessibility/accessibility_controller.h"
 #include "ash/accessibility/test_accessibility_controller_client.h"
@@ -10,9 +10,8 @@
 #include "ash/public/cpp/ash_switches.h"
 #include "ash/session/session_controller.h"
 #include "ash/shell.h"
-#include "ash/system/power/convertible_power_button_controller_test_api.h"
 #include "ash/system/power/power_button_test_base.h"
-#include "ash/system/power/power_button_util.h"
+#include "ash/system/power/tablet_power_button_controller_test_api.h"
 #include "ash/test_media_client.h"
 #include "ash/touch/touch_devices_controller.h"
 #include "ash/wm/lock_state_controller_test_api.h"
@@ -34,10 +33,10 @@
 
 }  // namespace
 
-class ConvertiblePowerButtonControllerTest : public PowerButtonTestBase {
+class TabletPowerButtonControllerTest : public PowerButtonTestBase {
  public:
-  ConvertiblePowerButtonControllerTest() = default;
-  ~ConvertiblePowerButtonControllerTest() override = default;
+  TabletPowerButtonControllerTest() = default;
+  ~TabletPowerButtonControllerTest() override = default;
 
   void SetUp() override {
     PowerButtonTestBase::SetUp();
@@ -46,7 +45,7 @@
     EXPECT_FALSE(power_manager_client_->backlights_forced_off());
 
     // Advance a long duration from initialized last resume time in
-    // |convertible_controller_| to avoid cross interference.
+    // |tablet_controller_| to avoid cross interference.
     tick_clock_->Advance(base::TimeDelta::FromMilliseconds(3000));
 
     // Run the event loop so that PowerButtonDisplayController can receive the
@@ -72,14 +71,15 @@
   // off is not ignored since we will ignore the repeated power button up if
   // they come too close.
   void AdvanceClockToAvoidIgnoring() {
-    tick_clock_->Advance(power_button_util::kIgnoreRepeatedButtonUpDelay +
-                         base::TimeDelta::FromMilliseconds(1));
+    tick_clock_->Advance(
+        TabletPowerButtonController::kIgnoreRepeatedButtonUpDelay +
+        base::TimeDelta::FromMilliseconds(1));
   }
 
-  DISALLOW_COPY_AND_ASSIGN(ConvertiblePowerButtonControllerTest);
+  DISALLOW_COPY_AND_ASSIGN(TabletPowerButtonControllerTest);
 };
 
-TEST_F(ConvertiblePowerButtonControllerTest, LockScreenIfRequired) {
+TEST_F(TabletPowerButtonControllerTest, LockScreenIfRequired) {
   Initialize(ButtonType::NORMAL, LoginStatus::USER);
   SetShouldLockScreenAutomatically(true);
   ASSERT_FALSE(GetLockedState());
@@ -109,31 +109,31 @@
 
 // Tests that shutdown animation is not started if the power button is released
 // quickly.
-TEST_F(ConvertiblePowerButtonControllerTest,
+TEST_F(TabletPowerButtonControllerTest,
        ReleasePowerButtonBeforeStartingShutdownAnimation) {
   PressPowerButton();
-  EXPECT_TRUE(convertible_test_api_->ShutdownTimerIsRunning());
+  EXPECT_TRUE(tablet_test_api_->ShutdownTimerIsRunning());
   EXPECT_FALSE(power_manager_client_->backlights_forced_off());
   ReleasePowerButton();
   power_manager_client_->SendBrightnessChanged(0, true);
-  EXPECT_FALSE(convertible_test_api_->ShutdownTimerIsRunning());
+  EXPECT_FALSE(tablet_test_api_->ShutdownTimerIsRunning());
   EXPECT_TRUE(power_manager_client_->backlights_forced_off());
 
   PressPowerButton();
   power_manager_client_->SendBrightnessChanged(kNonZeroBrightness, true);
-  EXPECT_TRUE(convertible_test_api_->ShutdownTimerIsRunning());
+  EXPECT_TRUE(tablet_test_api_->ShutdownTimerIsRunning());
   EXPECT_FALSE(power_manager_client_->backlights_forced_off());
   ReleasePowerButton();
-  EXPECT_FALSE(convertible_test_api_->ShutdownTimerIsRunning());
+  EXPECT_FALSE(tablet_test_api_->ShutdownTimerIsRunning());
   EXPECT_FALSE(power_manager_client_->backlights_forced_off());
 }
 
 // Tests that the shutdown animation is started when the power button is
 // released after the timer fires.
-TEST_F(ConvertiblePowerButtonControllerTest,
+TEST_F(TabletPowerButtonControllerTest,
        ReleasePowerButtonDuringShutdownAnimation) {
   PressPowerButton();
-  EXPECT_TRUE(convertible_test_api_->TriggerShutdownTimeout());
+  EXPECT_TRUE(tablet_test_api_->TriggerShutdownTimeout());
   EXPECT_TRUE(lock_state_test_api_->shutdown_timer_is_running());
   ReleasePowerButton();
   EXPECT_FALSE(lock_state_test_api_->shutdown_timer_is_running());
@@ -149,7 +149,7 @@
   PressPowerButton();
   power_manager_client_->SendBrightnessChanged(kNonZeroBrightness, true);
   EXPECT_FALSE(power_manager_client_->backlights_forced_off());
-  EXPECT_TRUE(convertible_test_api_->TriggerShutdownTimeout());
+  EXPECT_TRUE(tablet_test_api_->TriggerShutdownTimeout());
   EXPECT_TRUE(lock_state_test_api_->shutdown_timer_is_running());
   ReleasePowerButton();
   EXPECT_FALSE(lock_state_test_api_->shutdown_timer_is_running());
@@ -157,8 +157,7 @@
 }
 
 // Tests tapping power button when screen is idle off.
-TEST_F(ConvertiblePowerButtonControllerTest,
-       TappingPowerButtonWhenScreenIsIdleOff) {
+TEST_F(TabletPowerButtonControllerTest, TappingPowerButtonWhenScreenIsIdleOff) {
   power_manager_client_->SendBrightnessChanged(0, true);
   PressPowerButton();
   EXPECT_FALSE(power_manager_client_->backlights_forced_off());
@@ -169,7 +168,7 @@
 
 // Tests tapping power button when device is suspended without backlights forced
 // off.
-TEST_F(ConvertiblePowerButtonControllerTest,
+TEST_F(TabletPowerButtonControllerTest,
        TappingPowerButtonWhenSuspendedWithoutBacklightsForcedOff) {
   power_manager_client_->SendSuspendImminent(
       power_manager::SuspendImminent_Reason_OTHER);
@@ -182,25 +181,25 @@
   // are not forced off.
   tick_clock_->Advance(base::TimeDelta::FromMilliseconds(500));
   PressPowerButton();
-  EXPECT_TRUE(convertible_test_api_->ShutdownTimerIsRunning());
+  EXPECT_TRUE(tablet_test_api_->ShutdownTimerIsRunning());
   ReleasePowerButton();
-  EXPECT_FALSE(convertible_test_api_->ShutdownTimerIsRunning());
+  EXPECT_FALSE(tablet_test_api_->ShutdownTimerIsRunning());
   EXPECT_FALSE(power_manager_client_->backlights_forced_off());
 
   // Send the power button event after a longer delay and check that backlights
   // are forced off.
   tick_clock_->Advance(base::TimeDelta::FromMilliseconds(1600));
   PressPowerButton();
-  EXPECT_TRUE(convertible_test_api_->ShutdownTimerIsRunning());
+  EXPECT_TRUE(tablet_test_api_->ShutdownTimerIsRunning());
   ReleasePowerButton();
   power_manager_client_->SendBrightnessChanged(0, true);
-  EXPECT_FALSE(convertible_test_api_->ShutdownTimerIsRunning());
+  EXPECT_FALSE(tablet_test_api_->ShutdownTimerIsRunning());
   EXPECT_TRUE(power_manager_client_->backlights_forced_off());
 }
 
 // Tests tapping power button when device is suspended with backlights forced
 // off.
-TEST_F(ConvertiblePowerButtonControllerTest,
+TEST_F(TabletPowerButtonControllerTest,
        TappingPowerButtonWhenSuspendedWithBacklightsForcedOff) {
   PressPowerButton();
   ReleasePowerButton();
@@ -218,25 +217,25 @@
   tick_clock_->Advance(base::TimeDelta::FromMilliseconds(500));
   PressPowerButton();
   power_manager_client_->SendBrightnessChanged(kNonZeroBrightness, true);
-  EXPECT_TRUE(convertible_test_api_->ShutdownTimerIsRunning());
+  EXPECT_TRUE(tablet_test_api_->ShutdownTimerIsRunning());
   ReleasePowerButton();
-  EXPECT_FALSE(convertible_test_api_->ShutdownTimerIsRunning());
+  EXPECT_FALSE(tablet_test_api_->ShutdownTimerIsRunning());
   EXPECT_FALSE(power_manager_client_->backlights_forced_off());
 
   // Send the power button event after a longer delay and check that backlights
   // are forced off.
   tick_clock_->Advance(base::TimeDelta::FromMilliseconds(1600));
   PressPowerButton();
-  EXPECT_TRUE(convertible_test_api_->ShutdownTimerIsRunning());
+  EXPECT_TRUE(tablet_test_api_->ShutdownTimerIsRunning());
   ReleasePowerButton();
   power_manager_client_->SendBrightnessChanged(0, true);
-  EXPECT_FALSE(convertible_test_api_->ShutdownTimerIsRunning());
+  EXPECT_FALSE(tablet_test_api_->ShutdownTimerIsRunning());
   EXPECT_TRUE(power_manager_client_->backlights_forced_off());
 }
 
 // For convertible device working on laptop mode, tests keyboard/mouse event
 // when screen is off.
-TEST_F(ConvertiblePowerButtonControllerTest, ConvertibleOnLaptopMode) {
+TEST_F(TabletPowerButtonControllerTest, ConvertibleOnLaptopMode) {
   EnableTabletMode(false);
 
   // KeyEvent should SetBacklightsForcedOff(false).
@@ -272,7 +271,7 @@
 
 // For convertible device working on tablet mode, keyboard/mouse event should
 // not SetBacklightsForcedOff(false) when screen is off.
-TEST_F(ConvertiblePowerButtonControllerTest, ConvertibleOnTabletMode) {
+TEST_F(TabletPowerButtonControllerTest, ConvertibleOnTabletMode) {
   EnableTabletMode(true);
 
   PressPowerButton();
@@ -288,7 +287,7 @@
 
 // Tests that a single set of power button pressed-and-released operation should
 // cause only one SetBacklightsForcedOff call.
-TEST_F(ConvertiblePowerButtonControllerTest, IgnorePowerOnKeyEvent) {
+TEST_F(TabletPowerButtonControllerTest, IgnorePowerOnKeyEvent) {
   ui::KeyEvent power_key_pressed(ui::ET_KEY_PRESSED, ui::VKEY_POWER,
                                  ui::EF_NONE);
   ui::KeyEvent power_key_released(ui::ET_KEY_RELEASED, ui::VKEY_POWER,
@@ -298,22 +297,22 @@
   // generated for each pressing and releasing, and multiple repeating pressed
   // events depending on holding.
   ASSERT_EQ(0, power_manager_client_->num_set_backlights_forced_off_calls());
-  convertible_test_api_->SendKeyEvent(&power_key_pressed);
-  convertible_test_api_->SendKeyEvent(&power_key_pressed);
+  tablet_test_api_->SendKeyEvent(&power_key_pressed);
+  tablet_test_api_->SendKeyEvent(&power_key_pressed);
   PressPowerButton();
-  convertible_test_api_->SendKeyEvent(&power_key_pressed);
-  convertible_test_api_->SendKeyEvent(&power_key_pressed);
-  convertible_test_api_->SendKeyEvent(&power_key_pressed);
+  tablet_test_api_->SendKeyEvent(&power_key_pressed);
+  tablet_test_api_->SendKeyEvent(&power_key_pressed);
+  tablet_test_api_->SendKeyEvent(&power_key_pressed);
   ReleasePowerButton();
-  convertible_test_api_->SendKeyEvent(&power_key_released);
-  convertible_test_api_->SendKeyEvent(&power_key_released);
+  tablet_test_api_->SendKeyEvent(&power_key_released);
+  tablet_test_api_->SendKeyEvent(&power_key_released);
   EXPECT_EQ(1, power_manager_client_->num_set_backlights_forced_off_calls());
 }
 
 // Tests that under (1) tablet power button pressed/released, (2) keyboard/mouse
 // events on laptop mode when screen is off, requesting/stopping backlights
 // forced off should update the global touchscreen enabled status.
-TEST_F(ConvertiblePowerButtonControllerTest, DisableTouchscreenWhileForcedOff) {
+TEST_F(TabletPowerButtonControllerTest, DisableTouchscreenWhileForcedOff) {
   // Tests tablet power button.
   ASSERT_TRUE(GetGlobalTouchscreenEnabled());
   PressPowerButton();
@@ -352,7 +351,7 @@
 
 // When the screen is turned off automatically, the touchscreen should also be
 // disabled.
-TEST_F(ConvertiblePowerButtonControllerTest, DisableTouchscreenForInactivity) {
+TEST_F(TabletPowerButtonControllerTest, DisableTouchscreenForInactivity) {
   ASSERT_TRUE(GetGlobalTouchscreenEnabled());
 
   // Turn screen off for automated change (e.g. user is inactive).
@@ -369,25 +368,25 @@
 
 // When user switches convertible device between laptop mode and tablet mode,
 // power button may be pressed and held, which may cause unwanted shutdown.
-TEST_F(ConvertiblePowerButtonControllerTest,
+TEST_F(TabletPowerButtonControllerTest,
        EnterOrLeaveTabletModeWhilePressingPowerButton) {
   Initialize(ButtonType::NORMAL, LoginStatus::USER);
   SetShouldLockScreenAutomatically(true);
   ASSERT_FALSE(GetLockedState());
 
   PressPowerButton();
-  EXPECT_TRUE(convertible_test_api_->ShutdownTimerIsRunning());
-  convertible_controller_->OnTabletModeStarted();
-  EXPECT_FALSE(convertible_test_api_->ShutdownTimerIsRunning());
+  EXPECT_TRUE(tablet_test_api_->ShutdownTimerIsRunning());
+  tablet_controller_->OnTabletModeStarted();
+  EXPECT_FALSE(tablet_test_api_->ShutdownTimerIsRunning());
   tick_clock_->Advance(base::TimeDelta::FromMilliseconds(1500));
   ReleasePowerButton();
   EXPECT_FALSE(GetLockedState());
   EXPECT_FALSE(power_manager_client_->backlights_forced_off());
 
   PressPowerButton();
-  EXPECT_TRUE(convertible_test_api_->TriggerShutdownTimeout());
+  EXPECT_TRUE(tablet_test_api_->TriggerShutdownTimeout());
   EXPECT_TRUE(lock_state_test_api_->shutdown_timer_is_running());
-  convertible_controller_->OnTabletModeStarted();
+  tablet_controller_->OnTabletModeStarted();
   EXPECT_FALSE(lock_state_test_api_->shutdown_timer_is_running());
   tick_clock_->Advance(base::TimeDelta::FromMilliseconds(2500));
   ReleasePowerButton();
@@ -395,18 +394,18 @@
   EXPECT_FALSE(power_manager_client_->backlights_forced_off());
 
   PressPowerButton();
-  EXPECT_TRUE(convertible_test_api_->ShutdownTimerIsRunning());
-  convertible_controller_->OnTabletModeEnded();
-  EXPECT_FALSE(convertible_test_api_->ShutdownTimerIsRunning());
+  EXPECT_TRUE(tablet_test_api_->ShutdownTimerIsRunning());
+  tablet_controller_->OnTabletModeEnded();
+  EXPECT_FALSE(tablet_test_api_->ShutdownTimerIsRunning());
   tick_clock_->Advance(base::TimeDelta::FromMilliseconds(3500));
   ReleasePowerButton();
   EXPECT_FALSE(GetLockedState());
   EXPECT_FALSE(power_manager_client_->backlights_forced_off());
 
   PressPowerButton();
-  EXPECT_TRUE(convertible_test_api_->TriggerShutdownTimeout());
+  EXPECT_TRUE(tablet_test_api_->TriggerShutdownTimeout());
   EXPECT_TRUE(lock_state_test_api_->shutdown_timer_is_running());
-  convertible_controller_->OnTabletModeEnded();
+  tablet_controller_->OnTabletModeEnded();
   EXPECT_FALSE(lock_state_test_api_->shutdown_timer_is_running());
   tick_clock_->Advance(base::TimeDelta::FromMilliseconds(4500));
   ReleasePowerButton();
@@ -415,8 +414,7 @@
 }
 
 // Tests that repeated power button releases are ignored (crbug.com/675291).
-TEST_F(ConvertiblePowerButtonControllerTest,
-       IgnoreRepeatedPowerButtonReleases) {
+TEST_F(TabletPowerButtonControllerTest, IgnoreRepeatedPowerButtonReleases) {
   // Set backlights forced off for starting point.
   PressPowerButton();
   ReleasePowerButton();
@@ -447,7 +445,7 @@
 }
 
 // Tests that lid closed/open events stop forcing off backlights.
-TEST_F(ConvertiblePowerButtonControllerTest, LidEventsStopForcingOff) {
+TEST_F(TabletPowerButtonControllerTest, LidEventsStopForcingOff) {
   // Pressing/releasing power button to set backlights forced off.
   PressPowerButton();
   ReleasePowerButton();
@@ -473,7 +471,7 @@
 }
 
 // Tests that tablet mode events from powerd stop forcing off backlights.
-TEST_F(ConvertiblePowerButtonControllerTest, TabletModeEventsStopForcingOff) {
+TEST_F(TabletPowerButtonControllerTest, TabletModeEventsStopForcingOff) {
   PressPowerButton();
   ReleasePowerButton();
   ASSERT_TRUE(power_manager_client_->backlights_forced_off());
@@ -492,7 +490,7 @@
 
 // Tests that with system reboot, the global touchscreen enabled status should
 // be synced with new backlights forced off state from powerd.
-TEST_F(ConvertiblePowerButtonControllerTest, SyncTouchscreenEnabled) {
+TEST_F(TabletPowerButtonControllerTest, SyncTouchscreenEnabled) {
   Shell::Get()->touch_devices_controller()->SetTouchscreenEnabled(
       false, TouchscreenEnabledSource::GLOBAL);
   ASSERT_FALSE(GetGlobalTouchscreenEnabled());
@@ -512,27 +510,27 @@
 
 // Tests that tablet power button behavior is enabled on having seen
 // accelerometer update, otherwise it is disabled.
-TEST_F(ConvertiblePowerButtonControllerTest, EnableOnAccelerometerUpdate) {
-  ASSERT_TRUE(convertible_controller_);
+TEST_F(TabletPowerButtonControllerTest, EnableOnAccelerometerUpdate) {
+  ASSERT_TRUE(tablet_controller_);
   ResetPowerButtonController();
-  EXPECT_FALSE(convertible_controller_);
+  EXPECT_FALSE(tablet_controller_);
 
   SendAccelerometerUpdate(kSidewaysVector, kSidewaysVector);
-  EXPECT_TRUE(convertible_controller_);
+  EXPECT_TRUE(tablet_controller_);
 
   // If clamshell-like power button behavior is requested via a flag, the
-  // ConvertiblePowerButtonController shouldn't be initialized in response to
+  // TabletPowerButtonController shouldn't be initialized in response to
   // accelerometer events.
   base::CommandLine::ForCurrentProcess()->AppendSwitch(
       switches::kForceClamshellPowerButton);
   ResetPowerButtonController();
   SendAccelerometerUpdate(kSidewaysVector, kSidewaysVector);
-  EXPECT_FALSE(convertible_controller_);
+  EXPECT_FALSE(tablet_controller_);
 }
 
 // Tests that when backlights get forced off due to tablet power button, media
 // sessions should be suspended.
-TEST_F(ConvertiblePowerButtonControllerTest, SuspendMediaSessions) {
+TEST_F(TabletPowerButtonControllerTest, SuspendMediaSessions) {
   TestMediaClient client;
   Shell::Get()->media_controller()->SetClient(client.CreateAssociatedPtrInfo());
   ASSERT_FALSE(client.media_sessions_suspended());
@@ -548,7 +546,7 @@
 // Tests that when system is suspended with backlights forced off, and then
 // system resumes due to power button pressed without power button event fired
 // (crbug.com/735291), that we stop forcing off backlights.
-TEST_F(ConvertiblePowerButtonControllerTest, SuspendDoneStopsForcingOff) {
+TEST_F(TabletPowerButtonControllerTest, SuspendDoneStopsForcingOff) {
   PressPowerButton();
   ReleasePowerButton();
   power_manager_client_->SendBrightnessChanged(0, true);
@@ -563,7 +561,7 @@
 
 // Tests that for tablet power button induced locking screen, locking animations
 // are immediate.
-TEST_F(ConvertiblePowerButtonControllerTest, ImmediateLockAnimations) {
+TEST_F(TabletPowerButtonControllerTest, ImmediateLockAnimations) {
   TestSessionStateAnimator* test_animator = new TestSessionStateAnimator;
   lock_state_controller_->set_animator_for_test(test_animator);
   Initialize(ButtonType::NORMAL, LoginStatus::USER);
@@ -609,7 +607,7 @@
 // Tests that updating power button behavior from tablet behavior to clamshell
 // behavior will initially enable touchscreen on global touchscreen enabled
 // status (b/64972736).
-TEST_F(ConvertiblePowerButtonControllerTest, TouchscreenEnabledClamshell) {
+TEST_F(TabletPowerButtonControllerTest, TouchscreenEnabledClamshell) {
   PressPowerButton();
   ReleasePowerButton();
   ASSERT_TRUE(power_manager_client_->backlights_forced_off());
@@ -630,7 +628,7 @@
 
 // Tests that during the interval that the display is turning on, tablet power
 // button should not set display off (crbug.com/735225).
-TEST_F(ConvertiblePowerButtonControllerTest,
+TEST_F(TabletPowerButtonControllerTest,
        IgnoreForcingOffWhenDisplayIsTurningOn) {
   PressPowerButton();
   ReleasePowerButton();
@@ -644,7 +642,7 @@
   EXPECT_FALSE(power_manager_client_->backlights_forced_off());
 
   // Since display could still be off, ignore forcing off.
-  tick_clock_->Advance(power_button_util::kScreenStateChangeDelay -
+  tick_clock_->Advance(TabletPowerButtonController::kScreenStateChangeDelay -
                        base::TimeDelta::FromMilliseconds(1));
   PressPowerButton();
   ReleasePowerButton();
@@ -661,7 +659,7 @@
 
 // Tests that a11y alert is sent on tablet power button induced screen state
 // change.
-TEST_F(ConvertiblePowerButtonControllerTest, A11yAlert) {
+TEST_F(TabletPowerButtonControllerTest, A11yAlert) {
   TestAccessibilityControllerClient client;
   AccessibilityController* controller =
       Shell::Get()->accessibility_controller();
@@ -688,7 +686,7 @@
   InitPowerButtonControllerMembers(true /* send_accelerometer_update */);
   ASSERT_FALSE(base::CommandLine::ForCurrentProcess()->HasSwitch(
       switches::kAshEnableTabletMode));
-  EXPECT_FALSE(convertible_controller_);
+  EXPECT_FALSE(tablet_controller_);
 }
 
 }  // namespace ash
diff --git a/base/BUILD.gn b/base/BUILD.gn
index 744ec15..51afc04 100644
--- a/base/BUILD.gn
+++ b/base/BUILD.gn
@@ -67,6 +67,12 @@
       # Don't die on dtoa code that uses a char as an array index.
       # This is required solely for base/third_party/dmg_fp/dtoa_wrapper.cc.
       "-Wno-char-subscripts",
+
+      # Ideally all product code (but no test code) in chrome would have this
+      # flag. But this isn't trivial so start with //base as a minimum
+      # requirement.
+      # https://groups.google.com/a/chromium.org/d/topic/chromium-dev/B9Q5KTD7iCo/discussion
+      "-Wglobal-constructors",
     ]
   }
 }
diff --git a/base/android/library_loader/library_prefetcher.cc b/base/android/library_loader/library_prefetcher.cc
index e6a7a2d..bafc410 100644
--- a/base/android/library_loader/library_prefetcher.cc
+++ b/base/android/library_loader/library_prefetcher.cc
@@ -31,13 +31,13 @@
 
 // Android defines the background priority to this value since at least 2009
 // (see Process.java).
-const int kBackgroundPriority = 10;
+constexpr int kBackgroundPriority = 10;
 // Valid for all the Android architectures.
-const size_t kPageSize = 4096;
-const char* kLibchromeSuffix = "libchrome.so";
+constexpr size_t kPageSize = 4096;
+constexpr char kLibchromeSuffix[] = "libchrome.so";
 // "base.apk" is a suffix because the library may be loaded directly from the
 // APK.
-const char* kSuffixesToMatch[] = {kLibchromeSuffix, "base.apk"};
+constexpr const char* kSuffixesToMatch[] = {kLibchromeSuffix, "base.apk"};
 
 bool IsReadableAndPrivate(const base::debug::MappedMemoryRegion& region) {
   return region.permissions & base::debug::MappedMemoryRegion::READ &&
diff --git a/base/lazy_instance.h b/base/lazy_instance.h
index 2d150a2..bbb3e08d 100644
--- a/base/lazy_instance.h
+++ b/base/lazy_instance.h
@@ -34,11 +34,12 @@
 // requires that Type be a complete type so we can determine the size.
 //
 // Example usage:
-//   static LazyInstance<MyClass>::Leaky inst = LAZY_INSTANCE_INITIALIZER;
+//   // Does not generate a dynamic initializer.
+//   LazyInstance<MyClass>::Leaky my_lazy_instance;
 //   void SomeMethod() {
-//     inst.Get().SomeMethod();  // MyClass::SomeMethod()
+//     my_lazy_instance.Get().SomeMethod();  // MyClass::SomeMethod()
 //
-//     MyClass* ptr = inst.Pointer();
+//     MyClass* ptr = my_lazy_instance.Pointer();
 //     ptr->DoDoDo();  // MyClass::DoDoDo
 //   }
 
@@ -52,9 +53,11 @@
 #include "base/lazy_instance_helpers.h"
 #include "base/logging.h"
 #include "base/threading/thread_restrictions.h"
+#include "build/build_config.h"
 
-// LazyInstance uses its own struct initializer-list style static
-// initialization, which does not require a constructor.
+// To support the old initialization pattern for LazyInstance, i.e.:
+// LazyInstance<MyClass>::Leaky my_lazy_instance = LAZY_INSTANCE_INITIALIZER;
+// TODO(gab): Remove this.
 #define LAZY_INSTANCE_INITIALIZER {0}
 
 namespace base {
@@ -131,6 +134,10 @@
         internal::ErrorMustSelectLazyOrDestructorAtExitForLazyInstance<Type>>
 class LazyInstance {
  public:
+  // kLazyInstanceInitializer shouldn't be used (it is there to absorb the
+  // LAZY_INSTANCE_INITIALIZER param when constructed with it).
+  constexpr LazyInstance(int kLazyInstanceInitializer = 0) {}
+
   // Do not define a destructor, as doing so makes LazyInstance a
   // non-POD-struct. We don't want that because then a static initializer will
   // be created to register the (empty) destructor with atexit() under MSVC, for
@@ -169,26 +176,6 @@
     return 0 != subtle::NoBarrier_Load(&private_instance_);
   }
 
-  // MSVC gives a warning that the alignment expands the size of the
-  // LazyInstance struct to make the size a multiple of the alignment. This
-  // is expected in this case.
-#if defined(OS_WIN)
-#pragma warning(push)
-#pragma warning(disable: 4324)
-#endif
-
-  // Effectively private: member data is only public to allow the linker to
-  // statically initialize it and to maintain a POD class. DO NOT USE FROM
-  // OUTSIDE THIS CLASS.
-  subtle::AtomicWord private_instance_;
-
-  // Preallocated space for the Type instance.
-  alignas(Type) char private_buf_[sizeof(Type)];
-
-#if defined(OS_WIN)
-#pragma warning(pop)
-#endif
-
  private:
   Type* instance() {
     return reinterpret_cast<Type*>(subtle::NoBarrier_Load(&private_instance_));
@@ -203,6 +190,23 @@
     Traits::Delete(me->instance());
     subtle::NoBarrier_Store(&me->private_instance_, 0);
   }
+
+// MSVC gives a warning that the alignment expands the size of the
+// LazyInstance struct to make the size a multiple of the alignment. This
+// is expected in this case.
+#if defined(COMPILER_MSVC)
+#pragma warning(push)
+#pragma warning(disable : 4324)
+#endif
+
+  subtle::AtomicWord private_instance_ = 0;
+
+  // Preallocated space for the Type instance.
+  alignas(Type) char private_buf_[sizeof(Type)] = {};
+
+#if defined(COMPILER_MSVC)
+#pragma warning(pop)
+#endif
 };
 
 }  // namespace base
diff --git a/base/lazy_instance_unittest.cc b/base/lazy_instance_unittest.cc
index a5f024cf..104f5f23 100644
--- a/base/lazy_instance_unittest.cc
+++ b/base/lazy_instance_unittest.cc
@@ -320,3 +320,17 @@
   EXPECT_LT(base::TimeTicks::Now() - test_begin,
             base::TimeDelta::FromSeconds(5));
 }
+
+TEST(LazyInstanceTest, ConstExprConstructible) {
+  // Mostly just verifying that this compiles, the runtime test itself won't do
+  // much... Declaring the variable constexpr forces the compiler to verify that
+  // this is possible but renders the LazyInstance unusable as none of its
+  // methods are const.
+  static constexpr base::LazyInstance<SlowConstructor>
+      kTestConstExprConstructible;
+  static constexpr base::LazyInstance<SlowConstructor>
+      kTestConstExprConstructibleWithExplicitInitializer =
+          LAZY_INSTANCE_INITIALIZER;
+  ALLOW_UNUSED_LOCAL(kTestConstExprConstructible);
+  ALLOW_UNUSED_LOCAL(kTestConstExprConstructibleWithExplicitInitializer);
+}
diff --git a/base/message_loop/message_pump_mac.mm b/base/message_loop/message_pump_mac.mm
index 1a72da6..a3352ca 100644
--- a/base/message_loop/message_pump_mac.mm
+++ b/base/message_loop/message_pump_mac.mm
@@ -25,8 +25,19 @@
 
 namespace base {
 
+// kMessageLoopExclusiveRunLoopMode must be defined before kAllModes to generate
+// a sane static initialization order.
+const CFStringRef kMessageLoopExclusiveRunLoopMode =
+    CFSTR("kMessageLoopExclusiveRunLoopMode");
+
 namespace {
 
+// kCFRunLoopCommonModes is const but not constexpr; hence kAllModes is
+// initialized at run-time. This initialization being trivial, constant, and
+// without side-effects: this is fine.
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wglobal-constructors"
+
 // AppKit RunLoop modes observed to potentially run tasks posted to Chrome's
 // main thread task runner. Some are internal to AppKit but must be observed to
 // keep Chrome's UI responsive. Others that may be interesting, but are not
@@ -46,6 +57,8 @@
     CFSTR("NSUnhighlightMenuRunLoopMode"),
 };
 
+#pragma clang diagnostic pop  // -Wglobal-constructors
+
 // Mask that determines which modes in |kAllModes| to use.
 enum { kCommonModeMask = 0x1, kAllModesMask = 0xf };
 
@@ -112,10 +125,6 @@
 
 }  // namespace
 
-// static
-const CFStringRef kMessageLoopExclusiveRunLoopMode =
-    CFSTR("kMessageLoopExclusiveRunLoopMode");
-
 // A scoper for autorelease pools created from message pump run loops.
 // Avoids dirtying up the ScopedNSAutoreleasePool interface for the rare
 // case where an autorelease pool needs to be passed in.
diff --git a/base/process/memory_win.cc b/base/process/memory_win.cc
index 2ae826b..c3fe758 100644
--- a/base/process/memory_win.cc
+++ b/base/process/memory_win.cc
@@ -10,6 +10,12 @@
 #include <psapi.h>
 #include <stddef.h>
 
+#if defined(__clang__)
+// This global constructor is trivial and non-racy (per being const).
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wglobal-constructors"
+#endif
+
 // malloc_unchecked is required to implement UncheckedMalloc properly.
 // It's provided by allocator_shim_win.cc but since that's not always present,
 // we provide a default that falls back to regular malloc.
@@ -17,6 +23,10 @@
 extern "C" void* (*const malloc_unchecked)(size_t);
 extern "C" void* (*const malloc_default)(size_t) = &malloc;
 
+#if defined(__clang__)
+#pragma clang diagnostic pop  // -Wglobal-constructors
+#endif
+
 #if defined(_M_IX86)
 #pragma comment(linker, "/alternatename:_malloc_unchecked=_malloc_default")
 #elif defined(_M_X64) || defined(_M_ARM)
diff --git a/build/android/gyp/javac.py b/build/android/gyp/javac.py
index 42202e95..79815a83 100755
--- a/build/android/gyp/javac.py
+++ b/build/android/gyp/javac.py
@@ -204,13 +204,14 @@
                     (java_file, expected_path_suffix))
 
 
-def _OnStaleMd5(changes, options, javac_cmd, java_files, classpath_inputs):
+def _OnStaleMd5(changes, options, javac_cmd, java_files, classpath_inputs,
+                classpath):
   incremental = options.incremental
   # Don't bother enabling incremental compilation for third_party code, since
   # _CheckPathMatchesClassName() fails on some of it, and it's not really much
   # benefit.
   for java_file in java_files:
-    if 'third_party' in java_file:
+    if 'third_party' in java_file or not options.chromium_code:
       incremental = False
     else:
       _CheckPathMatchesClassName(java_file)
@@ -274,12 +275,7 @@
         # Add the extracted files to the classpath. This is required because
         # when compiling only a subset of files, classes that haven't changed
         # need to be findable.
-        try:
-          classpath_idx = javac_cmd.index('-classpath')
-          javac_cmd[classpath_idx + 1] += ':' + classes_dir
-        except ValueError:
-          # If there is no class path in the command line then add the arg
-          javac_cmd.extend(["-classpath", classes_dir])
+        classpath.append(classes_dir)
 
       # Can happen when a target goes from having no sources, to having sources.
       # It's created by the call to build_utils.Touch() below.
@@ -289,7 +285,20 @@
 
       # Don't include the output directory in the initial set of args since it
       # being in a temp dir makes it unstable (breaks md5 stamping).
-      cmd = javac_cmd + ['-d', classes_dir] + java_files
+      cmd = javac_cmd + ['-d', classes_dir]
+
+      # Pass classpath and source paths as response files to avoid extremely
+      # long command lines that are tedius to debug.
+      if classpath:
+        classpath_rsp_path = os.path.join(temp_dir, 'classpath.txt')
+        with open(classpath_rsp_path, 'w') as f:
+          f.write(':'.join(classpath))
+        cmd += ['-classpath', '@' + classpath_rsp_path]
+
+      java_files_rsp_path = os.path.join(temp_dir, 'files_list.txt')
+      with open(java_files_rsp_path, 'w') as f:
+        f.write(' '.join(java_files))
+      cmd += ['@' + java_files_rsp_path]
 
       # JMake prints out some diagnostic logs that we want to ignore.
       # This assumes that all compiler output goes through stderr.
@@ -493,8 +502,9 @@
   # Annotation processors crash when given interface jars.
   active_classpath = (
       options.classpath if options.processors else options.interface_classpath)
+  classpath = []
   if active_classpath:
-    javac_cmd.extend(['-classpath', ':'.join(active_classpath)])
+    classpath.extend(active_classpath)
 
   if options.processorpath:
     javac_cmd.extend(['-processorpath', ':'.join(options.processorpath)])
@@ -525,11 +535,11 @@
   # of them does not change what gets written to the depsfile.
   build_utils.CallAndWriteDepfileIfStale(
       lambda changes: _OnStaleMd5(changes, options, javac_cmd, java_files,
-                                  classpath_inputs),
+                                  classpath_inputs, classpath),
       options,
       depfile_deps=depfile_deps,
       input_paths=input_paths,
-      input_strings=javac_cmd,
+      input_strings=javac_cmd + classpath,
       output_paths=output_paths,
       force=force,
       pass_changes=True)
diff --git a/build/config/compiler/BUILD.gn b/build/config/compiler/BUILD.gn
index 2673c6a..4e464d8 100644
--- a/build/config/compiler/BUILD.gn
+++ b/build/config/compiler/BUILD.gn
@@ -104,9 +104,6 @@
 
   # Path to an AFDO profile to use while building with clang, if any. Empty
   # implies none.
-  #
-  # Please note that you need to be very careful about changing your profile at
-  # the moment. See the `BUG(gbiv)` comment later in this file.
   clang_sample_profile_path = ""
 
   # Some configurations have default sample profiles. If this is true and
@@ -179,6 +176,7 @@
   ldflags = []
   defines = []
   configs = []
+  inputs = []
 
   # System-specific flags. If your compiler flags apply to one of the
   # categories here, add it to the associated file to keep this shared config
@@ -219,12 +217,6 @@
     # AFDO to be split into its own config, so this isn't part of that config.
     #
     # Since we only profile the browser, skip it if we're building host tools.
-    #
-    # XXX(gbiv): There is currently *no* dependency between the profile we use
-    # and the compilations/links that we do. So, if the profile gets updated,
-    # the user has to manually clean build artifacts. CL:827560 should fix this
-    # by allowing us to specify `inputs` here, but until then, the only "good"
-    # workaround is changing your profile name each time you update the profile.
     if (is_clang && current_toolchain == default_toolchain) {
       _sample_path = ""
       if (clang_sample_profile_path != "") {
@@ -240,6 +232,7 @@
         if (clang_sample_profile_is_accurate) {
           cflags += [ "-fprofile-sample-accurate" ]
         }
+        inputs += [ _sample_path ]
       }
     }
 
diff --git a/cc/resources/display_resource_provider.cc b/cc/resources/display_resource_provider.cc
index 56cc411..696d4a19 100644
--- a/cc/resources/display_resource_provider.cc
+++ b/cc/resources/display_resource_provider.cc
@@ -91,6 +91,15 @@
   }
 }
 
+void DisplayResourceProvider::DeletePromotionHint(ResourceMap::iterator it,
+                                                  DeleteStyle style) {
+  viz::internal::Resource* resource = &it->second;
+  // If this resource was interested in promotion hints, then remove it from
+  // the set of resources that we'll notify.
+  if (resource->wants_promotion_hint)
+    wants_promotion_hints_set_.erase(it->first);
+}
+
 bool DisplayResourceProvider::IsBackedBySurfaceTexture(viz::ResourceId id) {
   viz::internal::Resource* resource = GetResource(id);
   return resource->is_backed_by_surface_texture;
@@ -293,6 +302,9 @@
 
     child_info->child_to_parent_map.erase(child_id);
     resource.imported_count = 0;
+#if defined(OS_ANDROID)
+    DeletePromotionHint(it, style);
+#endif
     DeleteResourceInternal(it, style);
   }
 
@@ -555,6 +567,9 @@
   if (resource->marked_for_deletion && !resource->lock_for_read_count) {
     if (!resource->child_id) {
       // The resource belongs to this ResourceProvider, so it can be destroyed.
+#if defined(OS_ANDROID)
+      DeletePromotionHint(it, NORMAL);
+#endif
       DeleteResourceInternal(it, NORMAL);
     } else {
       if (batch_return_resources_) {
diff --git a/cc/resources/display_resource_provider.h b/cc/resources/display_resource_provider.h
index 3f35fb4..a5071879 100644
--- a/cc/resources/display_resource_provider.h
+++ b/cc/resources/display_resource_provider.h
@@ -238,6 +238,9 @@
   const viz::internal::Resource* LockForRead(viz::ResourceId id);
   void UnlockForRead(viz::ResourceId id);
   bool ReadLockFenceHasPassed(const viz::internal::Resource* resource);
+#if defined(OS_ANDROID)
+  void DeletePromotionHint(ResourceMap::iterator it, DeleteStyle style);
+#endif
 
   struct Child {
     Child();
@@ -260,9 +263,20 @@
 
   scoped_refptr<viz::ResourceFence> current_read_lock_fence_;
   ChildMap children_;
+  // Used as child id when creating a child.
+  int next_child_ = 1;
   base::flat_map<viz::ResourceId, sk_sp<SkImage>> resource_sk_image_;
   viz::ResourceId next_id_;
   viz::SharedBitmapManager* shared_bitmap_manager_;
+  // Keep track of whether deleted resources should be batched up or returned
+  // immediately.
+  bool batch_return_resources_ = false;
+  // Maps from a child id to the set of resources to be returned to it.
+  base::small_map<std::map<int, ResourceIdArray>> batched_returning_resources_;
+#if defined(OS_ANDROID)
+  // Set of ResourceIds that would like to be notified about promotion hints.
+  viz::ResourceIdSet wants_promotion_hints_set_;
+#endif
 
   DISALLOW_COPY_AND_ASSIGN(DisplayResourceProvider);
 };
diff --git a/cc/resources/layer_tree_resource_provider.cc b/cc/resources/layer_tree_resource_provider.cc
index e49a200..8d5b7a5 100644
--- a/cc/resources/layer_tree_resource_provider.cc
+++ b/cc/resources/layer_tree_resource_provider.cc
@@ -818,6 +818,24 @@
   }
 }
 
+bool LayerTreeResourceProvider::IsLost(viz::ResourceId id) {
+  viz::internal::Resource* resource = GetResource(id);
+  return resource->lost;
+}
+
+void LayerTreeResourceProvider::LoseResourceForTesting(viz::ResourceId id) {
+  viz::internal::Resource* resource = GetResource(id);
+  DCHECK(resource);
+  resource->lost = true;
+}
+
+void LayerTreeResourceProvider::EnableReadLockFencesForTesting(
+    viz::ResourceId id) {
+  viz::internal::Resource* resource = GetResource(id);
+  DCHECK(resource);
+  resource->read_lock_fences_enabled = true;
+}
+
 LayerTreeResourceProvider::ScopedWriteLockGpu::ScopedWriteLockGpu(
     LayerTreeResourceProvider* resource_provider,
     viz::ResourceId resource_id)
diff --git a/cc/resources/layer_tree_resource_provider.h b/cc/resources/layer_tree_resource_provider.h
index 8c1af88..e9b6a3b 100644
--- a/cc/resources/layer_tree_resource_provider.h
+++ b/cc/resources/layer_tree_resource_provider.h
@@ -144,6 +144,11 @@
     return gpu_memory_buffer_manager_;
   }
 
+  bool IsLost(viz::ResourceId id);
+
+  void LoseResourceForTesting(viz::ResourceId id);
+  void EnableReadLockFencesForTesting(viz::ResourceId id);
+
   // The following lock classes are part of the ResourceProvider API and are
   // needed to read and write the resource contents. The user must ensure
   // that they only use GL locks on GL resources, etc, and this is enforced
diff --git a/cc/resources/resource_provider.cc b/cc/resources/resource_provider.cc
index 81aacbf..a9bf4b84 100644
--- a/cc/resources/resource_provider.cc
+++ b/cc/resources/resource_provider.cc
@@ -53,7 +53,6 @@
 ResourceProvider::ResourceProvider(
     viz::ContextProvider* compositor_context_provider)
     : compositor_context_provider_(compositor_context_provider),
-      next_child_(1),
       lost_context_provider_(false),
       tracing_id_(g_next_resource_provider_tracing_id.GetNext()) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
@@ -87,30 +86,12 @@
 #endif  // DCHECK_IS_ON()
 }
 
-bool ResourceProvider::IsLost(viz::ResourceId id) {
-  viz::internal::Resource* resource = GetResource(id);
-  return resource->lost;
-}
-
-void ResourceProvider::LoseResourceForTesting(viz::ResourceId id) {
-  viz::internal::Resource* resource = GetResource(id);
-  DCHECK(resource);
-  resource->lost = true;
-}
-
 void ResourceProvider::DeleteResourceInternal(ResourceMap::iterator it,
                                               DeleteStyle style) {
   TRACE_EVENT0("cc", "ResourceProvider::DeleteResourceInternal");
   viz::internal::Resource* resource = &it->second;
   DCHECK(resource->exported_count == 0 || style != NORMAL);
 
-#if defined(OS_ANDROID)
-  // If this resource was interested in promotion hints, then remove it from
-  // the set of resources that we'll notify.
-  if (resource->wants_promotion_hint)
-    wants_promotion_hints_set_.erase(it->first);
-#endif
-
   // Exported resources are lost on shutdown.
   bool exported_resource_lost =
       style == FOR_SHUTDOWN && resource->exported_count > 0;
@@ -174,12 +155,6 @@
   return &it->second;
 }
 
-void ResourceProvider::EnableReadLockFencesForTesting(viz::ResourceId id) {
-  viz::internal::Resource* resource = GetResource(id);
-  DCHECK(resource);
-  resource->read_lock_fences_enabled = true;
-}
-
 void ResourceProvider::PopulateSkBitmapWithResource(
     SkBitmap* sk_bitmap,
     const viz::internal::Resource* resource) {
@@ -209,10 +184,6 @@
   return context_provider ? context_provider->ContextGL() : nullptr;
 }
 
-bool ResourceProvider::IsGLContextLost() const {
-  return ContextGL()->GetGraphicsResetStatusKHR() != GL_NO_ERROR;
-}
-
 bool ResourceProvider::OnMemoryDump(
     const base::trace_event::MemoryDumpArgs& args,
     base::trace_event::ProcessMemoryDump* pmd) {
diff --git a/cc/resources/resource_provider.h b/cc/resources/resource_provider.h
index 368c81f..fa07aae 100644
--- a/cc/resources/resource_provider.h
+++ b/cc/resources/resource_provider.h
@@ -70,19 +70,12 @@
   explicit ResourceProvider(viz::ContextProvider* compositor_context_provider);
   ~ResourceProvider() override;
 
-  void Initialize();
-
   bool IsSoftware() const { return !compositor_context_provider_; }
 
   void DidLoseContextProvider() { lost_context_provider_ = true; }
 
   size_t num_resources() const { return resources_.size(); }
 
-  bool IsLost(viz::ResourceId id);
-
-  void LoseResourceForTesting(viz::ResourceId id);
-  void EnableReadLockFencesForTesting(viz::ResourceId id);
-
   GLenum GetResourceTextureTarget(viz::ResourceId id);
 
   // base::trace_event::MemoryDumpProvider implementation.
@@ -116,27 +109,13 @@
 
   ResourceMap resources_;
 
-  // Keep track of whether deleted resources should be batched up or returned
-  // immediately.
-  bool batch_return_resources_ = false;
-  // Maps from a child id to the set of resources to be returned to it.
-  base::small_map<std::map<int, ResourceIdArray>> batched_returning_resources_;
-
   viz::ContextProvider* compositor_context_provider_;
-  int next_child_;
 
   bool lost_context_provider_;
 
   THREAD_CHECKER(thread_checker_);
 
-#if defined(OS_ANDROID)
-  // Set of resource Ids that would like to be notified about promotion hints.
-  viz::ResourceIdSet wants_promotion_hints_set_;
-#endif
-
  private:
-  bool IsGLContextLost() const;
-
   // A process-unique ID used for disambiguating memory dumps from different
   // resource providers.
   int tracing_id_;
diff --git a/cc/test/test_web_graphics_context_3d.h b/cc/test/test_web_graphics_context_3d.h
index a0cc1a2..5e4921f 100644
--- a/cc/test/test_web_graphics_context_3d.h
+++ b/cc/test/test_web_graphics_context_3d.h
@@ -363,6 +363,9 @@
   void set_support_texture_storage_image(bool support) {
     test_capabilities_.texture_storage_image = support;
   }
+  void set_support_texture_npot(bool support) {
+    test_capabilities_.texture_npot = support;
+  }
 
   // When this context is lost, all contexts in its share group are also lost.
   void add_share_group_context(TestWebGraphicsContext3D* context3d) {
diff --git a/chrome/VERSION b/chrome/VERSION
index c1e6ceeb..ece84aa 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
-MAJOR=65
+MAJOR=66
 MINOR=0
-BUILD=3325
+BUILD=3326
 PATCH=0
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn
index e45a141b..6d8ffbe7 100644
--- a/chrome/android/BUILD.gn
+++ b/chrome/android/BUILD.gn
@@ -499,7 +499,6 @@
     "//chrome/android/third_party/widget_bottomsheet_base:widget_bottomsheet_base_java",
     "//chrome/android/webapk/libs/client:client_java",
     "//chrome/android/webapk/libs/common:common_java",
-    "//chrome/android/webapk/libs/runtime_library:webapk_service_aidl_java",
     "//chrome/test/android:chrome_java_test_support",
     "//components/autofill/android:autofill_java",
     "//components/background_task_scheduler:background_task_scheduler_java",
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java
index f8215688..6cad3a64 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java
@@ -240,6 +240,7 @@
     public static final String READER_MODE_IN_CCT = "ReaderModeInCCT";
     public static final String SERVICE_WORKER_PAYMENT_APPS = "ServiceWorkerPaymentApps";
     public static final String SITE_NOTIFICATION_CHANNELS = "SiteNotificationChannels";
+    public static final String SOLE_INTEGRATION = "SoleIntegration";
     public static final String SOUND_CONTENT_SETTING = "SoundContentSetting";
     public static final String SPANNABLE_INLINE_AUTOCOMPLETE = "SpannableInlineAutocomplete";
     public static final String TAB_REPARENTING = "TabReparenting";
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/init/AsyncInitializationActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/init/AsyncInitializationActivity.java
index d9eacfc..1af2d8531 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/init/AsyncInitializationActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/init/AsyncInitializationActivity.java
@@ -110,13 +110,14 @@
         // On N+, Chrome should always retain the tab strip layout on tablets. Normally in
         // multi-window, if Chrome is launched into a smaller screen Android will load the tab
         // switcher resources. Overriding the smallestScreenWidthDp in the Configuration ensures
-        // Android will load the tab strip resources.
-        // See crbug.com/588838, crbug.com/662338, crbug.com/780593.
+        // Android will load the tab strip resources. See crbug.com/588838.
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
-            Configuration overrideConfiguration = new Configuration();
-            overrideConfiguration.smallestScreenWidthDp =
-                    DeviceFormFactor.getSmallestDeviceWidthDp();
-            applyOverrideConfiguration(overrideConfiguration);
+            if (DeviceFormFactor.isTablet()) {
+                Configuration overrideConfiguration = new Configuration();
+                overrideConfiguration.smallestScreenWidthDp =
+                        DeviceFormFactor.getSmallestDeviceWidthDp();
+                applyOverrideConfiguration(overrideConfiguration);
+            }
         }
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceManager.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceManager.java
index 2c7ea7a3..c3188758a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceManager.java
@@ -66,6 +66,7 @@
 
     private static final String CHROME_HOME_MENU_ITEM_CLICK_COUNT_KEY =
             "chrome_home_menu_item_click_count";
+    private static final String SOLE_INTEGRATION_ENABLED_KEY = "sole_integration_enabled";
 
     private static class LazyHolder {
         static final ChromePreferenceManager INSTANCE = new ChromePreferenceManager();
@@ -494,6 +495,22 @@
     }
 
     /**
+     * Get whether or not Sole integration is enabled.
+     * @return True if Sole integration is enabled.
+     */
+    public boolean isSoleEnabled() {
+        return mSharedPreferences.getBoolean(SOLE_INTEGRATION_ENABLED_KEY, false);
+    }
+
+    /**
+     * Set whether or not Sole integration is enabled.
+     * @param isEnabled If Sole integration is enabled.
+     */
+    public void setSoleEnabled(boolean isEnabled) {
+        writeBoolean(SOLE_INTEGRATION_ENABLED_KEY, isEnabled);
+    }
+
+    /**
      * Writes the given int value to the named shared preference.
      * @param key The name of the preference to modify.
      * @param value The new value for the preference.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/util/FeatureUtilities.java b/chrome/android/java/src/org/chromium/chrome/browser/util/FeatureUtilities.java
index c797639b..9c22ef16 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/util/FeatureUtilities.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/util/FeatureUtilities.java
@@ -53,6 +53,7 @@
     private static boolean sChromeHomeNeedsUpdate;
     private static String sChromeHomeSwipeLogicType;
 
+    private static Boolean sIsSoleEnabled;
     /**
      * Determines whether or not the {@link RecognizerIntent#ACTION_WEB_SEARCH} {@link Intent}
      * is handled by any {@link android.app.Activity}s in the system.  The result will be cached for
@@ -154,6 +155,7 @@
      */
     public static void cacheNativeFlags() {
         cacheChromeHomeEnabled();
+        cacheSoleEnabled();
         FirstRunUtils.cacheFirstRunPrefs();
 
         // Propagate DONT_PREFETCH_LIBRARIES feature value to LibraryLoader. This can't
@@ -338,6 +340,33 @@
         return false;
     }
 
+    /**
+     * Cache whether or not Sole integration is enabled.
+     */
+    public static void cacheSoleEnabled() {
+        boolean featureEnabled = ChromeFeatureList.isEnabled(ChromeFeatureList.SOLE_INTEGRATION);
+        ChromePreferenceManager prefManager = ChromePreferenceManager.getInstance();
+        boolean prefEnabled = prefManager.isSoleEnabled();
+        if (featureEnabled == prefEnabled) return;
+
+        prefManager.setSoleEnabled(featureEnabled);
+    }
+
+    /**
+     * @return Whether or not Sole integration is enabled.
+     */
+    public static boolean isSoleEnabled() {
+        if (sIsSoleEnabled == null) {
+            ChromePreferenceManager prefManager = ChromePreferenceManager.getInstance();
+
+            // Allow disk access for preferences while Sole is in experimentation.
+            try (StrictModeContext unused = StrictModeContext.allowDiskReads()) {
+                sIsSoleEnabled = prefManager.isSoleEnabled();
+            }
+        }
+        return sIsSoleEnabled;
+    }
+
     private static native void nativeSetCustomTabVisible(boolean visible);
     private static native void nativeSetIsInMultiWindowMode(boolean isInMultiWindowMode);
     private static native void nativeNotifyChromeHomeStatusChanged(boolean isChromeHomeEnabled);
diff --git a/chrome/android/webapk/shell_apk/BUILD.gn b/chrome/android/webapk/shell_apk/BUILD.gn
index f24cf3c7..d00b927 100644
--- a/chrome/android/webapk/shell_apk/BUILD.gn
+++ b/chrome/android/webapk/shell_apk/BUILD.gn
@@ -34,9 +34,24 @@
   ]
 }
 
-android_library("webapk_java") {
+# Stamped out copy of the runtime-library, used for fail-safe code in when using an
+# old copy of the runtime library.
+android_library("compiled_in_runtime_library_java") {
+  chromium_code = false
+  java_files = [
+    "src/org/chromium/webapk/lib/runtime_library/IWebApkApi.java",
+ ]
+}
+
+# Split out as a separate target so that it can be tested from chrome_public_test_apk
+android_library("dex_loader_java") {
   java_files = [
     "src/org/chromium/webapk/shell_apk/DexLoader.java",
+  ]
+}
+
+android_library("webapk_java") {
+  java_files = [
     "src/org/chromium/webapk/shell_apk/HostBrowserClassLoader.java",
     "src/org/chromium/webapk/shell_apk/HostBrowserLauncher.java",
     "src/org/chromium/webapk/shell_apk/ChooseHostBrowserDialog.java",
@@ -54,10 +69,11 @@
     "src/org/chromium/webapk/shell_apk/WebApkUtils.java",
   ]
   deps = [
+    ":compiled_in_runtime_library_java",
+    ":dex_loader_java",
     ":shell_apk_manifest",
     ":shell_apk_resources",
     "//chrome/android/webapk/libs/common:common_java",
-    "//chrome/android/webapk/libs/runtime_library:webapk_service_aidl_java",
   ]
 
   android_manifest_for_lint = shell_apk_manifest
@@ -162,7 +178,7 @@
   java_files =
       [ "javatests/src/org/chromium/webapk/shell_apk/DexLoaderTest.java" ]
   deps = [
-    ":webapk_java",
+    ":dex_loader_java",
     "//base:base_java",
     "//base:base_java_test_support",
     "//chrome/android/webapk/libs/common:common_java",
@@ -181,10 +197,11 @@
     "junit/src/org/chromium/webapk/shell_apk/WebApkUtilsTest.java",
   ]
   deps = [
+    ":compiled_in_runtime_library_java",
+    ":dex_loader_java",
     ":webapk_java",
     "//chrome/android/webapk/libs/common:common_java",
     "//chrome/android/webapk/libs/runtime_library:runtime_library_for_tests_java",
-    "//chrome/android/webapk/libs/runtime_library:webapk_service_aidl_java",
     "//chrome/android/webapk/test:junit_test_support",
   ]
 }
diff --git a/chrome/android/webapk/shell_apk/junit/DEPS b/chrome/android/webapk/shell_apk/junit/DEPS
index 7bfd905..a7d6d038 100644
--- a/chrome/android/webapk/shell_apk/junit/DEPS
+++ b/chrome/android/webapk/shell_apk/junit/DEPS
@@ -1,5 +1,4 @@
 include_rules = [
   "+chrome/android/webapk/test",
-  "+chrome/android/webapk/libs/runtime_library",
   "+testing",
 ]
diff --git a/chrome/android/webapk/shell_apk/shell_apk_version.gni b/chrome/android/webapk/shell_apk/shell_apk_version.gni
index 056431d..a5b42d1 100644
--- a/chrome/android/webapk/shell_apk/shell_apk_version.gni
+++ b/chrome/android/webapk/shell_apk/shell_apk_version.gni
@@ -6,7 +6,7 @@
 # (including AndroidManifest.xml) is updated. This version should be incremented
 # prior to uploading a new ShellAPK to the WebAPK Minting Server.
 # Does not affect Chrome.apk
-template_shell_apk_version = 40
+template_shell_apk_version = 41
 
 # The ShellAPK version expected by Chrome. Chrome will try to update the WebAPK
 # if the WebAPK's ShellAPK version is less than |expected_shell_apk_version|.
diff --git a/chrome/android/webapk/shell_apk/src/org/chromium/webapk/lib/runtime_library/IWebApkApi.java b/chrome/android/webapk/shell_apk/src/org/chromium/webapk/lib/runtime_library/IWebApkApi.java
new file mode 100644
index 0000000..4a9ec53
--- /dev/null
+++ b/chrome/android/webapk/shell_apk/src/org/chromium/webapk/lib/runtime_library/IWebApkApi.java
@@ -0,0 +1,258 @@
+/*
+ * This file is auto-generated.  DO NOT MODIFY.
+ * Original file: ../../chrome/android/webapk/libs/runtime_library/src/org/chromium/webapk/lib/runtime_library/IWebApkApi.aidl
+ */
+package org.chromium.webapk.lib.runtime_library;
+/**
+ * Interface for communicating between WebAPK service and Chrome.
+ */
+public interface IWebApkApi extends android.os.IInterface
+{
+/** Local-side IPC implementation stub class. */
+public static abstract class Stub extends android.os.Binder implements org.chromium.webapk.lib.runtime_library.IWebApkApi
+{
+private static final java.lang.String DESCRIPTOR = "org.chromium.webapk.lib.runtime_library.IWebApkApi";
+/** Construct the stub at attach it to the interface. */
+public Stub()
+{
+this.attachInterface(this, DESCRIPTOR);
+}
+/**
+ * Cast an IBinder object into an org.chromium.webapk.lib.runtime_library.IWebApkApi interface,
+ * generating a proxy if needed.
+ */
+public static org.chromium.webapk.lib.runtime_library.IWebApkApi asInterface(android.os.IBinder obj)
+{
+if ((obj==null)) {
+return null;
+}
+android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
+if (((iin!=null)&&(iin instanceof org.chromium.webapk.lib.runtime_library.IWebApkApi))) {
+return ((org.chromium.webapk.lib.runtime_library.IWebApkApi)iin);
+}
+return new org.chromium.webapk.lib.runtime_library.IWebApkApi.Stub.Proxy(obj);
+}
+@Override public android.os.IBinder asBinder()
+{
+return this;
+}
+@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
+{
+switch (code)
+{
+case INTERFACE_TRANSACTION:
+{
+reply.writeString(DESCRIPTOR);
+return true;
+}
+case TRANSACTION_getSmallIconId:
+{
+data.enforceInterface(DESCRIPTOR);
+int _result = this.getSmallIconId();
+reply.writeNoException();
+reply.writeInt(_result);
+return true;
+}
+case TRANSACTION_notifyNotification:
+{
+data.enforceInterface(DESCRIPTOR);
+java.lang.String _arg0;
+_arg0 = data.readString();
+int _arg1;
+_arg1 = data.readInt();
+android.app.Notification _arg2;
+if ((0!=data.readInt())) {
+_arg2 = android.app.Notification.CREATOR.createFromParcel(data);
+}
+else {
+_arg2 = null;
+}
+this.notifyNotification(_arg0, _arg1, _arg2);
+reply.writeNoException();
+return true;
+}
+case TRANSACTION_cancelNotification:
+{
+data.enforceInterface(DESCRIPTOR);
+java.lang.String _arg0;
+_arg0 = data.readString();
+int _arg1;
+_arg1 = data.readInt();
+this.cancelNotification(_arg0, _arg1);
+reply.writeNoException();
+return true;
+}
+case TRANSACTION_notificationPermissionEnabled:
+{
+data.enforceInterface(DESCRIPTOR);
+boolean _result = this.notificationPermissionEnabled();
+reply.writeNoException();
+reply.writeInt(((_result)?(1):(0)));
+return true;
+}
+case TRANSACTION_notifyNotificationWithChannel:
+{
+data.enforceInterface(DESCRIPTOR);
+java.lang.String _arg0;
+_arg0 = data.readString();
+int _arg1;
+_arg1 = data.readInt();
+android.app.Notification _arg2;
+if ((0!=data.readInt())) {
+_arg2 = android.app.Notification.CREATOR.createFromParcel(data);
+}
+else {
+_arg2 = null;
+}
+java.lang.String _arg3;
+_arg3 = data.readString();
+this.notifyNotificationWithChannel(_arg0, _arg1, _arg2, _arg3);
+reply.writeNoException();
+return true;
+}
+}
+return super.onTransact(code, data, reply, flags);
+}
+private static class Proxy implements org.chromium.webapk.lib.runtime_library.IWebApkApi
+{
+private android.os.IBinder mRemote;
+Proxy(android.os.IBinder remote)
+{
+mRemote = remote;
+}
+@Override public android.os.IBinder asBinder()
+{
+return mRemote;
+}
+public java.lang.String getInterfaceDescriptor()
+{
+return DESCRIPTOR;
+}
+@Override public int getSmallIconId() throws android.os.RemoteException
+{
+android.os.Parcel _data = android.os.Parcel.obtain();
+android.os.Parcel _reply = android.os.Parcel.obtain();
+int _result;
+try {
+_data.writeInterfaceToken(DESCRIPTOR);
+mRemote.transact(Stub.TRANSACTION_getSmallIconId, _data, _reply, 0);
+_reply.readException();
+_result = _reply.readInt();
+}
+finally {
+_reply.recycle();
+_data.recycle();
+}
+return _result;
+}
+// Display a notification.
+// DEPRECATED: Use notifyNotificationWithChannel.
+
+@Override public void notifyNotification(java.lang.String platformTag, int platformID, android.app.Notification notification) throws android.os.RemoteException
+{
+android.os.Parcel _data = android.os.Parcel.obtain();
+android.os.Parcel _reply = android.os.Parcel.obtain();
+try {
+_data.writeInterfaceToken(DESCRIPTOR);
+_data.writeString(platformTag);
+_data.writeInt(platformID);
+if ((notification!=null)) {
+_data.writeInt(1);
+notification.writeToParcel(_data, 0);
+}
+else {
+_data.writeInt(0);
+}
+mRemote.transact(Stub.TRANSACTION_notifyNotification, _data, _reply, 0);
+_reply.readException();
+}
+finally {
+_reply.recycle();
+_data.recycle();
+}
+}
+// Cancel a notification.
+
+@Override public void cancelNotification(java.lang.String platformTag, int platformID) throws android.os.RemoteException
+{
+android.os.Parcel _data = android.os.Parcel.obtain();
+android.os.Parcel _reply = android.os.Parcel.obtain();
+try {
+_data.writeInterfaceToken(DESCRIPTOR);
+_data.writeString(platformTag);
+_data.writeInt(platformID);
+mRemote.transact(Stub.TRANSACTION_cancelNotification, _data, _reply, 0);
+_reply.readException();
+}
+finally {
+_reply.recycle();
+_data.recycle();
+}
+}
+// Get if notification permission is enabled.
+
+@Override public boolean notificationPermissionEnabled() throws android.os.RemoteException
+{
+android.os.Parcel _data = android.os.Parcel.obtain();
+android.os.Parcel _reply = android.os.Parcel.obtain();
+boolean _result;
+try {
+_data.writeInterfaceToken(DESCRIPTOR);
+mRemote.transact(Stub.TRANSACTION_notificationPermissionEnabled, _data, _reply, 0);
+_reply.readException();
+_result = (0!=_reply.readInt());
+}
+finally {
+_reply.recycle();
+_data.recycle();
+}
+return _result;
+}
+// Display a notification with a specified channel name.
+
+@Override public void notifyNotificationWithChannel(java.lang.String platformTag, int platformID, android.app.Notification notification, java.lang.String channelName) throws android.os.RemoteException
+{
+android.os.Parcel _data = android.os.Parcel.obtain();
+android.os.Parcel _reply = android.os.Parcel.obtain();
+try {
+_data.writeInterfaceToken(DESCRIPTOR);
+_data.writeString(platformTag);
+_data.writeInt(platformID);
+if ((notification!=null)) {
+_data.writeInt(1);
+notification.writeToParcel(_data, 0);
+}
+else {
+_data.writeInt(0);
+}
+_data.writeString(channelName);
+mRemote.transact(Stub.TRANSACTION_notifyNotificationWithChannel, _data, _reply, 0);
+_reply.readException();
+}
+finally {
+_reply.recycle();
+_data.recycle();
+}
+}
+}
+static final int TRANSACTION_getSmallIconId = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
+static final int TRANSACTION_notifyNotification = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
+static final int TRANSACTION_cancelNotification = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2);
+static final int TRANSACTION_notificationPermissionEnabled = (android.os.IBinder.FIRST_CALL_TRANSACTION + 3);
+static final int TRANSACTION_notifyNotificationWithChannel = (android.os.IBinder.FIRST_CALL_TRANSACTION + 4);
+}
+public int getSmallIconId() throws android.os.RemoteException;
+// Display a notification.
+// DEPRECATED: Use notifyNotificationWithChannel.
+
+public void notifyNotification(java.lang.String platformTag, int platformID, android.app.Notification notification) throws android.os.RemoteException;
+// Cancel a notification.
+
+public void cancelNotification(java.lang.String platformTag, int platformID) throws android.os.RemoteException;
+// Get if notification permission is enabled.
+
+public boolean notificationPermissionEnabled() throws android.os.RemoteException;
+// Display a notification with a specified channel name.
+
+public void notifyNotificationWithChannel(java.lang.String platformTag, int platformID, android.app.Notification notification, java.lang.String channelName) throws android.os.RemoteException;
+}
diff --git a/chrome/android/webapk/shell_apk/src/org/chromium/webapk/lib/runtime_library/README b/chrome/android/webapk/shell_apk/src/org/chromium/webapk/lib/runtime_library/README
new file mode 100644
index 0000000..3ddbc07
--- /dev/null
+++ b/chrome/android/webapk/shell_apk/src/org/chromium/webapk/lib/runtime_library/README
@@ -0,0 +1,10 @@
+This directory contains a pre-compiled / fallback copy of the runtime library.
+It was necessary for WebAPKs to switch to supporting Android O because as soon
+as the app targets Android O a notification channel was necessary for the
+notification to be shown. Since the runtime library is provided by the host
+browser, there's no way to guarantee this with the WebAPK shell change.
+
+To update this generated copy again,
+$ ninja -C out/Debug webapk_runtime_library
+$ unzip out/Debug/gen/chrome/android/webapk/libs/runtime_library/webapk_service_aidl.srcjar
+$ mv org/chromium/webapk/lib/runtime_library/IWebApkApi.java chrome/android/webapk/shell_apk/src/org/chromium/webapk/lib/runtime_library/
diff --git a/chrome/android/webapk/shell_apk/src/org/chromium/webapk/shell_apk/DexLoader.java b/chrome/android/webapk/shell_apk/src/org/chromium/webapk/shell_apk/DexLoader.java
index 48ba114..0d00494 100644
--- a/chrome/android/webapk/shell_apk/src/org/chromium/webapk/shell_apk/DexLoader.java
+++ b/chrome/android/webapk/shell_apk/src/org/chromium/webapk/shell_apk/DexLoader.java
@@ -23,6 +23,24 @@
     private static final int BUFFER_SIZE = 16 * 1024;
     private static final String TAG = "cr.DexLoader";
 
+    /** Delete the given File and (if it's a directory) everything within it. */
+    public static void deletePath(File file) {
+        if (file == null) return;
+
+        if (file.isDirectory()) {
+            File[] children = file.listFiles();
+            if (children != null) {
+                for (File child : children) {
+                    deletePath(child);
+                }
+            }
+        }
+
+        if (!file.delete()) {
+            Log.e(TAG, "Failed to delete : " + file.getAbsolutePath());
+        }
+    }
+
     /**
      * Creates ClassLoader for .dex file in {@link remoteContext}'s APK.
      * @param remoteContext The context with the APK with the .dex file.
@@ -76,7 +94,7 @@
      * @param localDexDir Cache directory passed to {@link #load()}.
      */
     public void deleteCachedDexes(File localDexDir) {
-        WebApkUtils.deletePath(localDexDir);
+        deletePath(localDexDir);
     }
 
     /**
diff --git a/chrome/android/webapk/shell_apk/src/org/chromium/webapk/shell_apk/HostBrowserLauncher.java b/chrome/android/webapk/shell_apk/src/org/chromium/webapk/shell_apk/HostBrowserLauncher.java
index a368ea1a..d4ff0dd 100644
--- a/chrome/android/webapk/shell_apk/src/org/chromium/webapk/shell_apk/HostBrowserLauncher.java
+++ b/chrome/android/webapk/shell_apk/src/org/chromium/webapk/shell_apk/HostBrowserLauncher.java
@@ -130,9 +130,9 @@
 
     /** Deletes the internal storage. */
     private void deleteInternalStorage() {
-        WebApkUtils.deletePath(mContext.getCacheDir());
-        WebApkUtils.deletePath(mContext.getFilesDir());
-        WebApkUtils.deletePath(
+        DexLoader.deletePath(mContext.getCacheDir());
+        DexLoader.deletePath(mContext.getFilesDir());
+        DexLoader.deletePath(
                 mContext.getDir(HostBrowserClassLoader.DEX_DIR_NAME, Context.MODE_PRIVATE));
     }
 
diff --git a/chrome/android/webapk/shell_apk/src/org/chromium/webapk/shell_apk/WebApkUtils.java b/chrome/android/webapk/shell_apk/src/org/chromium/webapk/shell_apk/WebApkUtils.java
index 5072180..a10297901 100644
--- a/chrome/android/webapk/shell_apk/src/org/chromium/webapk/shell_apk/WebApkUtils.java
+++ b/chrome/android/webapk/shell_apk/src/org/chromium/webapk/shell_apk/WebApkUtils.java
@@ -16,7 +16,6 @@
 import android.os.Build;
 import android.os.Bundle;
 import android.text.TextUtils;
-import android.util.Log;
 import android.util.TypedValue;
 import android.view.View;
 import android.widget.TextView;
@@ -24,7 +23,6 @@
 import org.chromium.webapk.lib.common.WebApkConstants;
 import org.chromium.webapk.lib.common.WebApkMetaDataKeys;
 
-import java.io.File;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashSet;
@@ -323,24 +321,6 @@
         }
     }
 
-    /** Delete the given File and (if it's a directory) everything within it. */
-    public static void deletePath(File file) {
-        if (file == null) return;
-
-        if (file.isDirectory()) {
-            File[] children = file.listFiles();
-            if (children != null) {
-                for (File child : children) {
-                    deletePath(child);
-                }
-            }
-        }
-
-        if (!file.delete()) {
-            Log.e(TAG, "Failed to delete : " + file.getAbsolutePath());
-        }
-    }
-
     /** Returns whether a WebAPK should be launched as a tab. See crbug.com/772398. */
     public static boolean shouldLaunchInTab(String versionName) {
         int dotIndex = versionName.indexOf(".");
diff --git a/chrome/app/chromium_strings.grd b/chrome/app/chromium_strings.grd
index f7683d7c..bf0479e 100644
--- a/chrome/app/chromium_strings.grd
+++ b/chrome/app/chromium_strings.grd
@@ -215,7 +215,7 @@
       </message>
       <if expr="is_win">
         <message name="IDS_WIN_XP_VISTA_OBSOLETE" desc="A message displayed on an at-launch infobar and about:help warning the user that the computer they are using is no longer supported.">
-          Chromium may not function correctly because it is no longer supported on Windows XP or Windows Vista.
+          Chromium may not function correctly because it is no longer supported on Windows XP or Windows Vista
         </message>
       </if>
       <message name="IDS_ACCNAME_APP" desc="The accessible name for the app menu.">
@@ -394,7 +394,7 @@
         </message>
       </if>
       <message name="IDS_DEFAULT_BROWSER_INFOBAR_TEXT" desc="Text to show in an infobar when Chromium is not the current default browser.">
-        Chromium isn't your default browser.
+        Chromium isn't your default browser
       </message>
       <if expr="chromeos">
         <message name="IDS_SYNC_OVERVIEW" desc="Chrome OS: The message that appears in the options dialog when sync has not been set up by the user.">
@@ -1101,19 +1101,19 @@
       <!-- Runtime permission strings -->
       <if expr="is_android">
         <message name="IDS_INFOBAR_MISSING_CAMERA_PERMISSION_TEXT" desc="Text shown in an infobar when a website has requested access to the camera capabilities, but Chrome is missing the Android camera permission.">
-          Chromium needs permission to access your camera for this site.
+          Chromium needs permission to access your camera for this site
         </message>
         <message name="IDS_INFOBAR_MISSING_MICROPHONE_PERMISSION_TEXT" desc="Text shown in an infobar when a website has requested access to the microphone capabilities, but Chrome is missing the Android microphone permission.">
-          Chromium needs permission to access your microphone for this site.
+          Chromium needs permission to access your microphone for this site
         </message>
         <message name="IDS_INFOBAR_MISSING_MICROPHONE_CAMERA_PERMISSIONS_TEXT" desc="Text shown in an infobar when a website has requested access to the microphone and camera capabilities, but Chrome is missing the Android microphone and camera permissions.">
-          Chromium needs permission to access your camera and microphone for this site.
+          Chromium needs permission to access your camera and microphone for this site
         </message>
         <message name="IDS_INFOBAR_MISSING_LOCATION_PERMISSION_TEXT" desc="Text shown in an infobar when a website has requested access to the location capabilities, but Chrome is missing the Android location permission.">
-          Chromium needs access to your location to share your location with this site.
+          Chromium needs access to your location to share your location with this site
         </message>
         <message name="IDS_MISSING_STORAGE_PERMISSION_DOWNLOAD_EDUCATION_TEXT" desc="Text shown educating the user that Chrome is missing the Android storage permission, which is required to download files.">
-          Chromium needs storage access to download files.
+          Chromium needs storage access to download files
         </message>
       </if>
 
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index 094021d..36f2b47 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -2933,7 +2933,7 @@
 
       <!-- DevTools attached infobar -->
       <message name="IDS_DEV_TOOLS_INFOBAR_LABEL" desc="Label displayed in an infobar when external debugger is attached to the browser">
-        "<ph name="CLIENT_NAME">$1<ex>Extension Foo</ex></ph>" is debugging this browser.
+        "<ph name="CLIENT_NAME">$1<ex>Extension Foo</ex></ph>" is debugging this browser
       </message>
 
       <!-- DevTools file system access -->
@@ -3325,7 +3325,7 @@
 
       <!-- Theme preview infobar -->
       <message name="IDS_THEME_INSTALL_INFOBAR_LABEL" desc="Text displayed on an infobar when a theme has been installed.">
-        Installed theme "<ph name="THEME_NAME">$1<ex>Snowflake Theme</ex></ph>".
+        Installed theme "<ph name="THEME_NAME">$1<ex>Snowflake Theme</ex></ph>"
       </message>
       <message name="IDS_THEME_INSTALL_INFOBAR_UNDO_BUTTON" desc="Text displayed on the button to undo a theme installation and go back to the previous theme.">
         Undo
@@ -3339,7 +3339,7 @@
         <ph name="EXTENSION_NAME">$1<ex>Adblock</ex></ph> is disabled
       </message>
       <message name="IDS_EXTENSION_IS_BLACKLISTED" desc="Text displayed in an infobar when an extension is blacklisted and prevented from being installed.">
-        Google has flagged "<ph name="EXTENSION_NAME">$1<ex>Google Talk</ex></ph>" as malicious and installation has been prevented.
+        Google has flagged "<ph name="EXTENSION_NAME">$1<ex>Google Talk</ex></ph>" as malicious and installation has been prevented
       </message>
       <message name="IDS_EXTENSION_DISABLED_REMOTE_INSTALL_ERROR_TITLE" desc="Title of the notification that an extension or app was disabled due to it being installed server side, requiring an explicit permission check from the user.">
         <ph name="EXTENSION_NAME">$1<ex>Adblock</ex></ph> was added remotely
@@ -3820,9 +3820,6 @@
       <message name="IDS_EXTENSION_DIRECTORY_NO_EXISTS" desc="Warning displayed in pack dialog when the extension directory does not exist.">
         Input directory must exist.
       </message>
-      <message name="IDS_EXTENSION_DISALLOW_NON_DOWNLOADED_GALLERY_INSTALLS" desc="Error displayed when an app or extension that has an update URL used by the gallery is installed when not directly downloaded from the gallery.">
-        This can only be added from the <ph name="CHROME_WEB_STORE">$1<ex>Web Store</ex></ph>.
-      </message>
       <message name="IDS_EXTENSION_PRIVATE_KEY_INVALID_PATH" desc="Warning displayed in pack dialog when the private key must be a valid path.">
         Input value for private key must be a valid path.
       </message>
@@ -3889,34 +3886,37 @@
         Could not move extension directory into profile.
       </message>
       <message name="IDS_EXTENSION_INSTALL_NOT_ENABLED" desc="Error displayed during installation of apps or extensions when installation is not enabled.">
-        Installation is not enabled.
+        Installation is not enabled
       </message>
       <message name="IDS_EXTENSION_INSTALL_INCORRECT_APP_CONTENT_TYPE" desc="Error displayed during installation of apps when the app is not served with the correct content-type.">
-        Apps must be served with content-type "<ph name="CONTENT_TYPE">$1<ex>application/x-chrome-extension</ex></ph>".
+        Apps must be served with content-type "<ph name="CONTENT_TYPE">$1<ex>application/x-chrome-extension</ex></ph>"
       </message>
       <message name="IDS_EXTENSION_INSTALL_INCORRECT_INSTALL_HOST" desc="Error displayed during installation of apps when the app is served from a different host than it affects.">
-        Apps must be served from the host they affect.
+        Apps must be served from the host they affect
       </message>
       <message name="IDS_EXTENSION_INSTALL_UNEXPECTED_ID" desc="Error displayed during installation of a side-loaded app, extension, or theme when the ID of the referenced extension does not match the ID the developer declared during registration.">
-        Expected ID "<ph name="EXPECTED_ID">$1<ex>bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb</ex></ph>", but ID was "<ph name="NEW_ID">$2<ex>aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa</ex></ph>".
+        Expected ID "<ph name="EXPECTED_ID">$1<ex>bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb</ex></ph>", but ID was "<ph name="NEW_ID">$2<ex>aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa</ex></ph>"
       </message>
       <message name="IDS_EXTENSION_INSTALL_DISALLOWED_ON_SITE" desc="Error displayed during installation of an extension when installation is not allowed from the current site.">
-        Apps, extensions, and user scripts cannot be added from this website.
+        Apps, extensions, and user scripts cannot be added from this website
       </message>
       <message name="IDS_EXTENSION_INSTALL_UNEXPECTED_VERSION" desc="Error displayed during installation of a side-loaded app, extension, or theme when the version of the referenced extension does not match the version the developer declared during registration.">
-        Expected version "<ph name="EXPECTED_VERSION">$1<ex>2.0</ex></ph>", but version was "<ph name="NEW_ID">$2<ex>1.0</ex></ph>".
+        Expected version "<ph name="EXPECTED_VERSION">$1<ex>2.0</ex></ph>", but version was "<ph name="NEW_ID">$2<ex>1.0</ex></ph>"
       </message>
       <message name="IDS_EXTENSION_INSTALL_DEPENDENCY_OLD_VERSION" desc="Error displayed during installation of an extension when an import dependency is older than the minimum version required.">
-        Extension requires "<ph name="IMPORT_NAME">$1<ex>Google Cast API</ex></ph>" with a minimum version "<ph name="IMPORT_VERSION">$2<ex>1.0</ex></ph>", but only version "<ph name="INSTALLED_VERSION">$3<ex>0.9</ex></ph>" is installed.
+        Extension requires "<ph name="IMPORT_NAME">$1<ex>Google Cast API</ex></ph>" with a minimum version "<ph name="IMPORT_VERSION">$2<ex>1.0</ex></ph>", but only version "<ph name="INSTALLED_VERSION">$3<ex>0.9</ex></ph>" is installed
       </message>
       <message name="IDS_EXTENSION_INSTALL_DEPENDENCY_NOT_SHARED_MODULE" desc="Error displayed during installation of an extension which tries to imports resources from an extension which is not a shared module.">
-        Unable to import extension "<ph name="IMPORT_NAME">$1<ex>Gmail</ex></ph>" because it is not a shared module.
+        Unable to import extension "<ph name="IMPORT_NAME">$1<ex>Gmail</ex></ph>" because it is not a shared module
       </message>
       <message name="IDS_EXTENSION_INSTALL_DEPENDENCY_NOT_WHITELISTED" desc="Error displayed during installation of an extension which tries to imports resources from an extension, but it is not whitelisted to do so.">
         Unable to install "<ph name="APP_NAME">$1<ex>Google Play Movies &amp; TV</ex></ph>" because it is not allowed by "<ph name="IMPORT_NAME">$2<ex>Google Cast API</ex></ph>"
       </message>
+      <message name="IDS_EXTENSION_INSTALL_GALLERY_ONLY" desc="Error displayed when an app or extension that has an update URL used by the gallery is installed when not directly downloaded from the gallery.">
+        This can only be added from the <ph name="CHROME_WEB_STORE">$1<ex>Web Store</ex></ph>
+      </message>
       <message name="IDS_EXTENSION_INSTALL_KIOSK_MODE_ONLY" desc="Error displayed during installation of an app with 'kiosk_only' attribute but user is not in Chrome OS kiosk mode.">
-        App with 'kiosk_only' manifest attribute must be installed in Chrome OS kiosk mode.
+        App with 'kiosk_only' manifest attribute must be installed in Chrome OS kiosk mode
       </message>
       <message name="IDS_EXTENSION_OVERLAPPING_WEB_EXTENT" desc="Error message when a user tries to install an app with a web extent that overlaps another installed app.">
         Could not add application "<ph name="TO_INSTALL_APP_NAME">$1<ex>Google Mail</ex></ph>" because it conflicts with "<ph name="INSTALLED_APP_NAME">$2<ex>Google Calendar</ex></ph>".
@@ -4780,10 +4780,10 @@
 
       <!-- Preview InfoBar -->
       <message name="IDS_PREVIEWS_INFOBAR_SAVED_DATA_TITLE" desc="The text of the infobar notifying the user that mobile data usage was reduced by showing a preview version of the web page instead of the full page.">
-         Saved data.
+         Saved data
       </message>
       <message name="IDS_PREVIEWS_INFOBAR_FASTER_PAGE_TITLE" desc="The text of the infobar notifying the user that a preview page has been shown to load faster.">
-         Faster page loaded.
+         Faster page loaded
       </message>
       <message name="IDS_PREVIEWS_INFOBAR_LINK" desc="The text of the link to load the original page from the infobar notifying the user that a preview page has been shown.">
          Show original
@@ -4969,7 +4969,7 @@
 
       <!-- Unimplemented Flags Infobar-->
       <message name="IDS_UNIMPLEMENTED_FLAGS_WARNING_MESSAGE" desc="Message shown when a command-line flag is used that is not implemented by this build. [Keep it short so it fits in the infobar.]">
-        <ph name="BAD_FLAG">$1<ex>--enable-heap-profiling</ex></ph> is not implemented in this build.
+        <ph name="BAD_FLAG">$1<ex>--enable-heap-profiling</ex></ph> is not implemented in this build
       </message>
 
       <!-- Bad Flags Infobar-->
@@ -4980,12 +4980,12 @@
       <!-- Pepper Broker Infobar -->
       <if expr="is_android">
         <message name="IDS_PEPPER_BROKER_MESSAGE" desc="Mobile: Message shown when a pepper plugin wants to launch its broker. This message is followed by a 'Learn more' link.">
-          <ph name="PEPPER_PLUGIN_NAME">$1<ex>Flash</ex></ph> on <ph name="PEPPER_PLUGIN_DOMAIN">$2<ex>example.com</ex></ph> wants to access your device.
+          <ph name="PEPPER_PLUGIN_NAME">$1<ex>Flash</ex></ph> on <ph name="PEPPER_PLUGIN_DOMAIN">$2<ex>example.com</ex></ph> wants to access your device
         </message>
       </if>
       <if expr="not is_android">
         <message name="IDS_PEPPER_BROKER_MESSAGE" desc="Message shown when a pepper plugin wants to launch its broker. This message is followed by a 'Learn more' link.">
-          <ph name="PEPPER_PLUGIN_NAME">$1<ex>Flash</ex></ph> on <ph name="PEPPER_PLUGIN_DOMAIN">$2<ex>example.com</ex></ph> wants to access your computer.
+          <ph name="PEPPER_PLUGIN_NAME">$1<ex>Flash</ex></ph> on <ph name="PEPPER_PLUGIN_DOMAIN">$2<ex>example.com</ex></ph> wants to access your computer
         </message>
       </if>
       <message name="IDS_PEPPER_BROKER_ALLOW_BUTTON" desc="Text for the allow button on the pepper broker launch prompt">
@@ -5059,7 +5059,7 @@
 
       <!-- chromeos bookmark app add to shelf strings -->
       <message name="IDS_ADD_TO_SHELF_INFOBAR_TITLE" desc="Label displayed in an infobar asking users to add to the site to their shelf">
-        Add this site to your shelf to use it any time.
+        Add this site to your shelf to use it any time
       </message>
       <message name="IDS_ADD_TO_SHELF_INFOBAR_ADD_BUTTON" desc="Text displayed on the button to allow users to add to the site to their shelf">
         Add
@@ -5315,7 +5315,7 @@
       </message>
       <if expr="is_android">
         <message name="IDS_ACCESSIBILITY_EVENTS_INFOBAR_TEXT" desc="Text requesting permission for a site to listen to accessibility events, for example if the user has a screen reader or braille device enabled">
-          <ph name="URL">$1<ex>maps.google.com</ex></ph> wants to respond to accessibility events.
+          <ph name="URL">$1<ex>maps.google.com</ex></ph> wants to respond to accessibility events
         </message>
       </if>
 
@@ -5427,7 +5427,7 @@
         </message>
       </if>
       <message name="IDS_BROWSER_HANGMONITOR_PLUGIN_INFOBAR" desc="The text of the infobar notifying the user that a plugin has hung">
-        A plugin (<ph name="PLUGIN_NAME">$1<ex>Flash</ex></ph>) isn't responding.
+        <ph name="PLUGIN_NAME">$1<ex>Flash</ex></ph> isn't responding
       </message>
       <message name="IDS_BROWSER_HANGMONITOR_PLUGIN_INFOBAR_KILLBUTTON" desc="The button on the hung plugin infobar (...PLUGIN_INFOBAR above) to terminate the plugin">
         Stop plugin
@@ -5851,7 +5851,7 @@
       <!-- Automatic updates -->
       <if expr="is_macosx">
         <message name="IDS_PROMOTE_INFOBAR_TEXT" desc="The text to show in the automatic update setup infobar.  Mac-only.">
-          <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> may not be able to keep itself updated.
+          <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> may not be able to keep itself updated
         </message>
         <message name="IDS_PROMOTE_INFOBAR_PROMOTE_BUTTON" desc="The 'Set up automatic updates' button in the automatic update setup infobar.  Mac-only.">
           Set up automatic updates
@@ -6205,10 +6205,10 @@
         <message name="IDS_PRINT_PREVIEW_DESTINATION_COUNT" desc="Message to show how many print destinations the user has.">
           (<ph name="COUNT">$1<ex>154</ex></ph> total)
         </message>
-        <message name="IDS_PRINT_PREVIEW_RECENT_DESTINATIONS_TITLE" desc="Title of the section of recently used print destinations.">
+        <message name="IDS_PRINT_PREVIEW_RECENT_DESTINATIONS_TITLE" desc="Title of the section in the Print Preview dialog that lists recently used printers that the user can print to. 'Destinations' is used because the list may include 'Saving as PDF' or other options that are not physical printers.">
           Recent Destinations
         </message>
-        <message name="IDS_PRINT_PREVIEW_PRINT_DESTINATIONS_TITLE" desc="Title of the section of print destinations.">
+        <message name="IDS_PRINT_PREVIEW_PRINT_DESTINATIONS_TITLE" desc="Title of the section in the Print Preview dialog that lists all printers that the user can print to. 'Destinations' is used because the list may include 'Saving as PDF' or other options that are not physical printers.">
           Print Destinations
         </message>
         <message name="IDS_PRINT_PREVIEW_MANAGE" desc="Text of link to manage printers.">
@@ -6999,7 +6999,7 @@
         Cleared on Exit
       </message>
       <message name="IDS_COLLECTED_COOKIES_INFOBAR_MESSAGE" desc="The string shown in the infobar after the user has changed the allowed/blocked state of a cookie, reminding them to reload the page in order for the new cookies to take effect.">
-        New cookie settings will take effect after reloading the page.
+        New cookie settings will take effect after reloading the page
       </message>
       <message name="IDS_COLLECTED_COOKIES_INFOBAR_BUTTON" desc="The string used in the infobar button allowing the user to reload the page directly from the infobar.">
         Reload
@@ -7953,24 +7953,24 @@
       </message>
 
       <message name="IDS_PLUGIN_OUTDATED_PROMPT" desc="Infobar message when an outdated plugin was disabled">
-        <ph name="PLUGIN_NAME">$1<ex>Flash</ex></ph> was blocked because it is out of date.
+        <ph name="PLUGIN_NAME">$1<ex>Flash</ex></ph> was blocked because it is out of date
       </message>
       <message name="IDS_PLUGIN_ENABLE_TEMPORARILY" desc="Infobar button to run a blocked outdated plugin">
         Run this time
       </message>
       <message name="IDS_PLUGIN_CRASHED_PROMPT" desc="Infobar message to notify about a crashed plugin">
-       <ph name="PLUGIN_NAME">$1<ex>Flash</ex></ph> has crashed.
+       <ph name="PLUGIN_NAME">$1<ex>Flash</ex></ph> has crashed
       </message>
       <if expr="is_win">
         <message name="IDS_PLUGIN_DISCONNECTED_PROMPT" desc="Infobar message to notify that the channel connecting to a plugin has encountered an error.">
-          <ph name="PLUGIN_NAME">$1<ex>Flash</ex></ph> has encountered an error.
+          <ph name="PLUGIN_NAME">$1<ex>Flash</ex></ph> has encountered an error
         </message>
       </if>
       <message name="IDS_RELOAD_PAGE_WITH_PLUGIN" desc="Infobar button to reload the page where a plugin crashed or disconnected.">
         Reload
       </message>
       <message name="IDS_PLUGIN_INITIALIZATION_ERROR_PROMPT" desc="Infobar message to notify that we couldn't load a plugin">
-        Could not load <ph name="PLUGIN_NAME">$1<ex>Flash</ex></ph>.
+        Could not load <ph name="PLUGIN_NAME">$1<ex>Flash</ex></ph>
       </message>
 
       <!-- External Protocol Dialog -->
@@ -9122,12 +9122,12 @@
       <!-- Geolocation messages -->
       <if expr="not is_android">
         <message name="IDS_GEOLOCATION_INFOBAR_TEXT" desc="Text requesting permission for a site to access the user's physical location">
-          <ph name="URL">$1<ex>maps.google.com</ex></ph> wants to use your computer's location.
+          <ph name="URL">$1<ex>maps.google.com</ex></ph> wants to use your computer's location
         </message>
       </if>
       <if expr="is_android">
         <message name="IDS_GEOLOCATION_INFOBAR_TEXT" desc="Mobile: Text requesting permission for a site to access the user's physical location">
-          <ph name="URL">$1<ex>maps.google.com</ex></ph> wants to use your device's location.
+          <ph name="URL">$1<ex>maps.google.com</ex></ph> wants to use your device's location
         </message>
       </if>
       <message name="IDS_GEOLOCATION_INFOBAR_PERMISSION_FRAGMENT" desc="Permission fragment used in the permission bubble, after 'This site wants to:' asking for permission to access the user's physical location.">
@@ -9157,7 +9157,7 @@
 
       <!-- Web MIDI messages -->
       <message name="IDS_MIDI_SYSEX_INFOBAR_TEXT" desc="Text requesting permission for a site to access MIDI devices with system exclusive messages.">
-        <ph name="URL">$1<ex>www.google.com</ex></ph> wants to get full control of your MIDI devices.
+        <ph name="URL">$1<ex>www.google.com</ex></ph> wants to get full control of your MIDI devices
       </message>
       <message name="IDS_MIDI_SYSEX_PERMISSION_FRAGMENT" desc="Permission asked in the permission bubble when a URL wants to access MIDI devices with system exclusive messages, along with other permissions requests. Preceded by the prompt 'This site would like to:'">
         Use your MIDI devices
@@ -9247,7 +9247,7 @@
           Know your unique device identifier
         </message>
         <message name="IDS_PROTECTED_MEDIA_IDENTIFIER_INFOBAR_TEXT" desc="Text requesting permission for a site to access protected media identifier. It shows the origin of the URL.">
-          <ph name="URL">$1<ex>https://www.youtube.com</ex></ph> wants to uniquely identify your device to play protected content.
+          <ph name="URL">$1<ex>https://www.youtube.com</ex></ph> wants to uniquely identify your device to play protected content
         </message>
       </if>
 
@@ -9370,12 +9370,12 @@
       <!-- File Selection Dialog Policy - Infobar -->
       <if expr="is_android">
         <message name="IDS_FILE_SELECTION_DIALOG_INFOBAR" desc="Mobile: Infobar message on disallowed file selection dialog.">
-          Access to local files on your device is disabled by your administrator.
+          Access to local files on your device is disabled by your administrator
         </message>
       </if>
       <if expr="not is_android">
         <message name="IDS_FILE_SELECTION_DIALOG_INFOBAR" desc="Infobar message on disallowed file selection dialog.">
-          Access to local files on your machine is disabled by your administrator.
+          Access to local files on your machine is disabled by your administrator
         </message>
       </if>
 
@@ -9481,16 +9481,16 @@
 
       <!-- Media Capture messages -->
       <message name="IDS_MEDIA_CAPTURE_AUDIO_AND_VIDEO_INFOBAR_TEXT" desc="Text requesting permission for a site to access the computer's microphone and camera.">
-        <ph name="HOST">$1<ex>html5rocks.com</ex></ph> wants to use your camera and microphone.
+        <ph name="HOST">$1<ex>html5rocks.com</ex></ph> wants to use your camera and microphone
       </message>
       <message name="IDS_MEDIA_CAPTURE_AUDIO_ONLY_INFOBAR_TEXT" desc="Text requesting permission for a site to access the computer's microphone.">
-        <ph name="HOST">$1<ex>html5rocks.com</ex></ph> wants to use your microphone.
+        <ph name="HOST">$1<ex>html5rocks.com</ex></ph> wants to use your microphone
       </message>
       <message name="IDS_MEDIA_CAPTURE_VIDEO_ONLY_INFOBAR_TEXT" desc="Text requesting permission for a site to access the computer's camera.">
-        <ph name="HOST">$1<ex>html5rocks.com</ex></ph> wants to use your camera.
+        <ph name="HOST">$1<ex>html5rocks.com</ex></ph> wants to use your camera
       </message>
       <message name="IDS_MEDIA_CAPTURE_SCREEN_INFOBAR_TEXT" desc="Text requesting permission for a site to access the device's screen.">
-        <ph name="HOST">$1<ex>html5rocks.com</ex></ph> wants to share your screen.
+        <ph name="HOST">$1<ex>html5rocks.com</ex></ph> wants to share your screen
       </message>
       <message name="IDS_MEDIA_CAPTURE_AUDIO_AND_VIDEO_PERMISSION_FRAGMENT" desc="Permission fragment shown in the permissions bubble when a web page requests access to the computer's microphone and camera.">
         Use your camera and microphone
@@ -9511,18 +9511,18 @@
       <!-- Quota messages -->
       <if expr="is_android">
         <message name="IDS_REQUEST_QUOTA_INFOBAR_TEXT" desc="Mobile: For Android device. Text requesting permission for a site to use a new (larger) quota to persistently store data on the device (e.g. for persistent-type filesystem).">
-          <ph name="URL">$1<ex>html5rocks.com</ex></ph> wants to permanently store data on your device.
+          <ph name="URL">$1<ex>html5rocks.com</ex></ph> wants to permanently store data on your device
         </message>
         <message name="IDS_REQUEST_LARGE_QUOTA_INFOBAR_TEXT" desc="Mobile: For Android device. Text requesting permission for a site to use a new (larger) quota to persistently store large data on the user's device (e.g. for persistent-type filesystem).">
-          <ph name="URL">$1<ex>html5rocks.com</ex></ph> wants to permanently store large data on your device.
+          <ph name="URL">$1<ex>html5rocks.com</ex></ph> wants to permanently store large data on your device
         </message>
       </if>
       <if expr="not is_android">
         <message name="IDS_REQUEST_QUOTA_INFOBAR_TEXT" desc="Text requesting permission for a site to use a new (larger) quota to persistently store data on the user's local computer (e.g. for persistent-type filesystem).">
-          <ph name="URL">$1<ex>html5rocks.com</ex></ph> wants to permanently store data on your local computer.
+          <ph name="URL">$1<ex>html5rocks.com</ex></ph> wants to permanently store data on your local computer
         </message>
         <message name="IDS_REQUEST_LARGE_QUOTA_INFOBAR_TEXT" desc="Text requesting permission for a site to use a new (larger) quota to persistently store large data on the user's local computer (e.g. for persistent-type filesystem).">
-          <ph name="URL">$1<ex>html5rocks.com</ex></ph> wants to permanently store large data on your local computer.
+          <ph name="URL">$1<ex>html5rocks.com</ex></ph> wants to permanently store large data on your local computer
         </message>
       </if>
       <message name="IDS_REQUEST_QUOTA_PERMISSION_FRAGMENT" desc="Permission fragment presented in the permission bubble when the webapp requests new larger quota to persistently store data on the device. Follows a 'This site would like to:' prompt.">
@@ -9914,11 +9914,11 @@
         </message>
         <message name="IDS_METRO_MISSING_PLUGIN_PROMPT"
                  desc="Infobar message to let user do something about the missing plugin">
-          <ph name="PLUGIN_NAME">$1<ex>Quicktime</ex></ph> is required to display some elements on this page.
+          <ph name="PLUGIN_NAME">$1<ex>Quicktime</ex></ph> is required to display some elements on this page
         </message>
         <message name="IDS_METRO_NPAPI_PLUGIN_PROMPT"
                  desc="Infobar message when an NPAPI plugin doesn't run in Metro mode.">
-          <ph name="PLUGIN_NAME">$1<ex>Quicktime</ex></ph> only works on the desktop.
+          <ph name="PLUGIN_NAME">$1<ex>Quicktime</ex></ph> only works on the desktop
         </message>
         <message name="IDS_METRO_DOWNLOAD_COMPLETE_NOTIFICATION"
                 desc="Notification displayed when a download request is completed">
@@ -9999,9 +9999,6 @@
         <message name="IDS_SEARCH_BOX_ACCESSIBILITY_NAME_TABLET" desc="Hint text for the search box in fullscreen app list window. Tablet mode only, so we don't mention the arrow keys.">
           Search your device, apps, and web.
         </message>
-        <message name="IDS_SEARCH_BOX_HINT" desc="Hint text for the search box in app list window.">
-          Search or type URL
-        </message>
         <message name="IDS_SEARCH_BOX_HINT_FULLSCREEN" desc="Hint text for the search box in fullscreen app list window.">
           Search your device, apps, web...
         </message>
diff --git a/chrome/app/google_chrome_strings.grd b/chrome/app/google_chrome_strings.grd
index b8bcc807..3a26441 100644
--- a/chrome/app/google_chrome_strings.grd
+++ b/chrome/app/google_chrome_strings.grd
@@ -404,7 +404,7 @@
         </message>
       </if>
       <message name="IDS_DEFAULT_BROWSER_INFOBAR_TEXT" desc="Text to show in an infobar when Google Chrome is not the current default browser.">
-        Google Chrome isn't your default browser.
+        Google Chrome isn't your default browser
       </message>
       <if expr="chromeos">
         <message name="IDS_SYNC_OVERVIEW" desc="Chrome OS: The message that appears in the options dialog when sync has not been set up by the user.">
@@ -1118,19 +1118,19 @@
       <!-- Runtime permission strings -->
       <if expr="is_android">
         <message name="IDS_INFOBAR_MISSING_CAMERA_PERMISSION_TEXT" desc="Text shown in an infobar when a website has requested access to the camera capabilities, but Chrome is missing the Android camera permission.">
-          Chrome needs permission to access your camera for this site.
+          Chrome needs permission to access your camera for this site
         </message>
         <message name="IDS_INFOBAR_MISSING_MICROPHONE_PERMISSION_TEXT" desc="Text shown in an infobar when a website has requested access to the microphone capabilities, but Chrome is missing the Android microphone permission.">
-          Chrome needs permission to access your microphone for this site.
+          Chrome needs permission to access your microphone for this site
         </message>
         <message name="IDS_INFOBAR_MISSING_MICROPHONE_CAMERA_PERMISSIONS_TEXT" desc="Text shown in an infobar when a website has requested access to the microphone and camera capabilities, but Chrome is missing the Android microphone and camera permissions.">
-          Chrome needs permission to access your camera and microphone for this site.
+          Chrome needs permission to access your camera and microphone for this site
         </message>
         <message name="IDS_INFOBAR_MISSING_LOCATION_PERMISSION_TEXT" desc="Text shown in an infobar when a website has requested access to the location capabilities, but Chrome is missing the Android location permission.">
-          Chrome needs access to your location to share your location with this site.
+          Chrome needs access to your location to share your location with this site
         </message>
         <message name="IDS_MISSING_STORAGE_PERMISSION_DOWNLOAD_EDUCATION_TEXT" desc="Text shown educating the user that Chrome is missing the Android storage permission, which is required to download files.">
-          Chrome needs storage access to download files.
+          Chrome needs storage access to download files
         </message>
       </if>
 
diff --git a/chrome/app/settings_strings.grdp b/chrome/app/settings_strings.grdp
index c6d45433..5e520bc 100644
--- a/chrome/app/settings_strings.grdp
+++ b/chrome/app/settings_strings.grdp
@@ -2471,6 +2471,9 @@
   <message name="IDS_SETTINGS_SITE_SETTINGS_SOUND" desc="Label for the sound site settings.">
     Sound
   </message>
+  <message name="IDS_SETTINGS_SITE_SETTINGS_SENSORS" desc="Label for the sensors permission in Site Settings. Sensors are motion and light sensors, specifically accelerometers, gyroscope, magnetometers, and ambient-light sensors">
+    Motion or Light Sensors
+  </message>
   <message name="IDS_SETTINGS_SITE_SETTINGS_USB_DEVICES" desc="Label for the USB devices in site settings.">
     USB devices
   </message>
@@ -2558,6 +2561,12 @@
   <message name="IDS_SETTINGS_SITE_SETTINGS_SOUND_BLOCK" desc="The block label for sound in site settings.">
     Mute sites that play sound
   </message>
+  <message name="IDS_SETTINGS_SITE_SETTINGS_SENSORS_ALLOW" desc="The allow label for sensors feature in site settings.">
+    Allow sites to use motion and light sensors
+  </message>
+  <message name="IDS_SETTINGS_SITE_SETTINGS_SENSORS_BLOCK" desc="The block label for sensors feature in site settings.">
+    Block sites from using motion and light sensors
+  </message>
   <message name="IDS_SETTINGS_SITE_SETTINGS_AUTOMATIC_DOWNLOAD_ASK" desc="The allow label for automatic download in site settings.">
     Ask when a site tries to download files automatically after the first file
   </message>
@@ -3838,7 +3847,7 @@
     <message name="IDS_SETTINGS_RESET_CLEANUP_TITLE_ERROR_SCANNING_FAILED" desc="Title of error message that could appear during the cleanup of harmful software.">
       Scanning failed
     </message>
-    <message name="IDS_SETTINGS_RESET_CLEANUP_TRY_AGAIN_BUTTON_LABEL" desc="Generic button that appears next to a message indicating that an operation failed during the cleanup of harmful software.">
+    <message name="IDS_SETTINGS_RESET_CLEANUP_TRY_AGAIN_BUTTON_LABEL" desc="Generic button that appears next to a message indicating that an operation failed during the cleanup of harmful software." meaning="Button referred to in the string 'Click Try Again, and accept the prompt on your computer', IDS_SETTINGS_RESET_CLEANUP_EXPLANATION_PERMISSIONS_NEEDED">
       Try again
     </message>
     <message name="IDS_SETTINGS_RESET_CLEANUP_LOGS_PERMISSION_EXPLANATION" desc="Description for the 'Report details to Google' option. Subject, 'Details', is omitted. Although the plural subject would indicate usage of the plural verb, here, we use the plural form of the verb, 'includes', to avoid the impression that 'include' is an infinitive verb. 'Includes' is a present tense main verb. ">
diff --git a/chrome/app/theme/theme_resources.grd b/chrome/app/theme/theme_resources.grd
index 15a3cbd..b7bb5e6 100644
--- a/chrome/app/theme/theme_resources.grd
+++ b/chrome/app/theme/theme_resources.grd
@@ -25,9 +25,6 @@
       <!-- KEEP THESE IN ALPHABETICAL ORDER!  DO NOT ADD TO RANDOM PLACES JUST
            BECAUSE YOUR RESOURCES ARE FUNCTIONALLY RELATED OR FALL UNDER THE
            SAME CONDITIONALS. -->
-      <if expr="enable_app_list and _google_chrome">
-        <structure type="chrome_scaled_image" name="IDR_APP_LIST_GOOGLE_LOGO_VOICE_SEARCH" file="google_chrome/google_logo_voice_search.png" />
-      </if>
       <if expr="enable_app_list">
         <structure type="chrome_scaled_image" name="IDR_APP_LIST_TAB_OVERLAY" file="common/app_list_v1_overlay.png" />
       </if>
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index d9c457cd..28cf756 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -107,6 +107,7 @@
 #include "ppapi/features/features.h"
 #include "printing/features/features.h"
 #include "services/device/public/cpp/device_features.h"
+#include "services/network/public/cpp/network_switches.h"
 #include "services/service_manager/sandbox/switches.h"
 #include "third_party/libaom/av1_features.h"
 #include "ui/app_list/app_list_features.h"
@@ -312,12 +313,6 @@
     {flag_descriptions::kDefaultTileHeightVenti, switches::kDefaultTileHeight,
      "1024"}};
 
-#if !BUILDFLAG(ENABLE_MIRROR)
-
-const FeatureEntry::FeatureParam kAccountConsistencyMirror[] = {
-    {signin::kAccountConsistencyFeatureMethodParameter,
-     signin::kAccountConsistencyFeatureMethodMirror}};
-
 #if BUILDFLAG(ENABLE_DICE_SUPPORT)
 const FeatureEntry::FeatureParam kAccountConsistencyDice[] = {
     {signin::kAccountConsistencyFeatureMethodParameter,
@@ -327,12 +322,6 @@
     {signin::kAccountConsistencyFeatureMethodParameter,
      signin::kAccountConsistencyFeatureMethodDicePrepareMigration}};
 
-const FeatureEntry::FeatureParam
-    kAccountConsistencyDicePrepareMigrationChromeSyncEndpoint[] = {
-        {signin::kAccountConsistencyFeatureMethodParameter,
-         signin::
-             kAccountConsistencyFeatureMethodDicePrepareMigrationChromeSyncEndpoint}};
-
 const FeatureEntry::FeatureParam kAccountConsistencyDiceMigration[] = {
     {signin::kAccountConsistencyFeatureMethodParameter,
      signin::kAccountConsistencyFeatureMethodDiceMigration}};
@@ -340,31 +329,20 @@
 const FeatureEntry::FeatureParam kAccountConsistencyDiceFixAuthErrors[] = {
     {signin::kAccountConsistencyFeatureMethodParameter,
      signin::kAccountConsistencyFeatureMethodDiceFixAuthErrors}};
-#endif  // BUILDFLAG(ENABLE_DICE_SUPPORT)
 
 const FeatureEntry::FeatureVariation kAccountConsistencyFeatureVariations[] = {
-    {"Mirror", kAccountConsistencyMirror, arraysize(kAccountConsistencyMirror),
-     nullptr /* variation_id */}
-#if BUILDFLAG(ENABLE_DICE_SUPPORT)
-    ,
     {"Dice", kAccountConsistencyDice, arraysize(kAccountConsistencyDice),
      nullptr /* variation_id */},
     {"Dice (migration)", kAccountConsistencyDiceMigration,
      arraysize(kAccountConsistencyDiceMigration), nullptr /* variation_id */},
-    {"Dice (prepare migration)", kAccountConsistencyDicePrepareMigration,
-     arraysize(kAccountConsistencyDicePrepareMigration),
-     nullptr /* variation_id */},
     {"Dice (prepare migration, Chrome sync endpoint)",
-     kAccountConsistencyDicePrepareMigrationChromeSyncEndpoint,
-     arraysize(kAccountConsistencyDicePrepareMigrationChromeSyncEndpoint),
+     kAccountConsistencyDicePrepareMigration,
+     arraysize(kAccountConsistencyDicePrepareMigration),
      nullptr /* variation_id */},
     {"Dice (fix auth errors)", kAccountConsistencyDiceFixAuthErrors,
      arraysize(kAccountConsistencyDiceFixAuthErrors),
-     nullptr /* variation_id */}
+     nullptr /* variation_id */}};
 #endif  // BUILDFLAG(ENABLE_DICE_SUPPORT)
-};
-
-#endif  // !BUILDFLAG(ENABLE_MIRROR)
 
 const FeatureEntry::Choice kSimpleCacheBackendChoices[] = {
     {flags_ui::kGenericExperimentChoiceDefault, "", ""},
@@ -1487,7 +1465,7 @@
 #endif  // ENABLE_PLUGINS
 #if defined(OS_CHROMEOS)
     {"ash-enable-night-light", flag_descriptions::kEnableNightLightName,
-     flag_descriptions::kEnableNightLightDescription, kOsCrOS,
+     flag_descriptions::kEnableNightLightDescription, kOsAll,
      SINGLE_VALUE_TYPE(ash::switches::kAshEnableNightLight)},
     {"allow-touchpad-three-finger-click",
      flag_descriptions::kAllowTouchpadThreeFingerClickName,
@@ -1545,10 +1523,6 @@
     {"show-touch-hud", flag_descriptions::kShowTouchHudName,
      flag_descriptions::kShowTouchHudDescription, kOsCrOS,
      SINGLE_VALUE_TYPE(ash::switches::kAshTouchHud)},
-    {"ash-disable-v1-app-back-button",
-     flag_descriptions::kAshDisableV1AppBackButtonName,
-     flag_descriptions::kAshDisableV1AppBackButtonDescription, kOsCrOS,
-     SINGLE_VALUE_TYPE(ash::switches::kAshDisableV1AppBackButton)},
 #endif  // OS_CHROMEOS
     {
         "disable-accelerated-video-decode",
@@ -1610,11 +1584,9 @@
      flag_descriptions::kPasswordGenerationDescription, kOsAll,
      ENABLE_DISABLE_VALUE_TYPE(autofill::switches::kEnablePasswordGeneration,
                                autofill::switches::kDisablePasswordGeneration)},
-    {"PasswordForceSaving",
-     flag_descriptions::kPasswordForceSavingName,
+    {"PasswordForceSaving", flag_descriptions::kPasswordForceSavingName,
      flag_descriptions::kPasswordForceSavingDescription, kOsAll,
-     FEATURE_VALUE_TYPE(
-         password_manager::features::kPasswordForceSaving)},
+     FEATURE_VALUE_TYPE(password_manager::features::kPasswordForceSaving)},
     {"enable-manual-password-generation",
      flag_descriptions::kManualPasswordGenerationName,
      flag_descriptions::kManualPasswordGenerationDescription, kOsAll,
@@ -1784,7 +1756,7 @@
      flag_descriptions::kWebglDraftExtensionsName,
      flag_descriptions::kWebglDraftExtensionsDescription, kOsAll,
      SINGLE_VALUE_TYPE(switches::kEnableWebGLDraftExtensions)},
-#if !BUILDFLAG(ENABLE_MIRROR)
+#if BUILDFLAG(ENABLE_DICE_SUPPORT)
     {"account-consistency", flag_descriptions::kAccountConsistencyName,
      flag_descriptions::kAccountConsistencyDescription, kOsAll,
      FEATURE_WITH_PARAMS_VALUE_TYPE(signin::kAccountConsistencyFeature,
@@ -3456,7 +3428,7 @@
     {"enable-manual-password-saving",
      flag_descriptions::kManualPasswordSavingName,
      flag_descriptions::kManualPasswordSavingDescription, kOsDesktop,
-     FEATURE_VALUE_TYPE(password_manager::features::kEnableManualSaving)},
+     FEATURE_VALUE_TYPE(password_manager::features::kManualSaving)},
 
 #if !defined(OS_ANDROID)
     {"remove-deprecared-gaia-signin-endpoint",
@@ -3638,7 +3610,7 @@
     {"enable-network-logging-to-file",
      flag_descriptions::kEnableNetworkLoggingToFileName,
      flag_descriptions::kEnableNetworkLoggingToFileDescription, kOsAll,
-     SINGLE_VALUE_TYPE(switches::kLogNetLog)},
+     SINGLE_VALUE_TYPE(network::switches::kLogNetLog)},
 
 #if defined(OS_CHROMEOS)
     {"enable-multi-mirroring", flag_descriptions::kDisableMultiMirroringName,
@@ -3678,6 +3650,12 @@
      FEATURE_VALUE_TYPE(features::kWebAuth)},
 #endif  // !defined(OS_ANDROID)
 
+#if defined(OS_ANDROID)
+    {"enable-sole-integration", flag_descriptions::kSoleIntegrationName,
+     flag_descriptions::kSoleIntegrationDescription, kOsAndroid,
+     FEATURE_VALUE_TYPE(chrome::android::kSoleIntegration)},
+#endif  // defined(OS_ANDROID)
+
     // NOTE: Adding a new flag requires adding a corresponding entry to enum
     // "LoginCustomFlags" in tools/metrics/histograms/enums.xml. See "Flag
     // Histograms" in tools/metrics/histograms/README.md (run the
diff --git a/chrome/browser/android/chrome_feature_list.cc b/chrome/browser/android/chrome_feature_list.cc
index 3eb51f0..a00bd297 100644
--- a/chrome/browser/android/chrome_feature_list.cc
+++ b/chrome/browser/android/chrome_feature_list.cc
@@ -115,6 +115,7 @@
     &kReaderModeInCCT,
     &kSearchEnginePromoExistingDevice,
     &kSearchEnginePromoNewDevice,
+    &kSoleIntegration,
     &kSpannableInlineAutocomplete,
     &kSpecialLocaleFeature,
     &kSpecialLocaleWrapper,
@@ -347,6 +348,9 @@
 const base::Feature kReaderModeInCCT{"ReaderModeInCCT",
                                      base::FEATURE_DISABLED_BY_DEFAULT};
 
+const base::Feature kSoleIntegration{"SoleIntegration",
+                                     base::FEATURE_DISABLED_BY_DEFAULT};
+
 const base::Feature kSpannableInlineAutocomplete{
     "SpannableInlineAutocomplete", base::FEATURE_ENABLED_BY_DEFAULT};
 
diff --git a/chrome/browser/android/chrome_feature_list.h b/chrome/browser/android/chrome_feature_list.h
index 9ce8cd2..17f1fc5 100644
--- a/chrome/browser/android/chrome_feature_list.h
+++ b/chrome/browser/android/chrome_feature_list.h
@@ -74,6 +74,7 @@
 extern const base::Feature kPwaImprovedSplashScreen;
 extern const base::Feature kPwaPersistentNotification;
 extern const base::Feature kReaderModeInCCT;
+extern const base::Feature kSoleIntegration;
 extern const base::Feature kSpannableInlineAutocomplete;
 extern const base::Feature kSpecialLocaleFeature;
 extern const base::Feature kSpecialLocaleWrapper;
diff --git a/chrome/browser/browser_process_impl.cc b/chrome/browser/browser_process_impl.cc
index a7b5b13..bafe286 100644
--- a/chrome/browser/browser_process_impl.cc
+++ b/chrome/browser/browser_process_impl.cc
@@ -131,6 +131,7 @@
 #include "net/url_request/url_request_context_getter.h"
 #include "ppapi/features/features.h"
 #include "printing/features/features.h"
+#include "services/network/public/cpp/network_switches.h"
 #include "services/preferences/public/cpp/in_process_service_factory.h"
 #include "ui/base/idle/idle.h"
 #include "ui/base/l10n/l10n_util.h"
@@ -1078,9 +1079,9 @@
       extensions::kExtensionScheme, true);
 #endif
 
-  if (command_line.HasSwitch(switches::kLogNetLog)) {
+  if (command_line.HasSwitch(network::switches::kLogNetLog)) {
     base::FilePath log_file =
-        command_line.GetSwitchValuePath(switches::kLogNetLog);
+        command_line.GetSwitchValuePath(network::switches::kLogNetLog);
     if (log_file.empty()) {
       base::FilePath user_data_dir;
       bool success =
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index d6cf360..201a3f4 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -318,6 +318,7 @@
 #include "chrome/browser/payments/payment_request_factory.h"
 #include "chrome/browser/search/instant_service.h"
 #include "chrome/browser/search/instant_service_factory.h"
+#include "chrome/browser/ui/search/new_tab_page_navigation_throttle.h"
 #include "chrome/common/importer/profile_import.mojom.h"
 #endif
 
@@ -3503,6 +3504,11 @@
       DevToolsWindow::MaybeCreateNavigationThrottle(handle);
   if (devtools_throttle)
     throttles.push_back(std::move(devtools_throttle));
+
+  std::unique_ptr<content::NavigationThrottle> new_tab_page_throttle =
+      NewTabPageNavigationThrottle::MaybeCreateThrottleFor(handle);
+  if (new_tab_page_throttle)
+    throttles.push_back(std::move(new_tab_page_throttle));
 #endif
 
   return throttles;
diff --git a/chrome/browser/chromeos/arc/enterprise/arc_cert_store_bridge_browsertest.cc b/chrome/browser/chromeos/arc/enterprise/arc_cert_store_bridge_browsertest.cc
index 46c9eec..2507212 100644
--- a/chrome/browser/chromeos/arc/enterprise/arc_cert_store_bridge_browsertest.cc
+++ b/chrome/browser/chromeos/arc/enterprise/arc_cert_store_bridge_browsertest.cc
@@ -251,7 +251,8 @@
     std::string client_cert1_spki(
         client_cert1_->derPublicKey.data,
         client_cert1_->derPublicKey.data + client_cert1_->derPublicKey.len);
-    permissions_for_ext->RegisterKeyForCorporateUsage(client_cert1_spki);
+    permissions_for_ext->RegisterKeyForCorporateUsage(
+        client_cert1_spki, {chromeos::KeyPermissions::KeyLocation::kUserSlot});
     done_callback.Run();
   }
 
diff --git a/chrome/browser/chromeos/platform_keys/key_permissions.cc b/chrome/browser/chromeos/platform_keys/key_permissions.cc
index c2f6d98..4b50694b 100644
--- a/chrome/browser/chromeos/platform_keys/key_permissions.cc
+++ b/chrome/browser/chromeos/platform_keys/key_permissions.cc
@@ -145,6 +145,13 @@
   return allow_corporate_key_usage;
 }
 
+bool IsKeyOnUserSlot(
+    const std::vector<KeyPermissions::KeyLocation>& key_locations) {
+  return std::find(key_locations.begin(), key_locations.end(),
+                   KeyPermissions::KeyLocation::kUserSlot) !=
+         key_locations.end();
+}
+
 }  // namespace
 
 struct KeyPermissions::PermissionsForExtension::KeyEntry {
@@ -188,7 +195,11 @@
 }
 
 bool KeyPermissions::PermissionsForExtension::CanUseKeyForSigning(
-    const std::string& public_key_spki_der) {
+    const std::string& public_key_spki_der,
+    const std::vector<KeyLocation>& key_locations) {
+  if (key_locations.empty())
+    return false;
+
   std::string public_key_spki_der_b64;
   base::Base64Encode(public_key_spki_der, &public_key_spki_der_b64);
 
@@ -206,8 +217,10 @@
 
   // Usage of corporate keys is solely determined by policy. The user must not
   // circumvent this decision.
-  if (key_permissions_->IsCorporateKey(public_key_spki_der_b64))
+  if (key_permissions_->IsCorporateKey(public_key_spki_der_b64,
+                                       key_locations)) {
     return PolicyAllowsCorporateKeyUsage();
+  }
 
   // Only permissions for keys that are not designated for corporate usage are
   // determined by user decisions.
@@ -215,16 +228,18 @@
 }
 
 void KeyPermissions::PermissionsForExtension::SetKeyUsedForSigning(
-    const std::string& public_key_spki_der) {
+    const std::string& public_key_spki_der,
+    const std::vector<KeyLocation>& key_locations) {
+  if (key_locations.empty())
+    return;
+
   std::string public_key_spki_der_b64;
   base::Base64Encode(public_key_spki_der, &public_key_spki_der_b64);
 
   KeyEntry* matching_entry = GetStateStoreEntry(public_key_spki_der_b64);
 
   if (!matching_entry->sign_once) {
-    if (matching_entry->sign_unlimited)
-      VLOG(1) << "Key is already marked as not usable for signing, skipping.";
-    else
+    if (!CanUseKeyForSigning(public_key_spki_der, key_locations))
       LOG(ERROR) << "Key was not allowed for signing.";
     return;
   }
@@ -234,7 +249,13 @@
 }
 
 void KeyPermissions::PermissionsForExtension::RegisterKeyForCorporateUsage(
-    const std::string& public_key_spki_der) {
+    const std::string& public_key_spki_der,
+    const std::vector<KeyLocation>& key_locations) {
+  if (key_locations.empty()) {
+    NOTREACHED();
+    return;
+  }
+
   std::string public_key_spki_der_b64;
   base::Base64Encode(public_key_spki_der, &public_key_spki_der_b64);
 
@@ -248,6 +269,14 @@
   matching_entry->sign_once = true;
   WriteToStateStore();
 
+  // Only register the key as corporate in the profile prefs if it is on the
+  // user slot. Keys on the system slot are implicitly corporate. We have still
+  // stored the sign_once permission, so the enrolling extension in the same
+  // profile can use the key for signing once in order to build a CSR even if it
+  // doesn't have permission to use corporate keys.
+  if (!IsKeyOnUserSlot(key_locations))
+    return;
+
   DictionaryPrefUpdate update(profile_prefs_, prefs::kPlatformKeys);
 
   std::unique_ptr<base::DictionaryValue> new_pref_entry(
@@ -259,14 +288,21 @@
 }
 
 void KeyPermissions::PermissionsForExtension::SetUserGrantedPermission(
-    const std::string& public_key_spki_der) {
-  if (!key_permissions_->CanUserGrantPermissionFor(public_key_spki_der)) {
+    const std::string& public_key_spki_der,
+    const std::vector<KeyLocation>& key_locations) {
+  if (!key_permissions_->CanUserGrantPermissionFor(public_key_spki_der,
+                                                   key_locations)) {
     LOG(WARNING) << "Tried to grant permission for a key although prohibited "
                     "(either key is a corporate key or this account is "
                     "managed).";
     return;
   }
 
+  // It only makes sense to store the sign_unlimited flag for a key if it is on
+  // a user slot. Currently, system-slot keys are implicitly corporate, so
+  // CanUserGrantPermissionForKey should return false for them.
+  DCHECK(IsKeyOnUserSlot(key_locations));
+
   std::string public_key_spki_der_b64;
   base::Base64Encode(public_key_spki_der, &public_key_spki_der_b64);
   KeyEntry* matching_entry = GetStateStoreEntry(public_key_spki_der_b64);
@@ -389,7 +425,8 @@
 }
 
 bool KeyPermissions::CanUserGrantPermissionFor(
-    const std::string& public_key_spki_der) const {
+    const std::string& public_key_spki_der,
+    const std::vector<KeyLocation>& key_locations) const {
   // As keys cannot be tagged for non-corporate usage, the user can currently
   // not grant any permissions if the profile is managed.
   if (profile_is_managed_)
@@ -400,7 +437,7 @@
 
   // If this profile is not managed but we find a corporate key, don't allow
   // the user to grant permissions.
-  return !IsCorporateKey(public_key_spki_der_b64);
+  return !IsCorporateKey(public_key_spki_der_b64, key_locations);
 }
 
 // static
@@ -443,8 +480,21 @@
 }
 
 bool KeyPermissions::IsCorporateKey(
-    const std::string& public_key_spki_der_b64) const {
-  return IsCorporateKeyForProfile(public_key_spki_der_b64, profile_prefs_);
+    const std::string& public_key_spki_der_b64,
+    const std::vector<KeyPermissions::KeyLocation>& key_locations) const {
+  for (const KeyLocation key_location : key_locations) {
+    switch (key_location) {
+      case KeyLocation::kUserSlot:
+        if (IsCorporateKeyForProfile(public_key_spki_der_b64, profile_prefs_))
+          return true;
+        break;
+      case KeyLocation::kSystemSlot:
+        return true;
+      default:
+        NOTREACHED();
+    }
+  }
+  return false;
 }
 
 void KeyPermissions::RegisterProfilePrefs(
diff --git a/chrome/browser/chromeos/platform_keys/key_permissions.h b/chrome/browser/chromeos/platform_keys/key_permissions.h
index 587707d5..4530782 100644
--- a/chrome/browser/chromeos/platform_keys/key_permissions.h
+++ b/chrome/browser/chromeos/platform_keys/key_permissions.h
@@ -72,6 +72,21 @@
 // permitted by the administrator.
 class KeyPermissions {
  public:
+  // Specifies where a private key is stored.
+  enum class KeyLocation {
+    // The key resides on the user's private slot. This is user-specific
+    // hardware-backed storage. Therefore the key is only available while the
+    // corresponding user is signed in.
+    kUserSlot,
+
+    // The key resides on the system slot. This is system-wide hardware-backed
+    // storage. The key is potentially accessible throughout all types of
+    // sessions, however, additional constraints may be imposed by the API logic
+    // - for instance, depending on the session type (e.g. affiliated user
+    // session or unaffiliated user session).
+    kSystemSlot
+  };
+
   // Allows querying and modifying permissions and registering keys for a
   // specific extension.
   class PermissionsForExtension {
@@ -90,27 +105,35 @@
 
     // Returns true if the private key matching |public_key_spki_der| can be
     // used for signing by the extension with id |extension_id_|.
-    // |public_key_spki_der| must be the DER of a Subject Public Key Info.
-    bool CanUseKeyForSigning(const std::string& public_key_spki_der);
+    // |key_locations| must describe locations available to the user the private
+    // key is stored on.
+    bool CanUseKeyForSigning(const std::string& public_key_spki_der,
+                             const std::vector<KeyLocation>& key_locations);
 
-    // Registers the key |public_key_spki_der| as being generated by the
-    // extension with id |extension_id| and marks it for corporate usage.
-    // |public_key_spki_der| must be the DER of a Subject Public Key Info.
-    void RegisterKeyForCorporateUsage(const std::string& public_key_spki_der);
+    // Registers the private key matching |public_key_spki_der| as being
+    // generated by the extension with id |extension_id| and marks it for
+    // corporate usage. |key_locations| must describe locations available to the
+    // user the private key is stored on.
+    void RegisterKeyForCorporateUsage(
+        const std::string& public_key_spki_der,
+        const std::vector<KeyLocation>& key_locations);
 
     // Sets the user granted permission that the extension with id
     // |extension_id| can use the private key matching |public_key_spki_der| for
-    // signing.
-    // |public_key_spki_der| must be the DER of a Subject Public Key Info.
-    void SetUserGrantedPermission(const std::string& public_key_spki_der);
+    // signing. |key_locations| must describe locations available to the user
+    // the private key is stored on.
+    void SetUserGrantedPermission(
+        const std::string& public_key_spki_der,
+        const std::vector<KeyLocation>& key_locations);
 
     // Must be called when the extension with id |extension_id| used the private
-    // key matching |public_key_spki_der| for signing.
-    // Updates the permissions accordingly. E.g. if this extension generated the
-    // key and no other permission was granted then the permission to sign with
-    // this key is removed.
-    // |public_key_spki_der| must be the DER of a Subject Public Key Info.
-    void SetKeyUsedForSigning(const std::string& public_key_spki_der);
+    // key matching |public_key_spki_der| for signing. |key_locations| must
+    // describe locations available to the user the private key is stored on.
+    // Updates the permissions accordingly.  E.g. if this extension generated
+    // the key and no other permission was granted then the permission to sign
+    // with this key is removed.
+    void SetKeyUsedForSigning(const std::string& public_key_spki_der,
+                              const std::vector<KeyLocation>& key_locations);
 
    private:
     struct KeyEntry;
@@ -168,10 +191,12 @@
   void GetPermissionsForExtension(const std::string& extension_id,
                                   const PermissionsCallback& callback);
 
-  // Returns true if the user can grant any permission for |public_key_spki_der|
-  // to extensions. |public_key_spki_der| must be the DER of a Subject Public
-  // Key Info.
-  bool CanUserGrantPermissionFor(const std::string& public_key_spki_der) const;
+  // Returns true if the user can grant any permission for
+  // |public_key_spki_derey_id| to extensions. |key_locations| must describe
+  // locations available to the user the private key is stored on.
+  bool CanUserGrantPermissionFor(
+      const std::string& public_key_spki_der,
+      const std::vector<KeyLocation>& key_locations) const;
 
   static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry);
 
@@ -186,7 +211,8 @@
       policy::PolicyService* const profile_policies);
 
  private:
-  bool IsCorporateKey(const std::string& public_key_spki_der_b64) const;
+  bool IsCorporateKey(const std::string& public_key_spki_der_b64,
+                      const std::vector<KeyLocation>& key_locations) const;
 
   // Creates a PermissionsForExtension object from |extension_id| and |value|
   // and passes the object to |callback|.
diff --git a/chrome/browser/chromeos/platform_keys/platform_keys.h b/chrome/browser/chromeos/platform_keys/platform_keys.h
index 9bccd63..bcb8f64 100644
--- a/chrome/browser/chromeos/platform_keys/platform_keys.h
+++ b/chrome/browser/chromeos/platform_keys/platform_keys.h
@@ -65,9 +65,10 @@
                             const std::string& error_message)>
     GenerateKeyCallback;
 
-// Generates a RSA key pair with |modulus_length_bits|. |token_id| is currently
-// ignored, instead the user token associated with |browser_context| is always
-// used. |callback| will be invoked with the resulting public key or an error.
+// Generates a RSA key pair with |modulus_length_bits|. |token_id| specifies the
+// token to store the keypair on and can currently be |kTokenIdUser| or
+// |kTokenIdSystem|. |callback| will be invoked with the resulting public key or
+// an error.
 void GenerateRSAKey(const std::string& token_id,
                     unsigned int modulus_length_bits,
                     const GenerateKeyCallback& callback,
@@ -77,25 +78,25 @@
                             const std::string& error_message)> SignCallback;
 
 // Digests |data|, applies PKCS1 padding and afterwards signs the data with the
-// private key matching |params.public_key|. If a non empty token id is provided
-// and the key is not found in that token, the operation aborts. |callback| will
-// be invoked with the signature or an error message.
+// private key matching |public_key_spki_der|. If a non empty token id is
+// provided and the key is not found in that token, the operation aborts.
+// |callback| will be invoked with the signature or an error message.
 void SignRSAPKCS1Digest(const std::string& token_id,
                         const std::string& data,
-                        const std::string& public_key,
+                        const std::string& public_key_spki_der,
                         HashAlgorithm hash_algorithm,
                         const SignCallback& callback,
                         content::BrowserContext* browser_context);
 
 // Applies PKCS1 padding and afterwards signs the data with the private key
-// matching |params.public_key|. |data| is not digested. If a non empty token id
-// is provided and the key is not found in that token, the operation aborts.
-// The size of |data| (number of octets) must be smaller than k - 11, where k
-// is the key size in octets.
-// |callback| will be invoked with the signature or an error message.
+// matching |public_key_spki_der|. |data| is not digested. If a non empty token
+// id is provided and the key is not found in that token, the operation aborts.
+// The size of |data| (number of octets) must be smaller than k - 11, where k is
+// the key size in octets. |callback| will be invoked with the signature or an
+// error message.
 void SignRSAPKCS1Raw(const std::string& token_id,
                      const std::string& data,
-                     const std::string& public_key,
+                     const std::string& public_key_spki_der,
                      const SignCallback& callback,
                      content::BrowserContext* browser_context);
 
@@ -151,9 +152,10 @@
     GetCertificatesCallback;
 
 // Returns the list of all certificates with stored private key available from
-// the given token. |token_id| is currently ignored, instead the user token
-// associated with |browser_context| is always used. |callback| will be invoked
-// with the list of available certificates or an error message.
+// the given token. If an empty |token_id| is provided, all certificates the
+// user associated with |browser_context| has access to are listed. Otherwise,
+// only certificates from the specified token are listed. |callback| will be
+// invoked with the list of available certificates or an error message.
 void GetCertificates(const std::string& token_id,
                      const GetCertificatesCallback& callback,
                      content::BrowserContext* browser_context);
@@ -165,9 +167,10 @@
 
 // Imports |certificate| to the given token if the certified key is already
 // stored in this token. Any intermediate of |certificate| will be ignored.
-// |token_id| is currently ignored, instead the user token associated with
-// |browser_context| is always used. |callback| will be invoked when the import
-// is finished, possibly with an error message.
+// |token_id| specifies the token to store the certificate on and can currently
+// be |kTokenIdUser| or |kTokenIdSystem|. The private key must be stored on the
+// same token. |callback| will be invoked when the import is finished, possibly
+// with an error message.
 void ImportCertificate(const std::string& token_id,
                        const scoped_refptr<net::X509Certificate>& certificate,
                        const ImportCertificateCallback& callback,
@@ -179,9 +182,10 @@
     RemoveCertificateCallback;
 
 // Removes |certificate| from the given token if present. Any intermediate of
-// |certificate| will be ignored. |token_id| is currently ignored, instead the
-// user token associated with |browser_context| is always used. |callback| will
-// be invoked when the removal is finished, possibly with an error message.
+// |certificate| will be ignored. |token_id| specifies the token to remove the
+// certificate from and can currently be empty (any token), |kTokenIdUser| or
+// |kTokenIdSystem|. |callback| will be invoked when the removal is finished,
+// possibly with an error message.
 void RemoveCertificate(const std::string& token_id,
                        const scoped_refptr<net::X509Certificate>& certificate,
                        const RemoveCertificateCallback& callback,
@@ -200,6 +204,30 @@
 void GetTokens(const GetTokensCallback& callback,
                content::BrowserContext* browser_context);
 
+// If token ids have been successfully retrieved, |error_message| will be empty.
+// Two cases are possible then:
+// If |token_ids| is not empty, |token_ids| has been filled with the identifiers
+// of the tokens the private key was found on and the user has access to.
+// Currently, valid token identifiers are |kTokenIdUser| and |kTokenIdSystem|.
+// If |token_ids| is empty, the private key has not been found on any token the
+// user has access to. Note that this is also the case if the key exists on the
+// system token, but the current user does not have access to the system token.
+// If an error occurred during processing, |token_ids| will be empty and
+// |error_message| will be set to an error message.
+// TODO(pmarko): This is currently a RepeatingCallback because of
+// GetNSSCertDatabaseForResourceContext semantics.
+typedef base::RepeatingCallback<void(const std::vector<std::string>& token_ids,
+                                     const std::string& error_message)>
+    GetKeyLocationsCallback;
+
+// Determines the token(s) on which the private key corresponding to
+// |public_key_spki_der| is stored. |callback| will be invoked when the token
+// ids are determined, possibly with an error message. Must be called and calls
+// |callback| on the UI thread.
+void GetKeyLocations(const std::string& public_key_spki_der,
+                     const GetKeyLocationsCallback& callback,
+                     content::BrowserContext* browser_context);
+
 }  // namespace platform_keys
 
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/platform_keys/platform_keys_nss.cc b/chrome/browser/chromeos/platform_keys/platform_keys_nss.cc
index e2f3e84ee..cbbb8e9 100644
--- a/chrome/browser/chromeos/platform_keys/platform_keys_nss.cc
+++ b/chrome/browser/chromeos/platform_keys/platform_keys_nss.cc
@@ -185,7 +185,7 @@
 class SignRSAState : public NSSOperationState {
  public:
   SignRSAState(const std::string& data,
-               const std::string& public_key,
+               const std::string& public_key_spki_der,
                bool sign_direct_pkcs_padded,
                HashAlgorithm hash_algorithm,
                const subtle::SignCallback& callback);
@@ -207,7 +207,7 @@
   const std::string data_;
 
   // Must be the DER encoding of a SubjectPublicKeyInfo.
-  const std::string public_key_;
+  const std::string public_key_spki_der_;
 
   // If true, |data_| will not be hashed before signing. Only PKCS#1 v1.5
   // padding will be applied before signing.
@@ -349,6 +349,32 @@
   GetTokensCallback callback_;
 };
 
+class GetKeyLocationsState : public NSSOperationState {
+ public:
+  GetKeyLocationsState(const std::string& public_key_spki_der,
+                       const GetKeyLocationsCallback& callback);
+  ~GetKeyLocationsState() override {}
+
+  void OnError(const base::Location& from,
+               const std::string& error_message) override {
+    CallBack(from, std::vector<std::string>(), error_message);
+  }
+
+  void CallBack(const base::Location& from,
+                const std::vector<std::string>& token_ids,
+                const std::string& error_message) {
+    origin_task_runner_->PostTask(
+        from, base::BindOnce(callback_, token_ids, error_message));
+  }
+
+  // Must be a DER encoding of a SubjectPublicKeyInfo.
+  const std::string public_key_spki_der_;
+
+ private:
+  // Must be called on origin thread, therefore use CallBack().
+  GetKeyLocationsCallback callback_;
+};
+
 NSSOperationState::NSSOperationState()
     : origin_task_runner_(base::ThreadTaskRunnerHandle::Get()) {
 }
@@ -360,16 +386,15 @@
 }
 
 SignRSAState::SignRSAState(const std::string& data,
-                           const std::string& public_key,
+                           const std::string& public_key_spki_der,
                            bool sign_direct_pkcs_padded,
                            HashAlgorithm hash_algorithm,
                            const subtle::SignCallback& callback)
     : data_(data),
-      public_key_(public_key),
+      public_key_spki_der_(public_key_spki_der),
       sign_direct_pkcs_padded_(sign_direct_pkcs_padded),
       hash_algorithm_(hash_algorithm),
-      callback_(callback) {
-}
+      callback_(callback) {}
 
 SelectCertificatesState::SelectCertificatesState(
     const std::string& username_hash,
@@ -403,6 +428,11 @@
     : callback_(callback) {
 }
 
+GetKeyLocationsState::GetKeyLocationsState(
+    const std::string& public_key_spki_der,
+    const GetKeyLocationsCallback& callback)
+    : public_key_spki_der_(public_key_spki_der), callback_(callback) {}
+
 // Does the actual key generation on a worker thread. Used by
 // GenerateRSAKeyWithDB().
 void GenerateRSAKeyOnWorkerThread(std::unique_ptr<GenerateRSAKeyState> state) {
@@ -454,9 +484,9 @@
 // Does the actual signing on a worker thread. Used by SignRSAWithDB().
 void SignRSAOnWorkerThread(std::unique_ptr<SignRSAState> state) {
   const uint8_t* public_key_uint8 =
-      reinterpret_cast<const uint8_t*>(state->public_key_.data());
+      reinterpret_cast<const uint8_t*>(state->public_key_spki_der_.data());
   std::vector<uint8_t> public_key_vector(
-      public_key_uint8, public_key_uint8 + state->public_key_.size());
+      public_key_uint8, public_key_uint8 + state->public_key_spki_der_.size());
 
   crypto::ScopedSECKEYPrivateKey rsa_key;
   if (state->slot_) {
@@ -736,6 +766,37 @@
                   std::string() /* no error */);
 }
 
+// Does the actual work to determine which key is on which token.
+void GetKeyLocationsWithDB(std::unique_ptr<GetKeyLocationsState> state,
+                           net::NSSCertDatabase* cert_db) {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+  std::vector<std::string> token_ids;
+
+  const uint8_t* public_key_uint8 =
+      reinterpret_cast<const uint8_t*>(state->public_key_spki_der_.data());
+  std::vector<uint8_t> public_key_vector(
+      public_key_uint8, public_key_uint8 + state->public_key_spki_der_.size());
+
+  if (cert_db->GetPrivateSlot().get()) {
+    crypto::ScopedSECKEYPrivateKey rsa_key =
+        crypto::FindNSSKeyFromPublicKeyInfoInSlot(
+            public_key_vector, cert_db->GetPrivateSlot().get());
+    if (rsa_key)
+      token_ids.push_back(kTokenIdUser);
+  }
+  if (cert_db->GetSystemSlot().get()) {
+    crypto::ScopedSECKEYPrivateKey rsa_key =
+        crypto::FindNSSKeyFromPublicKeyInfoInSlot(
+            public_key_vector, cert_db->GetSystemSlot().get());
+    if (rsa_key)
+      token_ids.push_back(kTokenIdSystem);
+  }
+
+  state->CallBack(FROM_HERE, std::move(token_ids),
+                  std::string() /* no error */);
+}
+
 }  // namespace
 
 namespace subtle {
@@ -763,14 +824,14 @@
 
 void SignRSAPKCS1Digest(const std::string& token_id,
                         const std::string& data,
-                        const std::string& public_key,
+                        const std::string& public_key_spki_der,
                         HashAlgorithm hash_algorithm,
                         const SignCallback& callback,
                         content::BrowserContext* browser_context) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  std::unique_ptr<SignRSAState> state(
-      new SignRSAState(data, public_key, false /* digest before signing */,
-                       hash_algorithm, callback));
+  std::unique_ptr<SignRSAState> state(new SignRSAState(
+      data, public_key_spki_der, false /* digest before signing */,
+      hash_algorithm, callback));
   // Get the pointer to |state| before base::Passed releases |state|.
   NSSOperationState* state_ptr = state.get();
 
@@ -783,12 +844,12 @@
 
 void SignRSAPKCS1Raw(const std::string& token_id,
                      const std::string& data,
-                     const std::string& public_key,
+                     const std::string& public_key_spki_der,
                      const SignCallback& callback,
                      content::BrowserContext* browser_context) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   std::unique_ptr<SignRSAState> state(new SignRSAState(
-      data, public_key, true /* sign directly without hashing */,
+      data, public_key_spki_der, true /* sign directly without hashing */,
       HASH_ALGORITHM_NONE, callback));
   // Get the pointer to |state| before base::Passed releases |state|.
   NSSOperationState* state_ptr = state.get();
@@ -951,6 +1012,20 @@
                   state_ptr);
 }
 
+void GetKeyLocations(const std::string& public_key_spki_der,
+                     const GetKeyLocationsCallback& callback,
+                     content::BrowserContext* browser_context) {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  auto state =
+      std::make_unique<GetKeyLocationsState>(public_key_spki_der, callback);
+  NSSOperationState* state_ptr = state.get();
+
+  GetCertDatabase(
+      std::string() /* don't get any specific slot - we need all slots */,
+      base::BindRepeating(&GetKeyLocationsWithDB, base::Passed(&state)),
+      browser_context, state_ptr);
+}
+
 }  // namespace platform_keys
 
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/platform_keys/platform_keys_service.cc b/chrome/browser/chromeos/platform_keys/platform_keys_service.cc
index 780eaf5..e7e57b2 100644
--- a/chrome/browser/chromeos/platform_keys/platform_keys_service.cc
+++ b/chrome/browser/chromeos/platform_keys/platform_keys_service.cc
@@ -13,6 +13,7 @@
 #include "base/callback.h"
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
+#include "base/optional.h"
 #include "base/stl_util.h"
 #include "base/values.h"
 #include "chrome/browser/chromeos/platform_keys/platform_keys.h"
@@ -30,6 +31,23 @@
     "This key is not allowed for signing. Either it was used for signing "
     "before or it was not correctly generated.";
 
+// Converts |token_ids| (string-based token identifiers used in the
+// platformKeys API) to a vector of KeyPermissions::KeyLocation. Currently only
+// accepts |kTokenIdUser| and |kTokenIdSystem| as |token_ids| elements.
+std::vector<KeyPermissions::KeyLocation> TokenIdsToKeyLocations(
+    const std::vector<std::string>& token_ids) {
+  std::vector<KeyPermissions::KeyLocation> key_locations;
+  for (const auto& token_id : token_ids) {
+    if (token_id == platform_keys::kTokenIdUser)
+      key_locations.push_back(KeyPermissions::KeyLocation::kUserSlot);
+    else if (token_id == platform_keys::kTokenIdSystem)
+      key_locations.push_back(KeyPermissions::KeyLocation::kSystemSlot);
+    else
+      NOTREACHED() << "Unknown platformKeys API token id " << token_id;
+  }
+  return key_locations;
+}
+
 }  // namespace
 
 class PlatformKeysService::Task {
@@ -93,10 +111,7 @@
         return;
       case Step::UPDATE_PERMISSIONS_AND_CALLBACK:
         next_step_ = Step::DONE;
-        extension_permissions_->RegisterKeyForCorporateUsage(
-            public_key_spki_der_);
-        callback_.Run(public_key_spki_der_, std::string() /* no error */);
-        DoStep();
+        UpdatePermissionsAndCallBack();
         return;
       case Step::DONE:
         service_->TaskFinished(this);
@@ -135,6 +150,16 @@
                                   base::Unretained(this)));
   }
 
+  void UpdatePermissionsAndCallBack() {
+    std::vector<KeyPermissions::KeyLocation> key_locations =
+        TokenIdsToKeyLocations({token_id_});
+    extension_permissions_->RegisterKeyForCorporateUsage(public_key_spki_der_,
+                                                         key_locations);
+    callback_.Run(public_key_spki_der_, std::string() /* no error */);
+    DoStep();
+    return;
+  }
+
   void GotPermissions(std::unique_ptr<KeyPermissions::PermissionsForExtension>
                           extension_permissions) {
     extension_permissions_ = std::move(extension_permissions);
@@ -162,6 +187,7 @@
  public:
   enum class Step {
     GET_EXTENSION_PERMISSIONS,
+    GET_KEY_LOCATIONS,
     SIGN_OR_ABORT,
     DONE,
   };
@@ -175,7 +201,7 @@
   // If an error occurs, an error message is passed to |callback| instead.
   SignTask(const std::string& token_id,
            const std::string& data,
-           const std::string& public_key,
+           const std::string& public_key_spki_der,
            bool sign_direct_pkcs_padded,
            platform_keys::HashAlgorithm hash_algorithm,
            const std::string& extension_id,
@@ -184,7 +210,7 @@
            PlatformKeysService* service)
       : token_id_(token_id),
         data_(data),
-        public_key_(public_key),
+        public_key_spki_der_(public_key_spki_der),
         sign_direct_pkcs_padded_(sign_direct_pkcs_padded),
         hash_algorithm_(hash_algorithm),
         extension_id_(extension_id),
@@ -206,13 +232,17 @@
   void DoStep() {
     switch (next_step_) {
       case Step::GET_EXTENSION_PERMISSIONS:
-        next_step_ = Step::SIGN_OR_ABORT;
+        next_step_ = Step::GET_KEY_LOCATIONS;
         GetExtensionPermissions();
         return;
+      case Step::GET_KEY_LOCATIONS:
+        next_step_ = Step::SIGN_OR_ABORT;
+        GetKeyLocations();
+        return;
       case Step::SIGN_OR_ABORT: {
         next_step_ = Step::DONE;
-        bool sign_granted =
-            extension_permissions_->CanUseKeyForSigning(public_key_);
+        bool sign_granted = extension_permissions_->CanUseKeyForSigning(
+            public_key_spki_der_, key_locations_);
         if (sign_granted) {
           Sign();
         } else {
@@ -241,19 +271,41 @@
     DoStep();
   }
 
-  // Updates the permissions for |public_key_|, starts the actual signing
-  // operation and afterwards passes the signature (or error) to |callback_|.
+  void GetKeyLocations() {
+    platform_keys::GetKeyLocations(
+        public_key_spki_der_,
+        base::BindRepeating(&SignTask::GotKeyLocation, base::Unretained(this)),
+        service_->browser_context_);
+  }
+
+  void GotKeyLocation(const std::vector<std::string>& token_ids,
+                      const std::string& error_message) {
+    if (!error_message.empty()) {
+      next_step_ = Step::DONE;
+      callback_.Run(std::string() /* no signature */, error_message);
+      DoStep();
+      return;
+    }
+
+    key_locations_ = TokenIdsToKeyLocations(token_ids);
+    DoStep();
+  }
+
+  // Updates the permissions for |public_key_spki_der_|, starts the actual
+  // signing operation and afterwards passes the signature (or error) to
+  // |callback_|.
   void Sign() {
-    extension_permissions_->SetKeyUsedForSigning(public_key_);
+    extension_permissions_->SetKeyUsedForSigning(public_key_spki_der_,
+                                                 key_locations_);
 
     if (sign_direct_pkcs_padded_) {
       platform_keys::subtle::SignRSAPKCS1Raw(
-          token_id_, data_, public_key_,
+          token_id_, data_, public_key_spki_der_,
           base::Bind(&SignTask::DidSign, weak_factory_.GetWeakPtr()),
           service_->browser_context_);
     } else {
       platform_keys::subtle::SignRSAPKCS1Digest(
-          token_id_, data_, public_key_, hash_algorithm_,
+          token_id_, data_, public_key_spki_der_, hash_algorithm_,
           base::Bind(&SignTask::DidSign, weak_factory_.GetWeakPtr()),
           service_->browser_context_);
     }
@@ -268,7 +320,7 @@
 
   const std::string token_id_;
   const std::string data_;
-  const std::string public_key_;
+  const std::string public_key_spki_der_;
 
   // If true, |data_| will not be hashed before signing. Only PKCS#1 v1.5
   // padding will be applied before signing.
@@ -280,6 +332,7 @@
   std::unique_ptr<KeyPermissions::PermissionsForExtension>
       extension_permissions_;
   KeyPermissions* const key_permissions_;
+  std::vector<KeyPermissions::KeyLocation> key_locations_;
   PlatformKeysService* const service_;
   base::WeakPtrFactory<SignTask> weak_factory_;
 
@@ -291,6 +344,7 @@
   enum class Step {
     GET_EXTENSION_PERMISSIONS,
     GET_MATCHING_CERTS,
+    GET_KEY_LOCATIONS,
     INTERSECT_WITH_INPUT_CERTS,
     SELECT_CERTS,
     UPDATE_PERMISSION,
@@ -339,9 +393,15 @@
         GetExtensionPermissions();
         return;
       case Step::GET_MATCHING_CERTS:
-        next_step_ = Step::INTERSECT_WITH_INPUT_CERTS;
+        next_step_ = Step::GET_KEY_LOCATIONS;
         GetMatchingCerts();
         return;
+      case Step::GET_KEY_LOCATIONS:
+        // Don't advance to the next step yet - GetKeyLocations is repeated for
+        // all matching certs. The next step will be selected in
+        // GetKeyLocations.
+        GetKeyLocations(Step::INTERSECT_WITH_INPUT_CERTS /* next_step */);
+        return;
       case Step::INTERSECT_WITH_INPUT_CERTS:
         if (interactive_)
           next_step_ = Step::SELECT_CERTS;
@@ -405,15 +465,6 @@
     }
 
     for (scoped_refptr<net::X509Certificate>& certificate : *matches) {
-      const std::string public_key_spki_der(
-          platform_keys::GetSubjectPublicKeyInfo(certificate));
-      // Skip this key if the user cannot grant any permission for it, except if
-      // this extension can already use it for signing.
-      if (!key_permissions_->CanUserGrantPermissionFor(public_key_spki_der) &&
-          !extension_permissions_->CanUseKeyForSigning(public_key_spki_der)) {
-        continue;
-      }
-
       // Filter the retrieved certificates returning only those whose type is
       // equal to one of the entries in the type field of the certificate
       // request.
@@ -431,7 +482,61 @@
           continue;
       }
 
-      matches_.push_back(std::move(certificate));
+      matches_pending_key_locations_.push_back(std::move(certificate));
+    }
+    DoStep();
+  }
+
+  // This is called once for each certificate in
+  // |matches_pending_key_locations_|.  Each invocation processes the first
+  // element and removes it from the deque. Each processed certificate is added
+  // to |matches_| and |key_locations_for_matches_| if it is selectable
+  // according to KeyPermissions. When all certificates have been processed,
+  // advances the SignTask state machine to |next_step|.
+  void GetKeyLocations(Step next_step) {
+    if (matches_pending_key_locations_.empty()) {
+      next_step_ = next_step;
+      DoStep();
+      return;
+    }
+
+    scoped_refptr<net::X509Certificate> certificate =
+        std::move(matches_pending_key_locations_.front());
+    matches_pending_key_locations_.pop_front();
+    const std::string public_key_spki_der(
+        platform_keys::GetSubjectPublicKeyInfo(certificate));
+
+    platform_keys::GetKeyLocations(
+        public_key_spki_der,
+        base::BindRepeating(&SelectTask::GotKeyLocations,
+                            base::Unretained(this), certificate),
+        service_->browser_context_);
+  }
+
+  void GotKeyLocations(const scoped_refptr<net::X509Certificate>& certificate,
+                       const std::vector<std::string>& token_ids,
+                       const std::string& error_message) {
+    if (!error_message.empty()) {
+      next_step_ = Step::DONE;
+      callback_.Run(nullptr /* no certificates */, error_message);
+      DoStep();
+      return;
+    }
+
+    const std::string public_key_spki_der(
+        platform_keys::GetSubjectPublicKeyInfo(certificate));
+
+    std::vector<KeyPermissions::KeyLocation> key_locations =
+        TokenIdsToKeyLocations(token_ids);
+
+    // Use this key if the user can use it for signing or can grant permission
+    // for it.
+    if (key_permissions_->CanUserGrantPermissionFor(public_key_spki_der,
+                                                    key_locations) ||
+        extension_permissions_->CanUseKeyForSigning(public_key_spki_der,
+                                                    key_locations)) {
+      matches_.push_back(certificate);
+      key_locations_for_matches_[public_key_spki_der] = key_locations;
     }
     DoStep();
   }
@@ -486,7 +591,11 @@
     }
     const std::string public_key_spki_der(
         platform_keys::GetSubjectPublicKeyInfo(selected_cert_));
-    extension_permissions_->SetUserGrantedPermission(public_key_spki_der);
+    auto key_locations_iter =
+        key_locations_for_matches_.find(public_key_spki_der);
+    CHECK(key_locations_iter != key_locations_for_matches_.end());
+    extension_permissions_->SetUserGrantedPermission(
+        public_key_spki_der, key_locations_iter->second);
     DoStep();
   }
 
@@ -508,7 +617,11 @@
       const std::string public_key_spki_der(
           platform_keys::GetSubjectPublicKeyInfo(selected_cert));
 
-      if (!extension_permissions_->CanUseKeyForSigning(public_key_spki_der))
+      auto key_locations_iter =
+          key_locations_for_matches_.find(public_key_spki_der);
+      CHECK(key_locations_iter != key_locations_for_matches_.end());
+      if (!extension_permissions_->CanUseKeyForSigning(
+              public_key_spki_der, key_locations_iter->second))
         continue;
 
       filtered_certs->push_back(selected_cert);
@@ -524,7 +637,13 @@
 
   Step next_step_ = Step::GET_EXTENSION_PERMISSIONS;
 
+  std::deque<scoped_refptr<net::X509Certificate>>
+      matches_pending_key_locations_;
   net::CertificateList matches_;
+  // Mapping of DER-encoded Subject Public Key Info to the KeyLocations
+  // determined for the corresponding private key.
+  base::flat_map<std::string, std::vector<KeyPermissions::KeyLocation>>
+      key_locations_for_matches_;
   scoped_refptr<net::X509Certificate> selected_cert_;
   platform_keys::ClientCertificateRequest request_;
   std::unique_ptr<net::CertificateList> input_client_certificates_;
@@ -584,26 +703,28 @@
 void PlatformKeysService::SignRSAPKCS1Digest(
     const std::string& token_id,
     const std::string& data,
-    const std::string& public_key,
+    const std::string& public_key_spki_der,
     platform_keys::HashAlgorithm hash_algorithm,
     const std::string& extension_id,
     const SignCallback& callback) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   StartOrQueueTask(base::WrapUnique(new SignTask(
-      token_id, data, public_key, false /* digest before signing */,
+      token_id, data, public_key_spki_der, false /* digest before signing */,
       hash_algorithm, extension_id, callback, &key_permissions_, this)));
 }
 
-void PlatformKeysService::SignRSAPKCS1Raw(const std::string& token_id,
-                                          const std::string& data,
-                                          const std::string& public_key,
-                                          const std::string& extension_id,
-                                          const SignCallback& callback) {
+void PlatformKeysService::SignRSAPKCS1Raw(
+    const std::string& token_id,
+    const std::string& data,
+    const std::string& public_key_spki_der,
+    const std::string& extension_id,
+    const SignCallback& callback) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  StartOrQueueTask(base::WrapUnique(new SignTask(
-      token_id, data, public_key, true /* sign directly without hashing */,
-      platform_keys::HASH_ALGORITHM_NONE, extension_id, callback,
-      &key_permissions_, this)));
+  StartOrQueueTask(base::WrapUnique(
+      new SignTask(token_id, data, public_key_spki_der,
+                   true /* sign directly without hashing */,
+                   platform_keys::HASH_ALGORITHM_NONE, extension_id, callback,
+                   &key_permissions_, this)));
 }
 
 void PlatformKeysService::SelectClientCertificates(
diff --git a/chrome/browser/chromeos/platform_keys/platform_keys_service.h b/chrome/browser/chromeos/platform_keys/platform_keys_service.h
index d2af3ff..b77be3d 100644
--- a/chrome/browser/chromeos/platform_keys/platform_keys_service.h
+++ b/chrome/browser/chromeos/platform_keys/platform_keys_service.h
@@ -98,11 +98,10 @@
                           const std::string& error_message)>;
 
   // Generates an RSA key pair with |modulus_length_bits| and registers the key
-  // to allow a single sign operation by the given extension. |token_id| is
-  // currently ignored, instead the user token associated with |browser_context|
-  // is always used. |callback| will be invoked with the resulting public key or
-  // an error.
-  // Will only call back during the lifetime of this object.
+  // to allow a single sign operation by the given extension. |token_id|
+  // specifies the token to store the keypair on. |callback| will be invoked
+  // with the resulting public key or an error. Will only call back during the
+  // lifetime of this object.
   void GenerateRSAKey(const std::string& token_id,
                       unsigned int modulus_length_bits,
                       const std::string& extension_id,
@@ -115,9 +114,9 @@
                                            const std::string& error_message)>;
 
   // Digests |data|, applies PKCS1 padding and afterwards signs the data with
-  // the private key matching |params.public_key|. If a non empty token id is
-  // provided and the key is not found in that token, the operation aborts.
-  // If the extension does not have permissions for signing with this key, the
+  // the private key matching |public_key_spki_der|. If a non empty token id is
+  // provided and the key is not found in that token, the operation aborts. If
+  // the extension does not have permissions for signing with this key, the
   // operation aborts. In case of a one time permission (granted after
   // generating the key), this function also removes the permission to prevent
   // future signing attempts.
@@ -125,14 +124,14 @@
   // Will only call back during the lifetime of this object.
   void SignRSAPKCS1Digest(const std::string& token_id,
                           const std::string& data,
-                          const std::string& public_key,
+                          const std::string& public_key_spki_der,
                           platform_keys::HashAlgorithm hash_algorithm,
                           const std::string& extension_id,
                           const SignCallback& callback);
 
   // Applies PKCS1 padding and afterwards signs the data with the private key
-  // matching |params.public_key|. |data| is not digested. If a non empty token
-  // id is provided and the key is not found in that token, the operation
+  // matching |public_key_spki_der|. |data| is not digested. If a non empty
+  // token id is provided and the key is not found in that token, the operation
   // aborts.
   // The size of |data| (number of octets) must be smaller than k - 11, where k
   // is the key size in octets.
@@ -144,7 +143,7 @@
   // Will only call back during the lifetime of this object.
   void SignRSAPKCS1Raw(const std::string& token_id,
                        const std::string& data,
-                       const std::string& public_key,
+                       const std::string& public_key_spki_der,
                        const std::string& extension_id,
                        const SignCallback& callback);
 
diff --git a/chrome/browser/chromeos/policy/pre_signin_policy_fetcher.cc b/chrome/browser/chromeos/policy/pre_signin_policy_fetcher.cc
index 556ef61..45654391 100644
--- a/chrome/browser/chromeos/policy/pre_signin_policy_fetcher.cc
+++ b/chrome/browser/chromeos/policy/pre_signin_policy_fetcher.cc
@@ -90,7 +90,7 @@
 
 void PreSigninPolicyFetcher::OnMountTemporaryUserHome(
     base::Optional<cryptohome::BaseReply> reply) {
-  if (BaseReplyToMountError(reply) != cryptohome::MOUNT_ERROR_NONE) {
+  if (MountExReplyToMountError(reply) != cryptohome::MOUNT_ERROR_NONE) {
     LOG(ERROR) << "Temporary user home mount failed.";
     NotifyCallback(PolicyFetchResult::ERROR, nullptr);
     return;
diff --git a/chrome/browser/chromeos/printing/printer_configurer.cc b/chrome/browser/chromeos/printing/printer_configurer.cc
index 04f6065..85f7169 100644
--- a/chrome/browser/chromeos/printing/printer_configurer.cc
+++ b/chrome/browser/chromeos/printing/printer_configurer.cc
@@ -46,15 +46,6 @@
 
 namespace {
 
-// Get the URI that we want for talking to cups.
-std::string URIForCups(const Printer& printer) {
-  if (!printer.effective_uri().empty()) {
-    return printer.effective_uri();
-  } else {
-    return printer.uri();
-  }
-}
-
 // Configures printers by downloading PPDs then adding them to CUPS through
 // debugd.  This class must be used on the UI thread.
 class PrinterConfigurerImpl : public PrinterConfigurer {
@@ -104,7 +95,7 @@
 
     auto* client = DBusThreadManager::Get()->GetDebugDaemonClient();
     client->CupsAddAutoConfiguredPrinter(
-        printer.id(), URIForCups(printer),
+        printer.id(), printer.UriForCups(),
         base::BindOnce(&PrinterConfigurerImpl::OnAddedPrinter,
                        weak_factory_.GetWeakPtr(), printer,
                        std::move(callback)));
@@ -176,7 +167,7 @@
     auto* client = DBusThreadManager::Get()->GetDebugDaemonClient();
 
     client->CupsAddManuallyConfiguredPrinter(
-        printer.id(), URIForCups(printer), ppd_contents,
+        printer.id(), printer.UriForCups(), ppd_contents,
         base::BindOnce(&PrinterConfigurerImpl::OnAddedPrinter,
                        weak_factory_.GetWeakPtr(), printer, std::move(cb)));
   }
@@ -267,7 +258,7 @@
   base::MD5Context ctx;
   base::MD5Init(&ctx);
   base::MD5Update(&ctx, printer.id());
-  base::MD5Update(&ctx, URIForCups(printer));
+  base::MD5Update(&ctx, printer.UriForCups());
   base::MD5Update(&ctx, printer.ppd_reference().user_supplied_ppd_url);
   base::MD5Update(&ctx, printer.ppd_reference().effective_make_and_model);
   char autoconf = printer.ppd_reference().autoconf ? 1 : 0;
diff --git a/chrome/browser/chromeos/printing/synced_printers_manager_unittest.cc b/chrome/browser/chromeos/printing/synced_printers_manager_unittest.cc
index d51a0e82..8d339d5 100644
--- a/chrome/browser/chromeos/printing/synced_printers_manager_unittest.cc
+++ b/chrome/browser/chromeos/printing/synced_printers_manager_unittest.cc
@@ -29,11 +29,11 @@
 
 namespace {
 
-const char kTestPrinterId[] = "UUID-UUID-UUID-PRINTER";
-const char kTestPrinterId2[] = "UUID-UUID-UUID-PRINTR2";
-const char kTestUri[] = "ipps://printer.chromium.org/ipp/print";
+constexpr char kTestPrinterId[] = "UUID-UUID-UUID-PRINTER";
+constexpr char kTestPrinterId2[] = "UUID-UUID-UUID-PRINTR2";
+constexpr char kTestUri[] = "ipps://printer.chromium.org/ipp/print";
 
-const char kLexJson[] = R"({
+constexpr char kLexJson[] = R"({
         "display_name": "LexaPrint",
         "description": "Laser on the test shelf",
         "manufacturer": "LexaPrint, Inc.",
@@ -45,7 +45,7 @@
         },
       } )";
 
-const char kColorLaserJson[] = R"json({
+constexpr char kColorLaserJson[] = R"json({
       "display_name": "Color Laser",
       "description": "The printer next to the water cooler.",
       "manufacturer": "Printer Manufacturer",
diff --git a/chrome/browser/chromeos/smb_client/smb_file_system.cc b/chrome/browser/chromeos/smb_client/smb_file_system.cc
index 6cf884d..94b86d3e 100644
--- a/chrome/browser/chromeos/smb_client/smb_file_system.cc
+++ b/chrome/browser/chromeos/smb_client/smb_file_system.cc
@@ -5,10 +5,12 @@
 #include "chrome/browser/chromeos/smb_client/smb_file_system.h"
 
 #include "base/memory/ptr_util.h"
+#include "base/posix/eintr_wrapper.h"
 #include "base/strings/string_number_conversions.h"
 #include "chrome/browser/chromeos/file_system_provider/service.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/smb_provider_client.h"
+#include "net/base/io_buffer.h"
 
 namespace chromeos {
 
@@ -249,7 +251,11 @@
     int64_t offset,
     int length,
     const ReadChunkReceivedCallback& callback) {
-  NOTIMPLEMENTED();
+  GetSmbProviderClient()->ReadFile(
+      GetMountId(), file_handle, offset, length,
+      base::BindOnce(&SmbFileSystem::HandleRequestReadFileCallback,
+                     weak_ptr_factory_.GetWeakPtr(), length,
+                     scoped_refptr<net::IOBuffer>(buffer), callback));
   return CreateAbortCallback();
 }
 
@@ -437,6 +443,38 @@
   return error;
 }
 
+void SmbFileSystem::HandleRequestReadFileCallback(
+    int32_t length,
+    scoped_refptr<net::IOBuffer> buffer,
+    const ReadChunkReceivedCallback& callback,
+    smbprovider::ErrorType error,
+    const base::ScopedFD& fd) const {
+  if (error != smbprovider::ERROR_OK) {
+    callback.Run(0 /* chunk_length */, false /* has_more */,
+                 TranslateError(error));
+    return;
+  }
+
+  int32_t total_read = 0;
+  while (total_read < length) {
+    // read() may return less than the requested amount of bytes. If this
+    // happens, try to read the remaining bytes.
+    const int32_t bytes_read = HANDLE_EINTR(
+        read(fd.get(), buffer->data() + total_read, length - total_read));
+    if (bytes_read < 0) {
+      // This is an error case, return an error immediately.
+      callback.Run(0 /* chunk_length */, false /* has_more */,
+                   base::File::FILE_ERROR_IO);
+      return;
+    }
+    if (bytes_read == 0) {
+      break;
+    }
+    total_read += bytes_read;
+  }
+  callback.Run(total_read, false /* has_more */, base::File::FILE_OK);
+}
+
 base::WeakPtr<file_system_provider::ProvidedFileSystemInterface>
 SmbFileSystem::GetWeakPtr() {
   return weak_ptr_factory_.GetWeakPtr();
diff --git a/chrome/browser/chromeos/smb_client/smb_file_system.h b/chrome/browser/chromeos/smb_client/smb_file_system.h
index e607508..78c20e1 100644
--- a/chrome/browser/chromeos/smb_client/smb_file_system.h
+++ b/chrome/browser/chromeos/smb_client/smb_file_system.h
@@ -206,6 +206,12 @@
       const std::string& file_system_id,
       file_system_provider::Service::UnmountReason reason);
 
+  void HandleRequestReadFileCallback(int32_t length,
+                                     scoped_refptr<net::IOBuffer> buffer,
+                                     const ReadChunkReceivedCallback& callback,
+                                     smbprovider::ErrorType error,
+                                     const base::ScopedFD& fd) const;
+
   int32_t GetMountId() const;
 
   SmbProviderClient* GetSmbProviderClient() const;
diff --git a/chrome/browser/data_use_measurement/chrome_data_use_ascriber.cc b/chrome/browser/data_use_measurement/chrome_data_use_ascriber.cc
index 4415005..3e796d2 100644
--- a/chrome/browser/data_use_measurement/chrome_data_use_ascriber.cc
+++ b/chrome/browser/data_use_measurement/chrome_data_use_ascriber.cc
@@ -28,6 +28,9 @@
 
 namespace data_use_measurement {
 
+const base::Feature kDisableAscriberIfDataSaverDisabled{
+    "DisableAscriberIfDataSaverDisabled", base::FEATURE_DISABLED_BY_DEFAULT};
+
 // static
 const void* const ChromeDataUseAscriber::DataUseRecorderEntryAsUserData::
     kDataUseAscriberUserDataKey =
@@ -194,6 +197,9 @@
   DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
   DCHECK(request);
 
+  if (IsDisabled())
+    return;
+
   const DataUseRecorderEntry entry = GetDataUseRecorderEntry(request);
 
   if (entry == data_use_recorders_.end())
@@ -214,6 +220,11 @@
   DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
   DCHECK(request);
 
+  if (IsDisabled())
+    return;
+
+  DCHECK(request);
+
   const DataUseRecorderEntry entry = GetDataUseRecorderEntry(request);
 
   if (entry == data_use_recorders_.end())
@@ -275,6 +286,8 @@
                                                int main_render_process_id,
                                                int main_render_frame_id) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+  if (IsDisabled())
+    return;
 
   const auto render_frame =
       RenderFrameHostID(render_process_id, render_frame_id);
@@ -305,6 +318,9 @@
                                                int main_render_frame_id) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
 
+  if (IsDisabled())
+    return;
+
   RenderFrameHostID key(render_process_id, render_frame_id);
 
   if (main_render_process_id == -1 && main_render_frame_id == -1) {
@@ -327,6 +343,8 @@
     int render_process_id,
     int render_frame_id) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+  if (IsDisabled())
+    return;
 
   main_render_frame_entry_map_
       .find(RenderFrameHostID(render_process_id, render_frame_id))
@@ -341,6 +359,8 @@
     uint32_t page_transition,
     base::TimeTicks time) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+  if (IsDisabled())
+    return;
 
   RenderFrameHostID main_frame(render_process_id, render_frame_id);
 
@@ -528,6 +548,8 @@
                                              int main_render_frame_id,
                                              bool visible) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+  if (IsDisabled())
+    return;
 
   auto main_frame_it = main_render_frame_entry_map_.find(
       RenderFrameHostID(main_render_process_id, main_render_frame_id));
@@ -543,6 +565,8 @@
                                                    int new_render_process_id,
                                                    int new_render_frame_id) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+  if (IsDisabled())
+    return;
 
   auto old_frame_iter = main_render_frame_entry_map_.find(
       RenderFrameHostID(old_render_process_id, old_render_frame_id));
@@ -563,4 +587,18 @@
   }
 }
 
+bool ChromeDataUseAscriber::IsDisabled() const {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+
+  // TODO(rajendrant): https://crbug.com/753559. Fix platform specific race
+  // conditions and re-enable.
+  return base::FeatureList::IsEnabled(kDisableAscriberIfDataSaverDisabled) &&
+         disable_ascriber_;
+}
+
+void ChromeDataUseAscriber::DisableAscriber() {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+  disable_ascriber_ = true;
+}
+
 }  // namespace data_use_measurement
diff --git a/chrome/browser/data_use_measurement/chrome_data_use_ascriber.h b/chrome/browser/data_use_measurement/chrome_data_use_ascriber.h
index 371a08c..2263815 100644
--- a/chrome/browser/data_use_measurement/chrome_data_use_ascriber.h
+++ b/chrome/browser/data_use_measurement/chrome_data_use_ascriber.h
@@ -12,6 +12,7 @@
 #include <tuple>
 #include <utility>
 
+#include "base/feature_list.h"
 #include "base/hash.h"
 #include "base/macros.h"
 #include "base/supports_user_data.h"
@@ -27,6 +28,9 @@
 
 namespace data_use_measurement {
 
+// Disables data use ascriber if data saver is disabled.
+extern const base::Feature kDisableAscriberIfDataSaverDisabled;
+
 class URLRequestClassifier;
 
 // Browser implementation of DataUseAscriber. Maintains a list of
@@ -181,6 +185,11 @@
   void AscribeRecorderWithRequest(net::URLRequest* request,
                                   DataUseRecorderEntry entry);
 
+  void DisableAscriber() override;
+
+  // Returns true if data use ascriber is disabled.
+  bool IsDisabled() const;
+
   // Owner for all instances of DataUseRecorder. An instance is kept in this
   // list if any entity (render frame hosts, URLRequests, pending navigations)
   // that ascribe data use to the instance exists, and deleted when all
@@ -206,6 +215,10 @@
   // Detects heavy pages. Can be null when the feature is disabled.
   std::unique_ptr<DataUseAscriber::PageLoadObserver> page_capping_observer_;
 
+  // True if the dtaa use ascriber should be disabled. The ascriber is enabled
+  // by default.
+  bool disable_ascriber_ = false;
+
   DISALLOW_COPY_AND_ASSIGN(ChromeDataUseAscriber);
 };
 
diff --git a/chrome/browser/download/notification/download_notification_browsertest.cc b/chrome/browser/download/notification/download_notification_browsertest.cc
index 9bb2671..e7d7055e 100644
--- a/chrome/browser/download/notification/download_notification_browsertest.cc
+++ b/chrome/browser/download/notification/download_notification_browsertest.cc
@@ -16,6 +16,7 @@
 #include "chrome/browser/download/download_core_service.h"
 #include "chrome/browser/download/download_core_service_factory.h"
 #include "chrome/browser/download/download_prefs.h"
+#include "chrome/browser/notifications/notification_display_service_tester.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/signin/signin_manager_factory.h"
 #include "chrome/browser/ui/browser.h"
@@ -37,9 +38,6 @@
 #include "net/test/embedded_test_server/embedded_test_server.h"
 #include "net/test/url_request/url_request_slow_download_job.h"
 #include "ui/base/l10n/l10n_util.h"
-#include "ui/message_center/message_center.h"
-#include "ui/message_center/message_center_observer.h"
-#include "ui/message_center/public/cpp/message_center_switches.h"
 #include "url/gurl.h"
 
 namespace {
@@ -66,181 +64,11 @@
     {"charlie@invalid.domain",   "10003", "hashcharl", "Charlie"},
 };
 
-template <typename T>
-bool IsInNotifications(
-    const T& notifications,
-    const std::string& id) {
-  for (const auto& notification : notifications) {
-    if (notification->id() == id)
-      return true;
-  }
-  return false;
-}
-
-// Base class observing notification events.
-class MessageCenterChangeObserver
-    : public message_center::MessageCenterObserver {
- public:
-  MessageCenterChangeObserver() {
-    message_center::MessageCenter::Get()->AddObserver(this);
-  }
-
-  ~MessageCenterChangeObserver() override {
-    message_center::MessageCenter::Get()->RemoveObserver(this);
-  }
-
- protected:
-  void RunLoop() {
-    base::MessageLoop::ScopedNestableTaskAllower allow(
-        base::MessageLoop::current());
-    run_loop_->Run();
-  }
-
-  void QuitRunLoop() {
-    run_loop_->Quit();
-  }
-
-  void ResetRunLoop() {
-    run_loop_.reset(new base::RunLoop);
-  }
-
- private:
-  std::unique_ptr<base::RunLoop> run_loop_;
-
-  DISALLOW_COPY_AND_ASSIGN(MessageCenterChangeObserver);
-};
-
-// Class observing of "ADD" notification events.
-class NotificationAddObserver : public MessageCenterChangeObserver {
- public:
-  NotificationAddObserver() : count_(1) {}
-  explicit NotificationAddObserver(int count) : count_(count) {
-    MessageCenterChangeObserver();
-  }
-  ~NotificationAddObserver() override {}
-
-  bool Wait() {
-    if (count_ <= 0)
-      return count_ == 0;
-
-    waiting_ = true;
-    ResetRunLoop();
-    RunLoop();
-    waiting_ = false;
-    return count_ == 0;
-  }
-
-  // message_center::MessageCenterObserver:
-  void OnNotificationAdded(const std::string& notification_id) override {
-    count_--;
-
-    notification_ids_.push_back(notification_id);
-
-    if (waiting_ && count_ == 0)
-      QuitRunLoop();
-  }
-
-  const std::string& notification_id() const { return notification_ids_.at(0); }
-  const std::vector<std::string>& notification_ids() const {
-    return notification_ids_;
-  }
-
- private:
-  std::vector<std::string> notification_ids_;
-  bool waiting_ = false;
-  int count_;
-
-  DISALLOW_COPY_AND_ASSIGN(NotificationAddObserver);
-};
-
-// Class observing of "UPDATE" notification events.
-class NotificationUpdateObserver : public MessageCenterChangeObserver {
- public:
-  NotificationUpdateObserver() {}
-  explicit NotificationUpdateObserver(const std::string& id)
-      : target_notification_id_(id) {}
-  ~NotificationUpdateObserver() override {}
-
-  std::string Wait() {
-    if (!notification_id_.empty())
-      return notification_id_;
-
-    waiting_ = true;
-    ResetRunLoop();
-    RunLoop();
-    waiting_ = false;
-
-    std::string notification_id(notification_id_);
-    notification_id_.clear();
-    return notification_id;
-  }
-
-  void OnNotificationUpdated(const std::string& notification_id) override {
-    if (notification_id_.empty()) {
-      if (!target_notification_id_.empty() &&
-          target_notification_id_ != notification_id) {
-        return;
-      }
-
-      notification_id_ = notification_id;
-
-      if (waiting_)
-        QuitRunLoop();
-    }
-  }
-
-  void Reset() {
-    notification_id_.clear();
-  }
-
- private:
-  std::string notification_id_;
-  std::string target_notification_id_;
-  bool waiting_ = false;
-
-  DISALLOW_COPY_AND_ASSIGN(NotificationUpdateObserver);
-};
-
-// Class observing of "REMOVE" notification events.
-class NotificationRemoveObserver : public MessageCenterChangeObserver {
- public:
-  NotificationRemoveObserver() {}
-  ~NotificationRemoveObserver() override {}
-
-  std::string Wait() {
-    if (!notification_id_.empty())
-      return notification_id_;
-
-    waiting_ = true;
-    ResetRunLoop();
-    RunLoop();
-    waiting_ = false;
-    return notification_id_;
-  }
-
-  // message_center::MessageCenterObserver:
-  void OnNotificationRemoved(
-      const std::string& notification_id, bool by_user) override {
-    if (notification_id_.empty()) {
-      notification_id_ = notification_id;
-
-      if (waiting_)
-        QuitRunLoop();
-    }
-  }
-
- private:
-  std::string notification_id_;
-  bool waiting_ = false;
-
-  DISALLOW_COPY_AND_ASSIGN(NotificationRemoveObserver);
-};
-
 class TestChromeDownloadManagerDelegate : public ChromeDownloadManagerDelegate {
  public:
   explicit TestChromeDownloadManagerDelegate(Profile* profile)
       : ChromeDownloadManagerDelegate(profile), opened_(false) {}
-  ~TestChromeDownloadManagerDelegate() override {}
+  ~TestChromeDownloadManagerDelegate() override = default;
 
   // ChromeDownloadManagerDelegate override:
   void OpenDownload(content::DownloadItem* item) override { opened_ = true; }
@@ -259,14 +87,22 @@
   bool opened_;
 };
 
-// Utility method to retrieve a message center.
-message_center::MessageCenter* GetMessageCenter() {
-  return message_center::MessageCenter::Get();
+// Utility method to retrieve a notification object by id. Warning: this will
+// check the last display service that was created. If there's a normal and an
+// incognito one, you may want to be explicit.
+base::Optional<message_center::Notification> GetNotification(
+    const std::string& id) {
+  return NotificationDisplayServiceTester::Get()->GetNotification(id);
 }
 
-// Utility method to retrieve a notification object by id.
-message_center::Notification* GetNotification(const std::string& id) {
-  return GetMessageCenter()->FindVisibleNotificationById(id);
+// Waits for a notification to be updated/added on |display_service|.
+void WaitForDownloadNotificationForDisplayService(
+    NotificationDisplayServiceTester* display_service) {
+  base::RunLoop run_loop;
+  display_service->SetNotificationAddedClosure(base::BindRepeating(
+      [](base::RunLoop* run_loop) { run_loop->Quit(); }, &run_loop));
+  run_loop.Run();
+  display_service->SetNotificationAddedClosure(base::RepeatingClosure());
 }
 
 }  // anonnymous namespace
@@ -274,17 +110,19 @@
 // Base class for tests
 class DownloadNotificationTestBase : public InProcessBrowserTest {
  public:
-  ~DownloadNotificationTestBase() override {}
+  DownloadNotificationTestBase() = default;
+  ~DownloadNotificationTestBase() override = default;
 
   void SetUpOnMainThread() override {
     ASSERT_TRUE(embedded_test_server()->Start());
 
+    display_service_ = std::make_unique<NotificationDisplayServiceTester>(
+        browser()->profile());
+
     content::BrowserThread::PostTask(
         content::BrowserThread::IO, FROM_HERE,
         base::BindOnce(&net::URLRequestSlowDownloadJob::AddUrlHandler));
 
-    GetMessageCenter()->DisableTimersForTest();
-
     ASSERT_TRUE(downloads_directory_.CreateUniqueTempDir());
     ASSERT_TRUE(SetDownloadsDirectory(browser()));
   }
@@ -310,9 +148,24 @@
     return content::BrowserContext::GetDownloadManager(browser->profile());
   }
 
- private:
+  // Requests to complete the download and wait for it.
+  void CompleteTheDownload(size_t wait_count = 1u) {
+    content::DownloadTestObserverTerminal download_terminal_observer(
+        GetDownloadManager(browser()), wait_count,
+        content::DownloadTestObserver::ON_DANGEROUS_DOWNLOAD_FAIL);
+    ui_test_utils::NavigateToURL(
+        browser(), GURL(net::URLRequestSlowDownloadJob::kFinishDownloadUrl));
+    download_terminal_observer.WaitForFinished();
+  }
+
+  std::unique_ptr<NotificationDisplayServiceTester> display_service_;
+  std::unique_ptr<NotificationDisplayServiceTester> incognito_display_service_;
+
   // Location of the downloads directory for these tests
   base::ScopedTempDir downloads_directory_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(DownloadNotificationTestBase);
 };
 
 //////////////////////////////////////////////////
@@ -321,7 +174,8 @@
 
 class DownloadNotificationTest : public DownloadNotificationTestBase {
  public:
-  ~DownloadNotificationTest() override {}
+  DownloadNotificationTest() = default;
+  ~DownloadNotificationTest() override = default;
 
   void SetUpOnMainThread() override {
     Profile* profile = browser()->profile();
@@ -354,6 +208,10 @@
     DownloadCoreServiceFactory::GetForBrowserContext(incognito_profile)
         ->SetDownloadManagerDelegateForTesting(
             std::move(incognito_test_delegate));
+
+    incognito_display_service_ =
+        std::make_unique<NotificationDisplayServiceTester>(
+            incognito_browser()->profile());
   }
 
   TestChromeDownloadManagerDelegate* GetIncognitoDownloadManagerDelegate()
@@ -370,23 +228,34 @@
         GURL(net::URLRequestSlowDownloadJob::kKnownSizeUrl));
   }
 
+  // Returns the correct display service for the given Browser. If |browser| is
+  // null, returns the service for browser().
+  NotificationDisplayServiceTester* GetDisplayServiceForBrowser(
+      Browser* browser) {
+    return (browser && browser == DownloadNotificationTest::incognito_browser())
+               ? incognito_display_service_.get()
+               : display_service_.get();
+  }
+
+  void WaitForDownloadNotification(Browser* browser = nullptr) {
+    WaitForDownloadNotificationForDisplayService(
+        GetDisplayServiceForBrowser(browser));
+  }
+
   void CreateDownloadForBrowserAndURL(Browser* browser, GURL url) {
     // Starts a download.
-    NotificationAddObserver download_start_notification_observer;
     ui_test_utils::NavigateToURL(browser, url);
-    EXPECT_TRUE(download_start_notification_observer.Wait());
 
     // Confirms that a notification is created.
-    notification_id_ = download_start_notification_observer.notification_id();
+    WaitForDownloadNotification(browser);
+    auto download_notifications =
+        GetDisplayServiceForBrowser(browser)->GetDisplayedNotificationsForType(
+            NotificationHandler::Type::DOWNLOAD);
+    ASSERT_EQ(1u, download_notifications.size());
+    notification_id_ = download_notifications[0].id();
     EXPECT_FALSE(notification_id_.empty());
     ASSERT_TRUE(notification());
 
-    // Confirms that there is only one notification.
-    message_center::NotificationList::Notifications
-        visible_notifications = GetMessageCenter()->GetVisibleNotifications();
-    EXPECT_EQ(1u, visible_notifications.size());
-    EXPECT_TRUE(IsInNotifications(visible_notifications, notification_id_));
-
     // Confirms that a download is also started.
     std::vector<content::DownloadItem*> downloads;
     GetDownloadManager(browser)->GetAllDownloads(&downloads);
@@ -395,9 +264,42 @@
     ASSERT_TRUE(download_item_);
   }
 
+  void CloseNotification() {
+    EXPECT_TRUE(notification());
+    display_service_->RemoveNotification(NotificationHandler::Type::DOWNLOAD,
+                                         notification_id(), true /* by_user */);
+    EXPECT_FALSE(notification());
+    EXPECT_EQ(0u, GetDownloadNotifications().size());
+  }
+
+  void VerifyDownloadState(content::DownloadItem::DownloadState state) {
+    std::vector<content::DownloadItem*> downloads;
+    GetDownloadManager(browser())->GetAllDownloads(&downloads);
+    ASSERT_EQ(1u, downloads.size());
+    EXPECT_EQ(state, downloads[0]->GetState());
+  }
+
+  void VerifyUpdatePropagatesToNotification(content::DownloadItem* item) {
+    bool notification_updated = false;
+    display_service_->SetNotificationAddedClosure(base::BindRepeating(
+        [](bool* updated) { *updated = true; }, &notification_updated));
+    item->UpdateObservers();
+    EXPECT_TRUE(notification_updated);
+    display_service_->SetNotificationAddedClosure(base::RepeatingClosure());
+  }
+
+  void InterruptTheDownload() {
+    content::DownloadTestObserverInterrupted download_interrupted_observer(
+        GetDownloadManager(browser()), 1u, /* wait_count */
+        content::DownloadTestObserver::ON_DANGEROUS_DOWNLOAD_FAIL);
+    ui_test_utils::NavigateToURL(
+        browser(), GURL(net::URLRequestSlowDownloadJob::kErrorDownloadUrl));
+    download_interrupted_observer.WaitForFinished();
+  }
+
   content::DownloadItem* download_item() const { return download_item_; }
   std::string notification_id() const { return notification_id_; }
-  message_center::Notification* notification() const {
+  base::Optional<message_center::Notification> notification() const {
     return GetNotification(notification_id_);
   }
   Browser* incognito_browser() const { return incognito_browser_; }
@@ -405,11 +307,17 @@
     return DownloadPrefs::FromDownloadManager(GetDownloadManager(browser()))->
       DownloadPath();
   }
+  std::vector<message_center::Notification> GetDownloadNotifications() {
+    return display_service_->GetDisplayedNotificationsForType(
+        NotificationHandler::Type::DOWNLOAD);
+  }
 
  private:
   content::DownloadItem* download_item_ = nullptr;
   Browser* incognito_browser_ = nullptr;
   std::string notification_id_;
+
+  DISALLOW_COPY_AND_ASSIGN(DownloadNotificationTest);
 };
 
 IN_PROC_BROWSER_TEST_F(DownloadNotificationTest, DownloadFile) {
@@ -418,47 +326,32 @@
   EXPECT_EQ(l10n_util::GetStringFUTF16(
                 IDS_DOWNLOAD_STATUS_IN_PROGRESS_TITLE,
                 download_item()->GetFileNameToReportUser().LossyDisplayName()),
-            GetNotification(notification_id())->title());
-  EXPECT_EQ(message_center::NOTIFICATION_TYPE_PROGRESS,
-            GetNotification(notification_id())->type());
+            notification()->title());
+  EXPECT_EQ(message_center::NOTIFICATION_TYPE_PROGRESS, notification()->type());
 
   // Confirms that the download update is delivered to the notification.
-  NotificationUpdateObserver download_notification_periodically_update_observer;
-  download_item()->UpdateObservers();
-  download_notification_periodically_update_observer.Wait();
+  EXPECT_TRUE(notification());
+  VerifyUpdatePropagatesToNotification(download_item());
 
-  // Requests to complete the download.
-  ui_test_utils::NavigateToURL(
-      browser(), GURL(net::URLRequestSlowDownloadJob::kFinishDownloadUrl));
-
-  // Waits for download completion.
-  NotificationUpdateObserver
-      download_change_notification_observer(notification_id());
-  while (download_item()->GetState() != content::DownloadItem::COMPLETE) {
-    download_change_notification_observer.Wait();
-    download_change_notification_observer.Reset();
-  }
+  CompleteTheDownload();
 
   // Checks strings.
+  ASSERT_TRUE(notification());
   EXPECT_EQ(l10n_util::GetStringUTF16(IDS_DOWNLOAD_STATUS_COMPLETE_TITLE),
-            GetNotification(notification_id())->title());
+            notification()->title());
   EXPECT_EQ(download_item()->GetFileNameToReportUser().LossyDisplayName(),
-            GetNotification(notification_id())->message());
+            notification()->message());
   EXPECT_EQ(message_center::NOTIFICATION_TYPE_BASE_FORMAT,
-            GetNotification(notification_id())->type());
+            notification()->type());
 
   // Confirms that there is only one notification.
-  message_center::NotificationList::Notifications
-      visible_notifications = GetMessageCenter()->GetVisibleNotifications();
-  EXPECT_EQ(1u, visible_notifications.size());
-  EXPECT_TRUE(IsInNotifications(visible_notifications, notification_id()));
-
-  // Opens the message center.
-  GetMessageCenter()->SetVisibility(message_center::VISIBILITY_MESSAGE_CENTER);
+  ASSERT_EQ(1u, GetDownloadNotifications().size());
 
   // Try to open the downloaded item by clicking the notification.
   EXPECT_FALSE(GetDownloadManagerDelegate()->opened());
-  GetMessageCenter()->ClickOnNotification(notification_id());
+  display_service_->SimulateClick(NotificationHandler::Type::DOWNLOAD,
+                                  notification_id(), base::nullopt,
+                                  base::nullopt);
   EXPECT_TRUE(GetDownloadManagerDelegate()->opened());
 
   EXPECT_FALSE(GetNotification(notification_id()));
@@ -482,22 +375,13 @@
             download_item()->GetDangerType());
   EXPECT_TRUE(download_item()->IsDangerous());
 
-  // Opens the message center.
-  GetMessageCenter()->SetVisibility(message_center::VISIBILITY_MESSAGE_CENTER);
+  // Clicks the "keep" button.
+  display_service_->SimulateClick(NotificationHandler::Type::DOWNLOAD,
+                                  notification_id(), 1,  // 2nd button: "Keep"
+                                  base::nullopt);
 
-  NotificationRemoveObserver notification_close_observer;
-  NotificationAddObserver notification_add_observer;
-
-  // Cicks the "keep" button.
-  notification()->ButtonClick(1);  // 2nd button: "Keep"
-  // Clicking makes the message center closed.
-  GetMessageCenter()->SetVisibility(message_center::VISIBILITY_TRANSIENT);
-
-  // Confirms that the notification is closed and re-shown.
-  EXPECT_EQ(notification_id(), notification_close_observer.Wait());
-  notification_add_observer.Wait();
-  EXPECT_EQ(notification_id(), notification_add_observer.notification_id());
-  EXPECT_EQ(1u, GetMessageCenter()->GetVisibleNotifications().size());
+  // The notification is closed and re-shown.
+  EXPECT_TRUE(notification());
 
   // Checks the download status.
   EXPECT_EQ(content::DOWNLOAD_DANGER_TYPE_USER_VALIDATED,
@@ -533,29 +417,23 @@
             download_item()->GetDangerType());
   EXPECT_TRUE(download_item()->IsDangerous());
 
-  // Opens the message center.
-  GetMessageCenter()->SetVisibility(message_center::VISIBILITY_MESSAGE_CENTER);
   // Ensures the notification exists.
-  EXPECT_EQ(1u, GetMessageCenter()->GetVisibleNotifications().size());
-
-  NotificationRemoveObserver notification_close_observer;
+  EXPECT_TRUE(notification());
 
   // Clicks the "Discard" button.
-  notification()->ButtonClick(0);  // 1st button: "Discard"
-  // Clicking makes the message center closed.
-  GetMessageCenter()->SetVisibility(message_center::VISIBILITY_TRANSIENT);
+  display_service_->SimulateClick(NotificationHandler::Type::DOWNLOAD,
+                                  notification_id(),
+                                  0,  // 1st button: "Discard"
+                                  base::nullopt);
 
-  // Confirms that the notification is closed.
-  EXPECT_EQ(notification_id(), notification_close_observer.Wait());
-
-  // Ensures the notification has closed.
-  EXPECT_EQ(0u, GetMessageCenter()->GetVisibleNotifications().size());
+  EXPECT_FALSE(notification());
 
   // Wait for the download completion.
   download_terminal_observer.WaitForFinished();
 
   // Checks there is neither any download nor any notification.
-  EXPECT_EQ(0u, GetMessageCenter()->GetVisibleNotifications().size());
+  EXPECT_FALSE(notification());
+  EXPECT_EQ(0u, GetDownloadNotifications().size());
   std::vector<content::DownloadItem*> downloads;
   GetDownloadManager(browser())->GetAllDownloads(&downloads);
   EXPECT_EQ(0u, downloads.size());
@@ -577,138 +455,61 @@
   // Wait for the download completion.
   download_terminal_observer.WaitForFinished();
 
-  // Waits for download completion.
-  NotificationUpdateObserver
-      download_change_notification_observer(notification_id());
-  while (GetNotification(notification_id())->image().IsEmpty()) {
-    download_change_notification_observer.Wait();
-    download_change_notification_observer.Reset();
-  }
+  WaitForDownloadNotification();
+  EXPECT_FALSE(notification()->image().IsEmpty());
 }
 
 IN_PROC_BROWSER_TEST_F(DownloadNotificationTest,
                        CloseNotificationAfterDownload) {
   CreateDownload();
 
-  // Requests to complete the download.
-  ui_test_utils::NavigateToURL(
-      browser(), GURL(net::URLRequestSlowDownloadJob::kFinishDownloadUrl));
+  CompleteTheDownload();
 
-  // Waits for download completion.
-  NotificationUpdateObserver
-      download_change_notification_observer(notification_id());
-  while (download_item()->GetState() != content::DownloadItem::COMPLETE) {
-    download_change_notification_observer.Wait();
-    download_change_notification_observer.Reset();
-  }
+  CloseNotification();
 
-  // Opens the message center.
-  GetMessageCenter()->SetVisibility(message_center::VISIBILITY_MESSAGE_CENTER);
-
-  // Closes the notification.
-  NotificationRemoveObserver notification_close_observer;
-  GetMessageCenter()->RemoveNotification(notification_id(), true /* by_user */);
-  EXPECT_EQ(notification_id(), notification_close_observer.Wait());
-
-  EXPECT_EQ(0u, GetMessageCenter()->GetVisibleNotifications().size());
-
-  // Confirms that a download is also started.
-  std::vector<content::DownloadItem*> downloads;
-  GetDownloadManager(browser())->GetAllDownloads(&downloads);
-  EXPECT_EQ(1u, downloads.size());
-  EXPECT_EQ(content::DownloadItem::COMPLETE, downloads[0]->GetState());
+  VerifyDownloadState(content::DownloadItem::COMPLETE);
 }
 
 IN_PROC_BROWSER_TEST_F(DownloadNotificationTest,
                        CloseNotificationWhileDownloading) {
   CreateDownload();
 
-  // Closes the notification.
-  NotificationRemoveObserver notification_close_observer;
-  GetMessageCenter()->RemoveNotification(notification_id(), true /* by_user */);
-  EXPECT_EQ(notification_id(), notification_close_observer.Wait());
+  CloseNotification();
 
-  EXPECT_EQ(0u, GetMessageCenter()->GetVisibleNotifications().size());
+  VerifyDownloadState(content::DownloadItem::IN_PROGRESS);
 
-  // Confirms that a download is still in progress.
-  std::vector<content::DownloadItem*> downloads;
-  content::DownloadManager* download_manager = GetDownloadManager(browser());
-  download_manager->GetAllDownloads(&downloads);
-  EXPECT_EQ(1u, downloads.size());
-  EXPECT_EQ(content::DownloadItem::IN_PROGRESS, downloads[0]->GetState());
+  CompleteTheDownload();
 
-  // Installs observers before requesting the completion.
-  NotificationAddObserver download_notification_add_observer;
-  content::DownloadTestObserverTerminal download_terminal_observer(
-      download_manager,
-      1u, /* wait_count */
-      content::DownloadTestObserver::ON_DANGEROUS_DOWNLOAD_FAIL);
-
-  // Requests to complete the download and wait for it.
-  ui_test_utils::NavigateToURL(
-      browser(), GURL(net::URLRequestSlowDownloadJob::kFinishDownloadUrl));
-  download_terminal_observer.WaitForFinished();
-
-  // Waits that new notification.
-  download_notification_add_observer.Wait();
-
-  // Confirms that there is only one notification.
-  message_center::NotificationList::Notifications
-      visible_notifications = GetMessageCenter()->GetVisibleNotifications();
-  EXPECT_EQ(1u, visible_notifications.size());
-  EXPECT_TRUE(IsInNotifications(visible_notifications, notification_id()));
+  EXPECT_TRUE(notification());
 }
 
 IN_PROC_BROWSER_TEST_F(DownloadNotificationTest, InterruptDownload) {
   CreateDownload();
 
-  // Installs observers before requesting.
-  NotificationUpdateObserver
-      download_notification_update_observer(notification_id());
-  content::DownloadTestObserverInterrupted download_terminal_observer(
-      GetDownloadManager(browser()),
-      1u, /* wait_count */
-      content::DownloadTestObserver::ON_DANGEROUS_DOWNLOAD_FAIL);
+  InterruptTheDownload();
 
-  // Requests to fail the download and wait for it.
-  ui_test_utils::NavigateToURL(
-      browser(), GURL(net::URLRequestSlowDownloadJob::kErrorDownloadUrl));
-  download_terminal_observer.WaitForFinished();
-
-  // Waits that new notification.
-  download_notification_update_observer.Wait();
-
-  // Confirms that there is only one notification.
-  message_center::NotificationList::Notifications
-      visible_notifications = GetMessageCenter()->GetVisibleNotifications();
-  EXPECT_EQ(1u, visible_notifications.size());
-  EXPECT_TRUE(IsInNotifications(visible_notifications, notification_id()));
+  EXPECT_EQ(1u, GetDownloadNotifications().size());
+  ASSERT_TRUE(notification());
 
   // Checks strings.
   EXPECT_EQ(l10n_util::GetStringFUTF16(
                 IDS_DOWNLOAD_STATUS_DOWNLOAD_FAILED_TITLE,
                 download_item()->GetFileNameToReportUser().LossyDisplayName()),
-            GetNotification(notification_id())->title());
-  EXPECT_NE(GetNotification(notification_id())->message().find(
-                l10n_util::GetStringFUTF16(
-                    IDS_DOWNLOAD_STATUS_INTERRUPTED,
-                    l10n_util::GetStringUTF16(
-                        IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_NETWORK_ERROR))),
+            notification()->title());
+  EXPECT_NE(notification()->message().find(l10n_util::GetStringFUTF16(
+                IDS_DOWNLOAD_STATUS_INTERRUPTED,
+                l10n_util::GetStringUTF16(
+                    IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_NETWORK_ERROR))),
             std::string::npos);
   EXPECT_EQ(message_center::NOTIFICATION_TYPE_BASE_FORMAT,
-            GetNotification(notification_id())->type());
+            notification()->type());
 }
 
 IN_PROC_BROWSER_TEST_F(DownloadNotificationTest,
                        InterruptDownloadAfterClosingNotification) {
   CreateDownload();
 
-  // Closes the notification.
-  NotificationRemoveObserver notification_close_observer;
-  GetMessageCenter()->RemoveNotification(notification_id(), true /* by_user */);
-  EXPECT_EQ(notification_id(), notification_close_observer.Wait());
-
-  EXPECT_EQ(0u, GetMessageCenter()->GetVisibleNotifications().size());
+  CloseNotification();
 
   // Confirms that a download is still in progress.
   std::vector<content::DownloadItem*> downloads;
@@ -718,36 +519,24 @@
   EXPECT_EQ(content::DownloadItem::IN_PROGRESS, downloads[0]->GetState());
 
   // Installs observers before requesting the completion.
-  NotificationAddObserver download_notification_add_observer;
   content::DownloadTestObserverInterrupted download_terminal_observer(
       download_manager,
       1u, /* wait_count */
       content::DownloadTestObserver::ON_DANGEROUS_DOWNLOAD_FAIL);
 
-  // Requests to fail the download and wait for it.
-  ui_test_utils::NavigateToURL(
-      browser(), GURL(net::URLRequestSlowDownloadJob::kErrorDownloadUrl));
-  download_terminal_observer.WaitForFinished();
-
-  // Waits that new notification.
-  download_notification_add_observer.Wait();
+  InterruptTheDownload();
 
   // Confirms that there is only one notification.
-  message_center::NotificationList::Notifications
-      visible_notifications = GetMessageCenter()->GetVisibleNotifications();
-  EXPECT_EQ(1u, visible_notifications.size());
-  EXPECT_TRUE(IsInNotifications(visible_notifications, notification_id()));
+  EXPECT_EQ(1u, GetDownloadNotifications().size());
+  ASSERT_TRUE(notification());
 }
 
 IN_PROC_BROWSER_TEST_F(DownloadNotificationTest, DownloadRemoved) {
   CreateDownload();
 
-  NotificationRemoveObserver notification_close_observer;
+  EXPECT_TRUE(notification());
   download_item()->Remove();
-  EXPECT_EQ(notification_id(), notification_close_observer.Wait());
-
-  // Confirms that the notification is removed.
-  EXPECT_EQ(0u, GetMessageCenter()->GetVisibleNotifications().size());
+  EXPECT_FALSE(notification());
 
   // Confirms that the download item is removed.
   std::vector<content::DownloadItem*> downloads;
@@ -760,43 +549,27 @@
   GURL url2(net::URLRequestSlowDownloadJob::kKnownSizeUrl);
 
   // Starts the 1st download.
-  NotificationAddObserver download_start_notification_observer1;
   ui_test_utils::NavigateToURL(browser(), url1);
-  EXPECT_TRUE(download_start_notification_observer1.Wait());
-  std::string notification_id1 =
-      download_start_notification_observer1.notification_id();
+  WaitForDownloadNotification();
+  auto notifications = GetDownloadNotifications();
+  ASSERT_EQ(1u, notifications.size());
+  std::string notification_id1 = notifications[0].id();
   EXPECT_FALSE(notification_id1.empty());
 
   // Confirms that there is a download.
   std::vector<content::DownloadItem*> downloads;
   GetDownloadManager(browser())->GetAllDownloads(&downloads);
-  EXPECT_EQ(1u, downloads.size());
+  ASSERT_EQ(1u, downloads.size());
   content::DownloadItem* download1 = downloads[0];
 
-  // Confirms that there is a notifications.
-  message_center::NotificationList::Notifications
-      visible_notifications = GetMessageCenter()->GetVisibleNotifications();
-  EXPECT_EQ(1u, visible_notifications.size());
-  EXPECT_TRUE(IsInNotifications(visible_notifications, notification_id1));
-
-  // Confirms that there is a popup notifications.
-  message_center::NotificationList::PopupNotifications
-      popup_notifications = GetMessageCenter()->GetPopupNotifications();
-  EXPECT_EQ(1u, popup_notifications.size());
-  EXPECT_TRUE(IsInNotifications(popup_notifications, notification_id1));
-
-  // Starts the 2nd download and waits for a notification.
-  NotificationAddObserver download_start_notification_observer2(2);
+  // Starts the 2nd download.
   ui_test_utils::NavigateToURL(browser(), url2);
-  // 2 notifications should be added. One is for new download (url2), and the
-  // other one is for reshowing the existing download (url1) as a low-priority
-  // notification.
-  EXPECT_TRUE(download_start_notification_observer2.Wait());
+  WaitForDownloadNotification();
 
   // Confirms that there are 2 downloads.
   downloads.clear();
   GetDownloadManager(browser())->GetAllDownloads(&downloads);
-  EXPECT_EQ(2u, downloads.size());
+  ASSERT_EQ(2u, downloads.size());
   content::DownloadItem* download2;
   if (download1 == downloads[0])
     download2 = downloads[1];
@@ -806,31 +579,18 @@
     NOTREACHED();
   EXPECT_NE(download1, download2);
 
+  notifications = GetDownloadNotifications();
   // Confirms that there are 2 notifications.
-  visible_notifications = GetMessageCenter()->GetVisibleNotifications();
-  EXPECT_EQ(2u, visible_notifications.size());
+  EXPECT_EQ(2u, notifications.size());
 
   std::string notification_id2;
-  for (auto* notification : visible_notifications) {
-    if (notification->id() == notification_id1) {
+  for (const auto& notification : notifications) {
+    if (notification.id() == notification_id1)
       continue;
-    } else if (notification->type() ==
-               message_center::NOTIFICATION_TYPE_PROGRESS) {
-      notification_id2 = (notification->id());
-    }
+
+    notification_id2 = notification.id();
   }
-  EXPECT_TRUE(!notification_id2.empty());
-
-  // Confirms that the both notifications are visible either as popup or in the
-  // message center.
-  EXPECT_TRUE(IsInNotifications(visible_notifications, notification_id1));
-  EXPECT_TRUE(IsInNotifications(visible_notifications, notification_id2));
-
-  // Confirms that the new one is popup, and the old one is not.
-  popup_notifications = GetMessageCenter()->GetPopupNotifications();
-  EXPECT_EQ(1u, popup_notifications.size());
-  EXPECT_FALSE(IsInNotifications(popup_notifications, notification_id1));
-  EXPECT_TRUE(IsInNotifications(popup_notifications, notification_id2));
+  EXPECT_FALSE(notification_id2.empty());
 
   // Confirms that the old one is low priority, and the new one is default.
   const int in_progress_priority1 =
@@ -842,39 +602,23 @@
 
   // Confirms that the updates of both download are delivered to the
   // notifications.
-  NotificationUpdateObserver
-      notification_periodically_update_observer1(notification_id1);
-  download1->UpdateObservers();
-  notification_periodically_update_observer1.Wait();
-  NotificationUpdateObserver
-      notification_periodically_update_observer2(notification_id2);
-  download2->UpdateObservers();
-  notification_periodically_update_observer2.Wait();
+  VerifyUpdatePropagatesToNotification(download1);
+  VerifyUpdatePropagatesToNotification(download2);
+
+  // Confirms the correct type of notification while download is in progress.
+  EXPECT_EQ(message_center::NOTIFICATION_TYPE_PROGRESS,
+            GetNotification(notification_id1)->type());
+  EXPECT_EQ(message_center::NOTIFICATION_TYPE_PROGRESS,
+            GetNotification(notification_id2)->type());
 
   // Requests to complete the downloads.
-  ui_test_utils::NavigateToURL(
-      browser(), GURL(net::URLRequestSlowDownloadJob::kFinishDownloadUrl));
+  CompleteTheDownload(2);
 
-  // Waits for the completion of downloads.
-  NotificationUpdateObserver download_change_notification_observer;
-  while (download1->GetState() != content::DownloadItem::COMPLETE ||
-         download2->GetState() != content::DownloadItem::COMPLETE) {
-    download_change_notification_observer.Wait();
-    download_change_notification_observer.Reset();
-  }
-
-  // Confirms that the both notifications are visible either as popup or in the
-  // message center.
-  visible_notifications = GetMessageCenter()->GetVisibleNotifications();
-  EXPECT_EQ(2u, visible_notifications.size());
-  EXPECT_TRUE(IsInNotifications(visible_notifications, notification_id1));
-  EXPECT_TRUE(IsInNotifications(visible_notifications, notification_id2));
-
-  // Confirms that the both are popup'd.
-  popup_notifications = GetMessageCenter()->GetPopupNotifications();
-  EXPECT_EQ(2u, popup_notifications.size());
-  EXPECT_TRUE(IsInNotifications(popup_notifications, notification_id1));
-  EXPECT_TRUE(IsInNotifications(popup_notifications, notification_id2));
+  // Confirms that the both notifications are visible.
+  notifications = GetDownloadNotifications();
+  EXPECT_EQ(2u, notifications.size());
+  ASSERT_TRUE(GetNotification(notification_id1));
+  ASSERT_TRUE(GetNotification(notification_id2));
 
   // Confirms that both increase in priority when finished.
   EXPECT_GT(GetNotification(notification_id1)->priority(),
@@ -893,95 +637,58 @@
                        DownloadMultipleFilesOneByOne) {
   CreateDownload();
   content::DownloadItem* first_download_item = download_item();
-  content::DownloadItem* second_download_item = nullptr;
   std::string first_notification_id = notification_id();
-  std::string second_notification_id;
 
-  // Requests to complete the first download.
-  ui_test_utils::NavigateToURL(
-      browser(), GURL(net::URLRequestSlowDownloadJob::kFinishDownloadUrl));
-
-  // Waits for completion of the first download.
-  NotificationUpdateObserver
-      download_change_notification_observer1(first_notification_id);
-  while (first_download_item->GetState() != content::DownloadItem::COMPLETE) {
-    download_change_notification_observer1.Wait();
-    download_change_notification_observer1.Reset();
-  }
+  CompleteTheDownload();
   EXPECT_EQ(content::DownloadItem::COMPLETE, first_download_item->GetState());
 
   // Checks the message center.
-  EXPECT_EQ(1u, GetMessageCenter()->GetVisibleNotifications().size());
+  EXPECT_TRUE(notification());
 
   // Starts the second download.
   GURL url(net::URLRequestSlowDownloadJob::kKnownSizeUrl);
-  NotificationAddObserver download_start_notification_observer;
   ui_test_utils::NavigateToURL(browser(), url);
-  EXPECT_TRUE(download_start_notification_observer.Wait());
+  WaitForDownloadNotification();
 
   // Confirms that the second notification is created.
-  second_notification_id =
-      download_start_notification_observer.notification_id();
+  auto notifications = GetDownloadNotifications();
+  ASSERT_EQ(2u, notifications.size());
+  std::string second_notification_id =
+      notifications[(notifications[0].id() == notification_id() ? 1 : 0)].id();
   EXPECT_FALSE(second_notification_id.empty());
   ASSERT_TRUE(GetNotification(second_notification_id));
 
-  // Confirms that there are two notifications, including the second
-  // notification.
-  message_center::NotificationList::Notifications
-      visible_notifications = GetMessageCenter()->GetVisibleNotifications();
-  EXPECT_EQ(2u, visible_notifications.size());
-  EXPECT_TRUE(IsInNotifications(visible_notifications, first_notification_id));
-  EXPECT_TRUE(IsInNotifications(visible_notifications, second_notification_id));
-
   // Confirms that the second download is also started.
   std::vector<content::DownloadItem*> downloads;
   GetDownloadManager(browser())->GetAllDownloads(&downloads);
   EXPECT_EQ(2u, downloads.size());
   EXPECT_TRUE(first_download_item == downloads[0] ||
               first_download_item == downloads[1]);
-  // Stores the second download.
-  if (first_download_item == downloads[0])
-    second_download_item = downloads[1];
-  else
-    second_download_item = downloads[0];
+  content::DownloadItem* second_download_item =
+      downloads[first_download_item == downloads[0] ? 1 : 0];
 
   EXPECT_EQ(content::DownloadItem::IN_PROGRESS,
             second_download_item->GetState());
 
   // Requests to complete the second download.
-  ui_test_utils::NavigateToURL(
-      browser(), GURL(net::URLRequestSlowDownloadJob::kFinishDownloadUrl));
+  CompleteTheDownload();
 
-  // Waits for completion of the second download.
-  NotificationUpdateObserver
-      download_change_notification_observer2(second_notification_id);
-  while (second_download_item->GetState() != content::DownloadItem::COMPLETE) {
-    download_change_notification_observer2.Wait();
-    download_change_notification_observer2.Reset();
-  }
-
-  // Opens the message center.
-  GetMessageCenter()->SetVisibility(message_center::VISIBILITY_MESSAGE_CENTER);
-  // Checks the message center.
-  EXPECT_EQ(2u, GetMessageCenter()->GetVisibleNotifications().size());
+  EXPECT_EQ(2u, GetDownloadNotifications().size());
 }
 
 IN_PROC_BROWSER_TEST_F(DownloadNotificationTest, CancelDownload) {
   CreateDownload();
 
-  // Opens the message center.
-  GetMessageCenter()->SetVisibility(message_center::VISIBILITY_MESSAGE_CENTER);
+  // Cancels the notification by clicking the "cancel" button.
+  display_service_->SimulateClick(NotificationHandler::Type::DOWNLOAD,
+                                  notification_id(), 1, base::nullopt);
+  EXPECT_FALSE(notification());
+  EXPECT_EQ(0u, GetDownloadNotifications().size());
 
-  // Cancels the notification by clicking the "cancel' button.
-  NotificationRemoveObserver notification_close_observer;
-  notification()->ButtonClick(1);
-  EXPECT_EQ(notification_id(), notification_close_observer.Wait());
-  EXPECT_EQ(0u, GetMessageCenter()->GetVisibleNotifications().size());
-
-  // Confirms that a download is also cancelled.
+  // Confirms that the download is cancelled.
   std::vector<content::DownloadItem*> downloads;
   GetDownloadManager(browser())->GetAllDownloads(&downloads);
-  EXPECT_EQ(1u, downloads.size());
+  ASSERT_EQ(1u, downloads.size());
   EXPECT_EQ(content::DownloadItem::CANCELLED, downloads[0]->GetState());
 }
 
@@ -989,30 +696,12 @@
                        DownloadCancelledByUserExternally) {
   CreateDownload();
 
-  // Cancels the notification by clicking the "cancel' button.
-  NotificationRemoveObserver notification_close_observer;
+  // Cancels the notification through the DownloadItem.
   download_item()->Cancel(true /* by_user */);
-  EXPECT_EQ(notification_id(), notification_close_observer.Wait());
-  EXPECT_EQ(0u, GetMessageCenter()->GetVisibleNotifications().size());
+  EXPECT_FALSE(notification());
+  EXPECT_EQ(0u, GetDownloadNotifications().size());
 
-  // Confirms that a download is also cancelled.
-  std::vector<content::DownloadItem*> downloads;
-  GetDownloadManager(browser())->GetAllDownloads(&downloads);
-  EXPECT_EQ(1u, downloads.size());
-  EXPECT_EQ(content::DownloadItem::CANCELLED, downloads[0]->GetState());
-}
-
-IN_PROC_BROWSER_TEST_F(DownloadNotificationTest,
-                       DownloadCancelledExternally) {
-  CreateDownload();
-
-  // Cancels the notification by clicking the "cancel' button.
-  NotificationRemoveObserver notification_close_observer;
-  download_item()->Cancel(false /* by_user */);
-  EXPECT_EQ(notification_id(), notification_close_observer.Wait());
-  EXPECT_EQ(0u, GetMessageCenter()->GetVisibleNotifications().size());
-
-  // Confirms that a download is also cancelled.
+  // Confirms that the download is cancelled.
   std::vector<content::DownloadItem*> downloads;
   GetDownloadManager(browser())->GetAllDownloads(&downloads);
   EXPECT_EQ(1u, downloads.size());
@@ -1030,41 +719,36 @@
   EXPECT_EQ(l10n_util::GetStringFUTF16(
                 IDS_DOWNLOAD_STATUS_IN_PROGRESS_TITLE,
                 download_item()->GetFileNameToReportUser().LossyDisplayName()),
-            GetNotification(notification_id())->title());
-  EXPECT_EQ(message_center::NOTIFICATION_TYPE_PROGRESS,
-            GetNotification(notification_id())->type());
+            notification()->title());
+  EXPECT_EQ(message_center::NOTIFICATION_TYPE_PROGRESS, notification()->type());
   EXPECT_TRUE(download_item()->GetBrowserContext()->IsOffTheRecord());
 
   // Requests to complete the download.
+  content::DownloadTestObserverTerminal download_terminal_observer(
+      GetDownloadManager(incognito_browser()), 1,
+      content::DownloadTestObserver::ON_DANGEROUS_DOWNLOAD_FAIL);
   ui_test_utils::NavigateToURL(
       incognito_browser(),
       GURL(net::URLRequestSlowDownloadJob::kFinishDownloadUrl));
-
-  // Waits for download completion.
-  NotificationUpdateObserver
-      download_change_notification_observer(notification_id());
-  while (download_item()->GetState() != content::DownloadItem::COMPLETE) {
-    download_change_notification_observer.Wait();
-    download_change_notification_observer.Reset();
-  }
+  download_terminal_observer.WaitForFinished();
 
   EXPECT_EQ(l10n_util::GetStringUTF16(IDS_DOWNLOAD_STATUS_COMPLETE_TITLE),
-            GetNotification(notification_id())->title());
+            notification()->title());
   EXPECT_EQ(download_item()->GetFileNameToReportUser().LossyDisplayName(),
-            GetNotification(notification_id())->message());
+            notification()->message());
   EXPECT_EQ(message_center::NOTIFICATION_TYPE_BASE_FORMAT,
-            GetNotification(notification_id())->type());
-
-  // Opens the message center.
-  GetMessageCenter()->SetVisibility(message_center::VISIBILITY_MESSAGE_CENTER);
+            notification()->type());
 
   // Try to open the downloaded item by clicking the notification.
+  EXPECT_TRUE(incognito_display_service_->GetNotification(notification_id()));
   EXPECT_FALSE(GetIncognitoDownloadManagerDelegate()->opened());
-  GetMessageCenter()->ClickOnNotification(notification_id());
+  incognito_display_service_->SimulateClick(NotificationHandler::Type::DOWNLOAD,
+                                            notification_id(), base::nullopt,
+                                            base::nullopt);
   EXPECT_TRUE(GetIncognitoDownloadManagerDelegate()->opened());
   EXPECT_FALSE(GetDownloadManagerDelegate()->opened());
 
-  EXPECT_FALSE(GetNotification(notification_id()));
+  EXPECT_FALSE(incognito_display_service_->GetNotification(notification_id()));
   chrome::CloseWindow(incognito_browser());
 }
 
@@ -1076,11 +760,13 @@
   GURL url_normal(net::URLRequestSlowDownloadJob::kKnownSizeUrl);
 
   // Starts the incognito download.
-  NotificationAddObserver download_start_notification_observer1;
   ui_test_utils::NavigateToURL(incognito_browser(), url_incognito);
-  EXPECT_TRUE(download_start_notification_observer1.Wait());
-  std::string notification_id1 =
-      download_start_notification_observer1.notification_id();
+  WaitForDownloadNotification(incognito_browser());
+  auto incognito_notifications =
+      incognito_display_service_->GetDisplayedNotificationsForType(
+          NotificationHandler::Type::DOWNLOAD);
+  ASSERT_EQ(1u, incognito_notifications.size());
+  std::string notification_id1 = incognito_notifications[0].id();
   EXPECT_FALSE(notification_id1.empty());
 
   // Confirms that there is a download.
@@ -1093,11 +779,11 @@
   content::DownloadItem* download_incognito = downloads[0];
 
   // Starts the normal download.
-  NotificationAddObserver download_start_notification_observer2;
   ui_test_utils::NavigateToURL(browser(), url_normal);
-  EXPECT_TRUE(download_start_notification_observer2.Wait());
-  std::string notification_id2 =
-      download_start_notification_observer2.notification_id();
+  WaitForDownloadNotification();
+  auto normal_notifications = GetDownloadNotifications();
+  ASSERT_EQ(1u, normal_notifications.size());
+  std::string notification_id2 = normal_notifications[0].id();
   EXPECT_FALSE(notification_id2.empty());
 
   // Confirms that there are 2 downloads.
@@ -1112,33 +798,34 @@
   EXPECT_EQ(download_incognito, downloads[0]);
 
   // Confirms the types of download notifications are correct.
+  auto incognito_notification =
+      incognito_display_service_->GetNotification(notification_id1);
+  ASSERT_TRUE(incognito_notification);
   EXPECT_EQ(message_center::NOTIFICATION_TYPE_PROGRESS,
-            GetNotification(notification_id1)->type());
-  EXPECT_EQ(-1, GetNotification(notification_id1)->progress());
+            incognito_notification->type());
+  EXPECT_EQ(-1, incognito_notification->progress());
+
+  auto normal_notification =
+      display_service_->GetNotification(notification_id2);
+  ASSERT_TRUE(normal_notification);
   EXPECT_EQ(message_center::NOTIFICATION_TYPE_PROGRESS,
-            GetNotification(notification_id2)->type());
-  EXPECT_LE(0, GetNotification(notification_id2)->progress());
+            normal_notification->type());
+  EXPECT_LE(0, normal_notification->progress());
 
   EXPECT_TRUE(download_incognito->GetBrowserContext()->IsOffTheRecord());
   EXPECT_FALSE(download_normal->GetBrowserContext()->IsOffTheRecord());
 
-  // Requests to complete the downloads.
-  ui_test_utils::NavigateToURL(
-      browser(), GURL(net::URLRequestSlowDownloadJob::kFinishDownloadUrl));
-
-  // Waits for the completion of downloads.
-  NotificationUpdateObserver download_change_notification_observer;
-  while (download_normal->GetState() != content::DownloadItem::COMPLETE ||
-         download_incognito->GetState() != content::DownloadItem::COMPLETE) {
-    download_change_notification_observer.Wait();
-    download_change_notification_observer.Reset();
-  }
+  // Request to complete the normal download.
+  CompleteTheDownload();
 
   // Confirms the types of download notifications are correct.
+  incognito_notification =
+      incognito_display_service_->GetNotification(notification_id1);
   EXPECT_EQ(message_center::NOTIFICATION_TYPE_BASE_FORMAT,
-            GetNotification(notification_id1)->type());
+            incognito_notification->type());
+  normal_notification = display_service_->GetNotification(notification_id2);
   EXPECT_EQ(message_center::NOTIFICATION_TYPE_BASE_FORMAT,
-            GetNotification(notification_id2)->type());
+            normal_notification->type());
 
   chrome::CloseWindow(incognito_browser());
 }
@@ -1150,7 +837,8 @@
 class MultiProfileDownloadNotificationTest
     : public DownloadNotificationTestBase {
  public:
-  ~MultiProfileDownloadNotificationTest() override {}
+  MultiProfileDownloadNotificationTest() = default;
+  ~MultiProfileDownloadNotificationTest() override = default;
 
   void SetUpCommandLine(base::CommandLine* command_line) override {
     DownloadNotificationTestBase::SetUpCommandLine(command_line);
@@ -1197,6 +885,12 @@
         chromeos::ProfileHelper::GetProfileByUserIdHashForTest(info.hash))
         ->SetAuthenticatedAccountInfo(info.gaia_id, info.email);
   }
+
+  std::unique_ptr<NotificationDisplayServiceTester> display_service1_;
+  std::unique_ptr<NotificationDisplayServiceTester> display_service2_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(MultiProfileDownloadNotificationTest);
 };
 
 IN_PROC_BROWSER_TEST_F(MultiProfileDownloadNotificationTest,
@@ -1216,10 +910,14 @@
   Browser* browser2 = CreateBrowser(profile2);
   EXPECT_NE(browser1, browser2);
 
+  display_service1_ =
+      std::make_unique<NotificationDisplayServiceTester>(profile1);
+  display_service2_ =
+      std::make_unique<NotificationDisplayServiceTester>(profile2);
+
   // First user starts a download.
-  NotificationAddObserver download_start_notification_observer1;
   ui_test_utils::NavigateToURL(browser1, url);
-  download_start_notification_observer1.Wait();
+  WaitForDownloadNotificationForDisplayService(display_service1_.get());
 
   // Confirms that the download is started.
   std::vector<content::DownloadItem*> downloads;
@@ -1228,17 +926,20 @@
   content::DownloadItem* download1 = downloads[0];
 
   // Confirms that a download notification is generated.
-  std::string notification_id_user1 =
-      download_start_notification_observer1.notification_id();
+  auto notifications1 = display_service1_->GetDisplayedNotificationsForType(
+      NotificationHandler::Type::DOWNLOAD);
+  ASSERT_EQ(1u, notifications1.size());
+  std::string notification_id_user1 = notifications1[0].id();
   EXPECT_FALSE(notification_id_user1.empty());
 
   // Second user starts a download.
-  NotificationAddObserver download_start_notification_observer2;
   ui_test_utils::NavigateToURL(browser2, url);
-  download_start_notification_observer2.Wait();
-  std::string notification_id_user2_1 =
-      download_start_notification_observer2.notification_id();
-  EXPECT_FALSE(notification_id_user2_1.empty());
+  WaitForDownloadNotificationForDisplayService(display_service2_.get());
+  auto notifications2 = display_service2_->GetDisplayedNotificationsForType(
+      NotificationHandler::Type::DOWNLOAD);
+  ASSERT_EQ(1u, notifications2.size());
+  std::string notification_id_user2 = notifications2[0].id();
+  EXPECT_FALSE(notification_id_user2.empty());
 
   // Confirms that the second user has only 1 download.
   downloads.clear();
@@ -1246,12 +947,11 @@
   ASSERT_EQ(1u, downloads.size());
 
   // Second user starts another download.
-  NotificationAddObserver download_start_notification_observer3;
   ui_test_utils::NavigateToURL(browser2, url);
-  download_start_notification_observer3.Wait();
-  std::string notification_id_user2_2 =
-      download_start_notification_observer3.notification_id();
-  EXPECT_FALSE(notification_id_user2_2.empty());
+  WaitForDownloadNotificationForDisplayService(display_service2_.get());
+  notifications2 = display_service2_->GetDisplayedNotificationsForType(
+      NotificationHandler::Type::DOWNLOAD);
+  ASSERT_EQ(2u, notifications2.size());
 
   // Confirms that the second user has 2 downloads.
   downloads.clear();
@@ -1272,39 +972,41 @@
   // Confirms the types of download notifications are correct.
   // Normal notification for user1.
   EXPECT_EQ(message_center::NOTIFICATION_TYPE_PROGRESS,
-            GetNotification(notification_id_user1)->type());
-  EXPECT_EQ(-1, GetNotification(notification_id_user1)->progress());
-  // Normal notification for user2.
-  EXPECT_EQ(message_center::NOTIFICATION_TYPE_PROGRESS,
-            GetNotification(notification_id_user2_1)->type());
-  EXPECT_EQ(-1, GetNotification(notification_id_user2_1)->progress());
-  EXPECT_EQ(message_center::NOTIFICATION_TYPE_PROGRESS,
-            GetNotification(notification_id_user2_2)->type());
-  EXPECT_EQ(-1, GetNotification(notification_id_user2_2)->progress());
+            display_service1_->GetNotification(notification_id_user1)->type());
+  EXPECT_EQ(
+      -1,
+      display_service1_->GetNotification(notification_id_user1)->progress());
+  // Normal notifications for user2.
+  notifications2 = display_service2_->GetDisplayedNotificationsForType(
+      NotificationHandler::Type::DOWNLOAD);
+  EXPECT_EQ(2u, notifications2.size());
+  for (const auto& notification : notifications2) {
+    EXPECT_EQ(message_center::NOTIFICATION_TYPE_PROGRESS, notification.type());
+    EXPECT_EQ(-1, notification.progress());
+  }
 
   // Requests to complete the downloads.
-  NotificationUpdateObserver download_change_notification_observer;
+  content::DownloadTestObserverTerminal download_terminal_observer(
+      GetDownloadManager(browser1), 1u /* wait_count */,
+      content::DownloadTestObserver::ON_DANGEROUS_DOWNLOAD_FAIL);
+  content::DownloadTestObserverTerminal download_terminal_observer2(
+      GetDownloadManager(browser2), 2u /* wait_count */,
+      content::DownloadTestObserver::ON_DANGEROUS_DOWNLOAD_FAIL);
   ui_test_utils::NavigateToURL(
-      browser(), GURL(net::URLRequestSlowDownloadJob::kFinishDownloadUrl));
-
-  // Waits for the completion of downloads.
-  while (download1->GetState() != content::DownloadItem::COMPLETE ||
-         download2->GetState() != content::DownloadItem::COMPLETE ||
-         download3->GetState() != content::DownloadItem::COMPLETE) {
-    // Requests again, since sometimes the request may fail.
-    ui_test_utils::NavigateToURL(
-        browser(), GURL(net::URLRequestSlowDownloadJob::kFinishDownloadUrl));
-    download_change_notification_observer.Wait();
-  }
+      browser1, GURL(net::URLRequestSlowDownloadJob::kFinishDownloadUrl));
+  ui_test_utils::NavigateToURL(
+      browser2, GURL(net::URLRequestSlowDownloadJob::kFinishDownloadUrl));
+  download_terminal_observer.WaitForFinished();
+  download_terminal_observer2.WaitForFinished();
 
   // Confirms the types of download notifications are correct.
   EXPECT_EQ(message_center::NOTIFICATION_TYPE_BASE_FORMAT,
-            GetNotification(notification_id_user1)->type());
-  EXPECT_EQ(message_center::NOTIFICATION_TYPE_BASE_FORMAT,
-            GetNotification(notification_id_user2_1)->type());
-  // Normal notifications for user2.
-  EXPECT_EQ(message_center::NOTIFICATION_TYPE_BASE_FORMAT,
-            GetNotification(notification_id_user2_1)->type());
-  EXPECT_EQ(message_center::NOTIFICATION_TYPE_BASE_FORMAT,
-            GetNotification(notification_id_user2_2)->type());
+            display_service1_->GetNotification(notification_id_user1)->type());
+  notifications2 = display_service2_->GetDisplayedNotificationsForType(
+      NotificationHandler::Type::DOWNLOAD);
+  EXPECT_EQ(2u, notifications2.size());
+  for (const auto& notification : notifications2) {
+    EXPECT_EQ(message_center::NOTIFICATION_TYPE_BASE_FORMAT,
+              notification.type());
+  }
 }
diff --git a/chrome/browser/extensions/api/enterprise_platform_keys/enterprise_platform_keys_apitest_nss.cc b/chrome/browser/extensions/api/enterprise_platform_keys/enterprise_platform_keys_apitest_nss.cc
index 79e0b90..5dc16a22 100644
--- a/chrome/browser/extensions/api/enterprise_platform_keys/enterprise_platform_keys_apitest_nss.cc
+++ b/chrome/browser/extensions/api/enterprise_platform_keys/enterprise_platform_keys_apitest_nss.cc
@@ -8,45 +8,19 @@
 #include <memory>
 
 #include "base/macros.h"
-#include "base/path_service.h"
 #include "base/run_loop.h"
 #include "base/strings/stringprintf.h"
-#include "chrome/browser/browser_process.h"
-#include "chrome/browser/chromeos/login/test/https_forwarder.h"
-#include "chrome/browser/chromeos/policy/affiliation_test_helper.h"
-#include "chrome/browser/chromeos/policy/device_policy_cros_browser_test.h"
-#include "chrome/browser/extensions/extension_apitest.h"
+#include "chrome/browser/extensions/api/platform_keys/platform_keys_test_base.h"
 #include "chrome/browser/net/nss_context.h"
 #include "chrome/browser/net/url_request_mock_util.h"
-#include "chrome/common/chrome_paths.h"
-#include "chrome/test/base/ui_test_utils.h"
-#include "chromeos/chromeos_switches.h"
-#include "chromeos/dbus/dbus_thread_manager.h"
-#include "chromeos/dbus/fake_session_manager_client.h"
-#include "chromeos/dbus/session_manager_client.h"
-#include "components/policy/core/browser/browser_policy_connector.h"
-#include "components/policy/core/common/mock_configuration_policy_provider.h"
 #include "components/policy/core/common/policy_map.h"
 #include "components/policy/policy_constants.h"
-#include "components/prefs/pref_service.h"
-#include "components/signin/core/account_id/account_id.h"
-#include "components/user_manager/user_manager.h"
 #include "content/public/common/content_switches.h"
 #include "crypto/nss_util_internal.h"
 #include "crypto/scoped_test_system_nss_key_slot.h"
 #include "extensions/browser/extension_registry.h"
 #include "extensions/browser/test_extension_registry_observer.h"
-#include "extensions/test/result_catcher.h"
-#include "google_apis/gaia/fake_gaia.h"
-#include "google_apis/gaia/gaia_constants.h"
-#include "google_apis/gaia/gaia_switches.h"
-#include "google_apis/gaia/gaia_urls.h"
-#include "net/base/net_errors.h"
 #include "net/cert/nss_cert_database.h"
-#include "net/dns/mock_host_resolver.h"
-#include "net/test/embedded_test_server/embedded_test_server.h"
-#include "net/test/embedded_test_server/http_request.h"
-#include "net/test/embedded_test_server/http_response.h"
 #include "net/test/url_request/url_request_mock_http_job.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -157,182 +131,35 @@
 // its extension ID is well-known and the policy system can push policies for
 // the extension.
 const char kTestExtensionID[] = "aecpbnckhoppanpmefllkdkohionpmig";
-const char kAffiliationID[] = "some-affiliation-id";
-const char kTestUserinfoToken[] = "fake-userinfo-token";
-
-using policy::affiliation_test_helper::kEnterpriseUserEmail;
-using policy::affiliation_test_helper::kEnterpriseUserGaiaId;
-
-enum SystemToken {
-  SYSTEM_TOKEN_EXISTS,
-  SYSTEM_TOKEN_NOT_EXISTS
-};
-
-enum DeviceStatus {
-  DEVICE_STATUS_ENROLLED,
-  DEVICE_STATUS_NOT_ENROLLED
-};
-
-enum UserAffiliation {
-  USER_AFFILIATION_ENROLLED_DOMAIN,
-  USER_AFFILIATION_UNRELATED
-};
 
 struct Params {
-  Params(SystemToken system_token,
-         DeviceStatus device_status,
-         UserAffiliation user_affiliation)
-      : system_token_(system_token),
-        device_status_(device_status),
-        user_affiliation_(user_affiliation) {}
+  Params(PlatformKeysTestBase::SystemTokenStatus system_token_status,
+         PlatformKeysTestBase::EnrollmentStatus enrollment_status,
+         PlatformKeysTestBase::UserStatus user_status)
+      : system_token_status_(system_token_status),
+        enrollment_status_(enrollment_status),
+        user_status_(user_status) {}
 
-  SystemToken system_token_;
-  DeviceStatus device_status_;
-  UserAffiliation user_affiliation_;
+  PlatformKeysTestBase::SystemTokenStatus system_token_status_;
+  PlatformKeysTestBase::EnrollmentStatus enrollment_status_;
+  PlatformKeysTestBase::UserStatus user_status_;
 };
 
 class EnterprisePlatformKeysTest
-    : public ExtensionApiTest,
+    : public PlatformKeysTestBase,
       public ::testing::WithParamInterface<Params> {
  public:
   EnterprisePlatformKeysTest()
-      : account_id_(AccountId::FromUserEmailGaiaId(kEnterpriseUserEmail,
-                                                   kEnterpriseUserGaiaId)) {
-    // Command line should not be tweaked as if user is already logged in.
-    set_chromeos_user_ = false;
-    // We log in without running browser.
-    set_exit_when_last_browser_closes(false);
-  }
-
-  void SetUp() override {
-    base::FilePath test_data_dir;
-    PathService::Get(chrome::DIR_TEST_DATA, &test_data_dir);
-    embedded_test_server()->ServeFilesFromDirectory(test_data_dir);
-
-    embedded_test_server()->RegisterRequestHandler(
-        base::Bind(&FakeGaia::HandleRequest,
-                   base::Unretained(&fake_gaia_)));
-
-    // Don't spin up the IO thread yet since no threads are allowed while
-    // spawning sandbox host process. See crbug.com/322732.
-    ASSERT_TRUE(embedded_test_server()->InitializeAndListen());
-
-    // Start https wrapper here so that the URLs can be pointed at it in
-    // SetUpCommandLine().
-    ASSERT_TRUE(gaia_https_forwarder_.Initialize(
-        GaiaUrls::GetInstance()->gaia_url().host(),
-        embedded_test_server()->base_url()));
-
-    ExtensionApiTest::SetUp();
-  }
+      : PlatformKeysTestBase(GetParam().system_token_status_,
+                             GetParam().enrollment_status_,
+                             GetParam().user_status_) {}
 
   void SetUpCommandLine(base::CommandLine* command_line) override {
-    ExtensionApiTest::SetUpCommandLine(command_line);
+    PlatformKeysTestBase::SetUpCommandLine(command_line);
 
     // Enable the WebCrypto API.
     command_line->AppendSwitch(
         switches::kEnableExperimentalWebPlatformFeatures);
-
-    policy::affiliation_test_helper::
-      AppendCommandLineSwitchesForLoginManager(command_line);
-
-    const GURL gaia_url = gaia_https_forwarder_.GetURLForSSLHost(std::string());
-    command_line->AppendSwitchASCII(::switches::kGaiaUrl, gaia_url.spec());
-    command_line->AppendSwitchASCII(::switches::kLsoUrl, gaia_url.spec());
-    command_line->AppendSwitchASCII(::switches::kGoogleApisUrl,
-                                    gaia_url.spec());
-
-    fake_gaia_.Initialize();
-    fake_gaia_.set_issue_oauth_code_cookie(true);
-  }
-
-  void SetUpInProcessBrowserTestFixture() override {
-    ExtensionApiTest::SetUpInProcessBrowserTestFixture();
-
-    chromeos::FakeSessionManagerClient* fake_session_manager_client =
-        new chromeos::FakeSessionManagerClient;
-    chromeos::DBusThreadManager::GetSetterForTesting()->SetSessionManagerClient(
-        std::unique_ptr<chromeos::SessionManagerClient>(
-            fake_session_manager_client));
-
-    if (GetParam().device_status_ == DEVICE_STATUS_ENROLLED) {
-      std::set<std::string> device_affiliation_ids;
-      device_affiliation_ids.insert(kAffiliationID);
-      policy::affiliation_test_helper::SetDeviceAffiliationID(
-          &device_policy_test_helper_, fake_session_manager_client,
-          device_affiliation_ids);
-    }
-
-
-    if (GetParam().user_affiliation_ == USER_AFFILIATION_ENROLLED_DOMAIN) {
-      std::set<std::string> user_affiliation_ids;
-      user_affiliation_ids.insert(kAffiliationID);
-      policy::UserPolicyBuilder user_policy;
-      policy::affiliation_test_helper::SetUserAffiliationIDs(
-          &user_policy, fake_session_manager_client, account_id_.GetUserEmail(),
-          user_affiliation_ids);
-    }
-
-
-    EXPECT_CALL(policy_provider_, IsInitializationComplete(testing::_))
-        .WillRepeatedly(testing::Return(true));
-    policy_provider_.SetAutoRefresh();
-    policy::BrowserPolicyConnector::SetPolicyProviderForTesting(
-        &policy_provider_);
-  }
-
-  void SetUpOnMainThread() override {
-    host_resolver()->AddRule("*", "127.0.0.1");
-    // Start the accept thread as the sandbox host process has already been
-    // spawned.
-    embedded_test_server()->StartAcceptingConnections();
-
-    FakeGaia::AccessTokenInfo token_info;
-    token_info.scopes.insert(GaiaConstants::kDeviceManagementServiceOAuth);
-    token_info.scopes.insert(GaiaConstants::kOAuthWrapBridgeUserInfoScope);
-    token_info.audience = GaiaUrls::GetInstance()->oauth2_chrome_client_id();
-    token_info.token = kTestUserinfoToken;
-    token_info.email = account_id_.GetUserEmail();
-    fake_gaia_.IssueOAuthToken(
-        policy::affiliation_test_helper::kFakeRefreshToken,
-        token_info);
-
-    // On PRE_ test stage list of users is empty at this point. Then in the body
-    // of PRE_ test kEnterpriseUser is added. Afterwards in the main test flow
-    // after PRE_ test the list of user contains one kEnterpriseUser user.
-    // This user logs in.
-    const base::ListValue* users =
-        g_browser_process->local_state()->GetList("LoggedInUsers");
-
-    // This condition is not held in PRE_ test.
-    if (!users->empty())
-      policy::affiliation_test_helper::LoginUser(account_id_);
-
-    if (GetParam().system_token_ == SYSTEM_TOKEN_EXISTS) {
-      base::RunLoop loop;
-      content::BrowserThread::PostTask(
-          content::BrowserThread::IO, FROM_HERE,
-          base::BindOnce(&EnterprisePlatformKeysTest::SetUpTestSystemSlotOnIO,
-                         base::Unretained(this), loop.QuitClosure()));
-      loop.Run();
-    }
-
-    ExtensionApiTest::SetUpOnMainThread();
-  }
-
-  void TearDownOnMainThread() override {
-    ExtensionApiTest::TearDownOnMainThread();
-
-    if (GetParam().system_token_ == SYSTEM_TOKEN_EXISTS) {
-      base::RunLoop loop;
-      content::BrowserThread::PostTask(
-          content::BrowserThread::IO, FROM_HERE,
-          base::BindOnce(
-              &EnterprisePlatformKeysTest::TearDownTestSystemSlotOnIO,
-              base::Unretained(this), loop.QuitClosure()));
-      loop.Run();
-    }
-    EXPECT_TRUE(embedded_test_server()->ShutdownAndWaitUntilComplete());
   }
 
   void DidGetCertDatabase(const base::Closure& done_callback,
@@ -366,70 +193,27 @@
     // Set the policy and wait until the extension is installed.
     extensions::TestExtensionRegistryObserver observer(
         extensions::ExtensionRegistry::Get(profile()));
-    policy_provider_.UpdateChromePolicy(policy);
+    mock_policy_provider()->UpdateChromePolicy(policy);
     observer.WaitForExtensionWillBeInstalled();
   }
 
-  // Load |page_url| in |browser| and wait for PASSED or FAILED notification.
-  // The functionality of this function is reduced functionality of
-  // RunExtensionSubtest(), but we don't use it here because it requires
-  // function InProcessBrowserTest::browser() to return non-NULL pointer.
-  // Unfortunately it returns the value which is set in constructor and can't be
-  // modified. Because on login flow there is no browser, the function
-  // InProcessBrowserTest::browser() always returns NULL. Besides this we need
-  // only very little functionality from RunExtensionSubtest(). Thus so that
-  // don't make RunExtensionSubtest() to complex we just introduce a new
-  // function.
-  bool TestExtension(Browser* browser, const std::string& page_url) {
-    DCHECK(!page_url.empty()) << "page_url cannot be empty";
-
-    extensions::ResultCatcher catcher;
-    ui_test_utils::NavigateToURL(browser, GURL(page_url));
-
-    if (!catcher.GetNextResult()) {
-      message_ = catcher.message();
-      return false;
-    }
-    return true;
-  }
-
  private:
-  void SetUpTestSystemSlotOnIO(const base::Closure& done_callback) {
-    test_system_slot_.reset(new crypto::ScopedTestSystemNSSKeySlot());
-    ASSERT_TRUE(test_system_slot_->ConstructedSuccessfully());
-
+  void PrepareTestSystemSlotOnIO(
+      crypto::ScopedTestSystemNSSKeySlot* system_slot) override {
     // Import a private key to the system slot.  The Javascript part of this
     // test has a prepared certificate for this key.
     ImportPrivateKeyPKCS8ToSlot(privateKeyPkcs8System,
                                 arraysize(privateKeyPkcs8System),
-                                test_system_slot_->slot());
-
-    content::BrowserThread::PostTask(
-        content::BrowserThread::UI, FROM_HERE, done_callback);
+                                system_slot->slot());
   }
 
-  void TearDownTestSystemSlotOnIO(const base::Closure& done_callback) {
-    test_system_slot_.reset();
-
-    content::BrowserThread::PostTask(
-        content::BrowserThread::UI, FROM_HERE, done_callback);
-  }
-
- protected:
-  const AccountId account_id_;
-
- private:
-  policy::DevicePolicyCrosTestHelper device_policy_test_helper_;
-  std::unique_ptr<crypto::ScopedTestSystemNSSKeySlot> test_system_slot_;
-  policy::MockConfigurationPolicyProvider policy_provider_;
-  FakeGaia fake_gaia_;
-  chromeos::HTTPSForwarder gaia_https_forwarder_;
+  DISALLOW_COPY_AND_ASSIGN(EnterprisePlatformKeysTest);
 };
 
 }  // namespace
 
 IN_PROC_BROWSER_TEST_P(EnterprisePlatformKeysTest, PRE_Basic) {
-  policy::affiliation_test_helper::PreLoginUser(account_id_);
+  RunPreTest();
 }
 
 IN_PROC_BROWSER_TEST_P(EnterprisePlatformKeysTest, Basic) {
@@ -456,34 +240,34 @@
   // Only if the system token exists, and the current user is of the same domain
   // as the device is enrolled to, the system token is available to the
   // extension.
-  if (GetParam().system_token_ == SYSTEM_TOKEN_EXISTS &&
-      GetParam().device_status_ == DEVICE_STATUS_ENROLLED &&
-      GetParam().user_affiliation_ == USER_AFFILIATION_ENROLLED_DOMAIN) {
+  if (system_token_status() == SystemTokenStatus::EXISTS &&
+      enrollment_status() == EnrollmentStatus::ENROLLED &&
+      user_status() == UserStatus::MANAGED_AFFILIATED_DOMAIN) {
     system_token_availability = "systemTokenEnabled";
   }
 
-  ASSERT_TRUE(TestExtension(CreateBrowser(profile()),
+  ASSERT_TRUE(TestExtension(
       base::StringPrintf("chrome-extension://%s/basic.html?%s",
-                         kTestExtensionID,
-                         system_token_availability.c_str())))
+                         kTestExtensionID, system_token_availability.c_str())))
       << message_;
 }
 
 INSTANTIATE_TEST_CASE_P(
     CheckSystemTokenAvailability,
     EnterprisePlatformKeysTest,
-    ::testing::Values(Params(SYSTEM_TOKEN_EXISTS,
-                             DEVICE_STATUS_ENROLLED,
-                             USER_AFFILIATION_ENROLLED_DOMAIN),
-                      Params(SYSTEM_TOKEN_EXISTS,
-                             DEVICE_STATUS_ENROLLED,
-                             USER_AFFILIATION_UNRELATED),
-                      Params(SYSTEM_TOKEN_EXISTS,
-                             DEVICE_STATUS_NOT_ENROLLED,
-                             USER_AFFILIATION_UNRELATED),
-                      Params(SYSTEM_TOKEN_NOT_EXISTS,
-                             DEVICE_STATUS_ENROLLED,
-                             USER_AFFILIATION_ENROLLED_DOMAIN)));
+    ::testing::Values(
+        Params(PlatformKeysTestBase::SystemTokenStatus::EXISTS,
+               PlatformKeysTestBase::EnrollmentStatus::ENROLLED,
+               PlatformKeysTestBase::UserStatus::MANAGED_AFFILIATED_DOMAIN),
+        Params(PlatformKeysTestBase::SystemTokenStatus::EXISTS,
+               PlatformKeysTestBase::EnrollmentStatus::ENROLLED,
+               PlatformKeysTestBase::UserStatus::MANAGED_OTHER_DOMAIN),
+        Params(PlatformKeysTestBase::SystemTokenStatus::EXISTS,
+               PlatformKeysTestBase::EnrollmentStatus::NOT_ENROLLED,
+               PlatformKeysTestBase::UserStatus::MANAGED_OTHER_DOMAIN),
+        Params(PlatformKeysTestBase::SystemTokenStatus::DOES_NOT_EXIST,
+               PlatformKeysTestBase::EnrollmentStatus::ENROLLED,
+               PlatformKeysTestBase::UserStatus::MANAGED_AFFILIATED_DOMAIN)));
 
 class EnterprisePlatformKeysTestNonPolicyInstalledExtension
     : public EnterprisePlatformKeysTest {};
diff --git a/chrome/browser/extensions/api/platform_keys/platform_keys_apitest_nss.cc b/chrome/browser/extensions/api/platform_keys/platform_keys_apitest_nss.cc
index fe1d003..63971e9f 100644
--- a/chrome/browser/extensions/api/platform_keys/platform_keys_apitest_nss.cc
+++ b/chrome/browser/extensions/api/platform_keys/platform_keys_apitest_nss.cc
@@ -9,29 +9,18 @@
 
 #include "base/json/json_writer.h"
 #include "base/macros.h"
-#include "base/memory/ptr_util.h"
 #include "base/run_loop.h"
 #include "base/strings/stringprintf.h"
 #include "chrome/browser/chromeos/platform_keys/platform_keys_service.h"
 #include "chrome/browser/chromeos/platform_keys/platform_keys_service_factory.h"
-#include "chrome/browser/chromeos/policy/device_policy_cros_browser_test.h"
-#include "chrome/browser/chromeos/policy/user_policy_test_helper.h"
-#include "chrome/browser/extensions/extension_apitest.h"
+#include "chrome/browser/extensions/api/platform_keys/platform_keys_test_base.h"
 #include "chrome/browser/net/nss_context.h"
 #include "chrome/browser/policy/profile_policy_connector.h"
 #include "chrome/browser/policy/profile_policy_connector_factory.h"
 #include "chrome/browser/profiles/profile.h"
-#include "chromeos/chromeos_switches.h"
 #include "components/policy/policy_constants.h"
-#include "components/signin/core/account_id/account_id.h"
-#include "components/user_manager/user_names.h"
-#include "content/public/browser/notification_service.h"
-#include "content/public/test/test_utils.h"
 #include "crypto/nss_util_internal.h"
 #include "crypto/scoped_test_system_nss_key_slot.h"
-#include "extensions/browser/extension_registry.h"
-#include "extensions/browser/notification_types.h"
-#include "net/base/net_errors.h"
 #include "net/cert/nss_cert_database.h"
 #include "net/cert/test_root_certs.h"
 #include "net/test/cert_test_util.h"
@@ -39,98 +28,63 @@
 
 namespace {
 
-enum DeviceStatus { DEVICE_STATUS_ENROLLED, DEVICE_STATUS_NOT_ENROLLED };
-
-enum UserStatus {
-  USER_STATUS_MANAGED_AFFILIATED_DOMAIN,
-  USER_STATUS_MANAGED_OTHER_DOMAIN,
-  USER_STATUS_UNMANAGED
-};
-
-class PlatformKeysTest : public ExtensionApiTest {
+class PlatformKeysTest : public PlatformKeysTestBase {
  public:
-  PlatformKeysTest(DeviceStatus device_status,
+  PlatformKeysTest(EnrollmentStatus enrollment_status,
                    UserStatus user_status,
                    bool key_permission_policy)
-      : device_status_(device_status),
-        user_status_(user_status),
-        key_permission_policy_(key_permission_policy) {
-    if (user_status_ != USER_STATUS_UNMANAGED)
-      SetupInitialEmptyPolicy();
-  }
-
-  void SetUpCommandLine(base::CommandLine* command_line) override {
-    ExtensionApiTest::SetUpCommandLine(command_line);
-
-    if (policy_helper_)
-      policy_helper_->UpdateCommandLine(command_line);
-
-    command_line->AppendSwitchASCII(
-        chromeos::switches::kLoginUser,
-        user_manager::StubAccountId().GetUserEmail());
-  }
-
-  void SetUpInProcessBrowserTestFixture() override {
-    ExtensionApiTest::SetUpInProcessBrowserTestFixture();
-
-    if (device_status_ == DEVICE_STATUS_ENROLLED) {
-      device_policy_test_helper_.device_policy()->policy_data().set_username(
-          user_status_ == USER_STATUS_MANAGED_AFFILIATED_DOMAIN
-              ? user_manager::StubAccountId().GetUserEmail()
-              : "someuser@anydomain.com");
-
-      device_policy_test_helper_.device_policy()->Build();
-      device_policy_test_helper_.MarkAsEnterpriseOwned();
-    }
-  }
+      : PlatformKeysTestBase(SystemTokenStatus::EXISTS,
+                             enrollment_status,
+                             user_status),
+        key_permission_policy_(key_permission_policy) {}
 
   void SetUpOnMainThread() override {
-    if (policy_helper_)
-      policy_helper_->WaitForInitialPolicy(browser()->profile());
+    PlatformKeysTestBase::SetUpOnMainThread();
 
-    {
-      base::RunLoop loop;
-      content::BrowserThread::PostTask(
-          content::BrowserThread::IO, FROM_HERE,
-          base::BindOnce(&PlatformKeysTest::SetUpTestSystemSlotOnIO,
-                         base::Unretained(this),
-                         browser()->profile()->GetResourceContext(),
-                         loop.QuitClosure()));
-      loop.Run();
-    }
-
-    ExtensionApiTest::SetUpOnMainThread();
+    if (IsPreTest())
+      return;
 
     {
       base::RunLoop loop;
       GetNSSCertDatabaseForProfile(
-          browser()->profile(),
-          base::Bind(&PlatformKeysTest::SetupTestCerts, base::Unretained(this),
-                     loop.QuitClosure()));
+          profile(),
+          base::BindRepeating(&PlatformKeysTest::SetupTestCerts,
+                              base::Unretained(this), loop.QuitClosure()));
       loop.Run();
     }
 
     base::FilePath extension_path = test_data_dir_.AppendASCII("platform_keys");
     extension_ = LoadExtension(extension_path);
 
-    if (policy_helper_ && key_permission_policy_)
-      SetupKeyPermissionPolicy();
+    if (user_status() != UserStatus::UNMANAGED && key_permission_policy_)
+      SetupKeyPermissionUserPolicy();
   }
 
-  void TearDownOnMainThread() override {
-    ExtensionApiTest::TearDownOnMainThread();
+  void SetupKeyPermissionUserPolicy() {
+    policy::PolicyMap policy;
 
-    base::RunLoop loop;
-    content::BrowserThread::PostTask(
-        content::BrowserThread::IO, FROM_HERE,
-        base::BindOnce(&PlatformKeysTest::TearDownTestSystemSlotOnIO,
-                       base::Unretained(this), loop.QuitClosure()));
-    loop.Run();
+    // Set up the test policy that gives |extension_| the permission to access
+    // corporate keys.
+    std::unique_ptr<base::DictionaryValue> key_permissions_policy =
+        std::make_unique<base::DictionaryValue>();
+    {
+      std::unique_ptr<base::DictionaryValue> cert1_key_permission(
+          new base::DictionaryValue);
+      cert1_key_permission->SetKey("allowCorporateKeyUsage", base::Value(true));
+      key_permissions_policy->SetWithoutPathExpansion(
+          extension_->id(), std::move(cert1_key_permission));
+    }
+
+    policy.Set(policy::key::kKeyPermissions, policy::POLICY_LEVEL_MANDATORY,
+               policy::POLICY_SCOPE_USER, policy::POLICY_SOURCE_CLOUD,
+               std::move(key_permissions_policy), nullptr);
+
+    mock_policy_provider()->UpdateChromePolicy(policy);
   }
 
   chromeos::PlatformKeysService* GetPlatformKeysService() {
     return chromeos::PlatformKeysServiceFactory::GetForBrowserContext(
-        browser()->profile());
+        profile());
   }
 
   bool RunExtensionTest(const std::string& test_suite_name) {
@@ -139,15 +93,16 @@
 
     // Only if the current user is of the same domain as the device is enrolled
     // to, the system token is available to the extension.
-    if (device_status_ == DEVICE_STATUS_ENROLLED &&
-        user_status_ == USER_STATUS_MANAGED_AFFILIATED_DOMAIN) {
+    if (system_token_status() == SystemTokenStatus::EXISTS &&
+        enrollment_status() == EnrollmentStatus::ENROLLED &&
+        user_status() == UserStatus::MANAGED_AFFILIATED_DOMAIN) {
       system_token_availability = "systemTokenEnabled";
     }
 
     GURL url = extension_->GetResourceURL(base::StringPrintf(
         "basic.html?%s#%s", system_token_availability.c_str(),
         test_suite_name.c_str()));
-    return RunExtensionSubtest("", url.spec());
+    return TestExtension(url.spec());
   }
 
   void RegisterClient1AsCorporateKey() {
@@ -173,55 +128,19 @@
   }
 
  protected:
-  const DeviceStatus device_status_;
-  const UserStatus user_status_;
-
   scoped_refptr<net::X509Certificate> client_cert1_;
   scoped_refptr<net::X509Certificate> client_cert2_;
   const extensions::Extension* extension_;
 
  private:
-  void SetupInitialEmptyPolicy() {
-    policy_helper_.reset(new policy::UserPolicyTestHelper(
-        user_manager::StubAccountId().GetUserEmail()));
-    policy_helper_->Init(
-        base::DictionaryValue() /* empty mandatory policy */,
-        base::DictionaryValue() /* empty recommended policy */);
-  }
-
-  void SetupKeyPermissionPolicy() {
-    // Set up the test policy that gives |extension_| the permission to access
-    // corporate keys.
-    base::DictionaryValue key_permissions_policy;
-    {
-      std::unique_ptr<base::DictionaryValue> cert1_key_permission(
-          new base::DictionaryValue);
-      cert1_key_permission->SetKey("allowCorporateKeyUsage", base::Value(true));
-      key_permissions_policy.SetWithoutPathExpansion(
-          extension_->id(), std::move(cert1_key_permission));
-    }
-
-    std::string key_permissions_policy_str;
-    base::JSONWriter::WriteWithOptions(key_permissions_policy,
-                                       base::JSONWriter::OPTIONS_PRETTY_PRINT,
-                                       &key_permissions_policy_str);
-
-    base::DictionaryValue user_policy;
-    user_policy.SetKey(policy::key::kKeyPermissions,
-                       base::Value(key_permissions_policy_str));
-
-    policy_helper_->UpdatePolicy(
-        user_policy, base::DictionaryValue() /* empty recommended policy */,
-        browser()->profile());
-  }
-
   void GotPermissionsForExtension(
       const base::Closure& done_callback,
       std::unique_ptr<chromeos::KeyPermissions::PermissionsForExtension>
           permissions_for_ext) {
     std::string client_cert1_spki =
         chromeos::platform_keys::GetSubjectPublicKeyInfo(client_cert1_);
-    permissions_for_ext->RegisterKeyForCorporateUsage(client_cert1_spki);
+    permissions_for_ext->RegisterKeyForCorporateUsage(
+        client_cert1_spki, {chromeos::KeyPermissions::KeyLocation::kUserSlot});
     done_callback.Run();
   }
 
@@ -242,7 +161,7 @@
     // system wide key slot.
     client_cert2_ = net::ImportClientCertAndKeyFromFile(
         net::GetTestCertsDirectory(), "client_2.pem", "client_2.pk8",
-        test_system_slot_->slot());
+        test_system_slot()->slot());
     ASSERT_TRUE(client_cert2_.get());
   }
 
@@ -255,28 +174,9 @@
         test_data_dir_.AppendASCII("platform_keys").AppendASCII("root.pem"));
   }
 
-  void SetUpTestSystemSlotOnIO(content::ResourceContext* context,
-                               const base::Closure& done_callback) {
-    DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
-    test_system_slot_.reset(new crypto::ScopedTestSystemNSSKeySlot());
-    ASSERT_TRUE(test_system_slot_->ConstructedSuccessfully());
-
-    content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
-                                     done_callback);
-  }
-
-  void TearDownTestSystemSlotOnIO(const base::Closure& done_callback) {
-    DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
-    test_system_slot_.reset();
-
-    content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
-                                     done_callback);
-  }
-
   const bool key_permission_policy_;
-  std::unique_ptr<policy::UserPolicyTestHelper> policy_helper_;
-  policy::DevicePolicyCrosTestHelper device_policy_test_helper_;
-  std::unique_ptr<crypto::ScopedTestSystemNSSKeySlot> test_system_slot_;
+
+  DISALLOW_COPY_AND_ASSIGN(PlatformKeysTest);
 };
 
 class TestSelectDelegate
@@ -319,22 +219,23 @@
   net::CertificateList certs_to_select_;
 };
 
-class UnmanagedPlatformKeysTest
-    : public PlatformKeysTest,
-      public ::testing::WithParamInterface<DeviceStatus> {
+class UnmanagedPlatformKeysTest : public PlatformKeysTest,
+                                  public ::testing::WithParamInterface<
+                                      PlatformKeysTestBase::EnrollmentStatus> {
  public:
   UnmanagedPlatformKeysTest()
       : PlatformKeysTest(GetParam(),
-                         USER_STATUS_UNMANAGED,
+                         UserStatus::UNMANAGED,
                          false /* unused */) {}
 };
 
 struct Params {
-  Params(DeviceStatus device_status, UserStatus user_status)
-      : device_status_(device_status), user_status_(user_status) {}
+  Params(PlatformKeysTestBase::EnrollmentStatus enrollment_status,
+         PlatformKeysTestBase::UserStatus user_status)
+      : enrollment_status_(enrollment_status), user_status_(user_status) {}
 
-  DeviceStatus device_status_;
-  UserStatus user_status_;
+  PlatformKeysTestBase::EnrollmentStatus enrollment_status_;
+  PlatformKeysTestBase::UserStatus user_status_;
 };
 
 class ManagedWithPermissionPlatformKeysTest
@@ -342,7 +243,7 @@
       public ::testing::WithParamInterface<Params> {
  public:
   ManagedWithPermissionPlatformKeysTest()
-      : PlatformKeysTest(GetParam().device_status_,
+      : PlatformKeysTest(GetParam().enrollment_status_,
                          GetParam().user_status_,
                          true /* grant the extension key permission */) {}
 };
@@ -352,13 +253,17 @@
       public ::testing::WithParamInterface<Params> {
  public:
   ManagedWithoutPermissionPlatformKeysTest()
-      : PlatformKeysTest(GetParam().device_status_,
+      : PlatformKeysTest(GetParam().enrollment_status_,
                          GetParam().user_status_,
                          false /* do not grant key permission */) {}
 };
 
 }  // namespace
 
+IN_PROC_BROWSER_TEST_P(UnmanagedPlatformKeysTest, PRE_Basic) {
+  RunPreTest();
+}
+
 // At first interactively selects |client_cert1_| and |client_cert2_| to grant
 // permissions and afterwards runs more basic tests.
 // After the initial two interactive calls, the simulated user does not select
@@ -370,11 +275,15 @@
   certs.push_back(client_cert1_);
 
   GetPlatformKeysService()->SetSelectDelegate(
-      base::WrapUnique(new TestSelectDelegate(certs)));
+      std::make_unique<TestSelectDelegate>(certs));
 
   ASSERT_TRUE(RunExtensionTest("basicTests")) << message_;
 }
 
+IN_PROC_BROWSER_TEST_P(UnmanagedPlatformKeysTest, PRE_Permissions) {
+  RunPreTest();
+}
+
 // On interactive calls, the simulated user always selects |client_cert1_| if
 // matching.
 IN_PROC_BROWSER_TEST_P(UnmanagedPlatformKeysTest, Permissions) {
@@ -382,15 +291,21 @@
   certs.push_back(client_cert1_);
 
   GetPlatformKeysService()->SetSelectDelegate(
-      base::WrapUnique(new TestSelectDelegate(certs)));
+      std::make_unique<TestSelectDelegate>(certs));
 
   ASSERT_TRUE(RunExtensionTest("permissionTests")) << message_;
 }
 
-INSTANTIATE_TEST_CASE_P(Unmanaged,
-                        UnmanagedPlatformKeysTest,
-                        ::testing::Values(DEVICE_STATUS_ENROLLED,
-                                          DEVICE_STATUS_NOT_ENROLLED));
+INSTANTIATE_TEST_CASE_P(
+    Unmanaged,
+    UnmanagedPlatformKeysTest,
+    ::testing::Values(PlatformKeysTestBase::EnrollmentStatus::ENROLLED,
+                      PlatformKeysTestBase::EnrollmentStatus::NOT_ENROLLED));
+
+IN_PROC_BROWSER_TEST_P(ManagedWithoutPermissionPlatformKeysTest,
+                       PRE_UserPermissionsBlocked) {
+  RunPreTest();
+}
 
 IN_PROC_BROWSER_TEST_P(ManagedWithoutPermissionPlatformKeysTest,
                        UserPermissionsBlocked) {
@@ -402,6 +317,11 @@
   ASSERT_TRUE(RunExtensionTest("managedProfile")) << message_;
 }
 
+IN_PROC_BROWSER_TEST_P(ManagedWithoutPermissionPlatformKeysTest,
+                       PRE_CorporateKeyAccessBlocked) {
+  RunPreTest();
+}
+
 // A corporate key must not be useable if there is no policy permitting it.
 IN_PROC_BROWSER_TEST_P(ManagedWithoutPermissionPlatformKeysTest,
                        CorporateKeyAccessBlocked) {
@@ -410,7 +330,7 @@
   // To verify that the user is not prompted for any certificate selection,
   // set up a delegate that fails on any invocation.
   GetPlatformKeysService()->SetSelectDelegate(
-      base::WrapUnique(new TestSelectDelegate(net::CertificateList())));
+      std::make_unique<TestSelectDelegate>(net::CertificateList()));
 
   ASSERT_TRUE(RunExtensionTest("corporateKeyWithoutPermissionTests"))
       << message_;
@@ -420,9 +340,17 @@
     ManagedWithoutPermission,
     ManagedWithoutPermissionPlatformKeysTest,
     ::testing::Values(
-        Params(DEVICE_STATUS_ENROLLED, USER_STATUS_MANAGED_AFFILIATED_DOMAIN),
-        Params(DEVICE_STATUS_ENROLLED, USER_STATUS_MANAGED_OTHER_DOMAIN),
-        Params(DEVICE_STATUS_NOT_ENROLLED, USER_STATUS_MANAGED_OTHER_DOMAIN)));
+        Params(PlatformKeysTestBase::EnrollmentStatus::ENROLLED,
+               PlatformKeysTestBase::UserStatus::MANAGED_AFFILIATED_DOMAIN),
+        Params(PlatformKeysTestBase::EnrollmentStatus::ENROLLED,
+               PlatformKeysTestBase::UserStatus::MANAGED_OTHER_DOMAIN),
+        Params(PlatformKeysTestBase::EnrollmentStatus::NOT_ENROLLED,
+               PlatformKeysTestBase::UserStatus::MANAGED_OTHER_DOMAIN)));
+
+IN_PROC_BROWSER_TEST_P(ManagedWithPermissionPlatformKeysTest,
+                       PRE_PolicyGrantsAccessToCorporateKey) {
+  RunPreTest();
+}
 
 IN_PROC_BROWSER_TEST_P(ManagedWithPermissionPlatformKeysTest,
                        PolicyGrantsAccessToCorporateKey) {
@@ -440,12 +368,25 @@
 }
 
 IN_PROC_BROWSER_TEST_P(ManagedWithPermissionPlatformKeysTest,
+                       PRE_PolicyDoesGrantAccessToNonCorporateKey) {
+  RunPreTest();
+}
+
+IN_PROC_BROWSER_TEST_P(ManagedWithPermissionPlatformKeysTest,
                        PolicyDoesGrantAccessToNonCorporateKey) {
-  // The policy grants access to corporate keys but none are available.
+  // The policy grants access to corporate keys.
   // As the profile is managed, the user must not be able to grant any
-  // certificate permission. Set up a delegate that fails on any invocation.
+  // certificate permission.
+  // If the user is not affilited, no corporate keys are available. Set up a
+  // delegate that fails on any invocation. If the user is affiliated, client_2
+  // on the system token will be avialable for selection, as it is implicitly
+  // corporate.
+  net::CertificateList certs;
+  if (user_status() == UserStatus::MANAGED_AFFILIATED_DOMAIN)
+    certs.push_back(nullptr);
+
   GetPlatformKeysService()->SetSelectDelegate(
-      std::make_unique<TestSelectDelegate>(net::CertificateList()));
+      std::make_unique<TestSelectDelegate>(certs));
 
   ASSERT_TRUE(RunExtensionTest("policyDoesGrantAccessToNonCorporateKey"))
       << message_;
@@ -455,6 +396,9 @@
     ManagedWithPermission,
     ManagedWithPermissionPlatformKeysTest,
     ::testing::Values(
-        Params(DEVICE_STATUS_ENROLLED, USER_STATUS_MANAGED_AFFILIATED_DOMAIN),
-        Params(DEVICE_STATUS_ENROLLED, USER_STATUS_MANAGED_OTHER_DOMAIN),
-        Params(DEVICE_STATUS_NOT_ENROLLED, USER_STATUS_MANAGED_OTHER_DOMAIN)));
+        Params(PlatformKeysTestBase::EnrollmentStatus::ENROLLED,
+               PlatformKeysTestBase::UserStatus::MANAGED_AFFILIATED_DOMAIN),
+        Params(PlatformKeysTestBase::EnrollmentStatus::ENROLLED,
+               PlatformKeysTestBase::UserStatus::MANAGED_OTHER_DOMAIN),
+        Params(PlatformKeysTestBase::EnrollmentStatus::NOT_ENROLLED,
+               PlatformKeysTestBase::UserStatus::MANAGED_OTHER_DOMAIN)));
diff --git a/chrome/browser/extensions/api/platform_keys/platform_keys_test_base.cc b/chrome/browser/extensions/api/platform_keys/platform_keys_test_base.cc
new file mode 100644
index 0000000..0c25f11
--- /dev/null
+++ b/chrome/browser/extensions/api/platform_keys/platform_keys_test_base.cc
@@ -0,0 +1,223 @@
+// 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.
+
+#include "chrome/browser/extensions/api/platform_keys/platform_keys_test_base.h"
+
+#include "base/path_service.h"
+#include "base/run_loop.h"
+#include "chrome/browser/chromeos/policy/affiliation_test_helper.h"
+#include "chrome/browser/policy/profile_policy_connector.h"
+#include "chrome/browser/policy/profile_policy_connector_factory.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/common/chrome_paths.h"
+#include "chrome/test/base/ui_test_utils.h"
+#include "chromeos/dbus/dbus_thread_manager.h"
+#include "chromeos/dbus/fake_session_manager_client.h"
+#include "chromeos/dbus/session_manager_client.h"
+#include "components/policy/core/browser/browser_policy_connector.h"
+#include "components/policy/policy_constants.h"
+#include "content/public/test/test_launcher.h"
+#include "crypto/scoped_test_system_nss_key_slot.h"
+#include "extensions/test/result_catcher.h"
+#include "google_apis/gaia/gaia_constants.h"
+#include "google_apis/gaia/gaia_switches.h"
+#include "google_apis/gaia/gaia_urls.h"
+#include "net/dns/mock_host_resolver.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
+#include "net/test/embedded_test_server/http_request.h"
+#include "net/test/embedded_test_server/http_response.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+const char kAffiliationID[] = "some-affiliation-id";
+const char kTestUserinfoToken[] = "fake-userinfo-token";
+
+using policy::affiliation_test_helper::kEnterpriseUserEmail;
+using policy::affiliation_test_helper::kEnterpriseUserGaiaId;
+
+PlatformKeysTestBase::PlatformKeysTestBase(
+    SystemTokenStatus system_token_status,
+    EnrollmentStatus enrollment_status,
+    UserStatus user_status)
+    : system_token_status_(system_token_status),
+      enrollment_status_(enrollment_status),
+      user_status_(user_status),
+      account_id_(AccountId::FromUserEmailGaiaId(kEnterpriseUserEmail,
+                                                 kEnterpriseUserGaiaId)) {
+  // Command line should not be tweaked as if user is already logged in.
+  set_chromeos_user_ = false;
+  // We log in without running browser.
+  set_exit_when_last_browser_closes(false);
+}
+
+PlatformKeysTestBase::~PlatformKeysTestBase() {}
+
+void PlatformKeysTestBase::SetUp() {
+  base::FilePath test_data_dir;
+  PathService::Get(chrome::DIR_TEST_DATA, &test_data_dir);
+  embedded_test_server()->ServeFilesFromDirectory(test_data_dir);
+
+  embedded_test_server()->RegisterRequestHandler(base::BindRepeating(
+      &FakeGaia::HandleRequest, base::Unretained(&fake_gaia_)));
+
+  // Don't spin up the IO thread yet since no threads are allowed while
+  // spawning sandbox host process. See crbug.com/322732.
+  ASSERT_TRUE(embedded_test_server()->InitializeAndListen());
+
+  // Start https wrapper here so that the URLs can be pointed at it in
+  // SetUpCommandLine().
+  ASSERT_TRUE(gaia_https_forwarder_.Initialize(
+      GaiaUrls::GetInstance()->gaia_url().host(),
+      embedded_test_server()->base_url()));
+
+  ExtensionApiTest::SetUp();
+}
+
+void PlatformKeysTestBase::SetUpCommandLine(base::CommandLine* command_line) {
+  ExtensionApiTest::SetUpCommandLine(command_line);
+
+  policy::affiliation_test_helper::AppendCommandLineSwitchesForLoginManager(
+      command_line);
+
+  const GURL gaia_url = gaia_https_forwarder_.GetURLForSSLHost(std::string());
+  command_line->AppendSwitchASCII(::switches::kGaiaUrl, gaia_url.spec());
+  command_line->AppendSwitchASCII(::switches::kLsoUrl, gaia_url.spec());
+  command_line->AppendSwitchASCII(::switches::kGoogleApisUrl, gaia_url.spec());
+
+  fake_gaia_.Initialize();
+  fake_gaia_.set_issue_oauth_code_cookie(true);
+}
+
+void PlatformKeysTestBase::SetUpInProcessBrowserTestFixture() {
+  ExtensionApiTest::SetUpInProcessBrowserTestFixture();
+
+  chromeos::FakeSessionManagerClient* fake_session_manager_client =
+      new chromeos::FakeSessionManagerClient;
+  chromeos::DBusThreadManager::GetSetterForTesting()->SetSessionManagerClient(
+      std::unique_ptr<chromeos::SessionManagerClient>(
+          fake_session_manager_client));
+
+  if (enrollment_status() == EnrollmentStatus::ENROLLED) {
+    std::set<std::string> device_affiliation_ids;
+    device_affiliation_ids.insert(kAffiliationID);
+    policy::affiliation_test_helper::SetDeviceAffiliationID(
+        &device_policy_test_helper_, fake_session_manager_client,
+        device_affiliation_ids);
+  }
+
+  if (user_status() == UserStatus::MANAGED_AFFILIATED_DOMAIN) {
+    std::set<std::string> user_affiliation_ids;
+    user_affiliation_ids.insert(kAffiliationID);
+    policy::UserPolicyBuilder user_policy;
+    policy::affiliation_test_helper::SetUserAffiliationIDs(
+        &user_policy, fake_session_manager_client, account_id_.GetUserEmail(),
+        user_affiliation_ids);
+  }
+
+  EXPECT_CALL(mock_policy_provider_, IsInitializationComplete(testing::_))
+      .WillRepeatedly(testing::Return(true));
+  mock_policy_provider_.SetAutoRefresh();
+  policy::BrowserPolicyConnector::SetPolicyProviderForTesting(
+      &mock_policy_provider_);
+}
+
+void PlatformKeysTestBase::SetUpOnMainThread() {
+  host_resolver()->AddRule("*", "127.0.0.1");
+  // Start the accept thread as the sandbox host process has already been
+  // spawned.
+  embedded_test_server()->StartAcceptingConnections();
+
+  FakeGaia::AccessTokenInfo token_info;
+  token_info.scopes.insert(GaiaConstants::kDeviceManagementServiceOAuth);
+  token_info.scopes.insert(GaiaConstants::kOAuthWrapBridgeUserInfoScope);
+  token_info.audience = GaiaUrls::GetInstance()->oauth2_chrome_client_id();
+  token_info.token = kTestUserinfoToken;
+  token_info.email = account_id_.GetUserEmail();
+  fake_gaia_.IssueOAuthToken(policy::affiliation_test_helper::kFakeRefreshToken,
+                             token_info);
+
+  // On PRE_ test stage list of users is empty at this point. Then in the body
+  // of PRE_ test kEnterpriseUser is added. Afterwards in the main test flow
+  // after PRE_ test the list of user contains one kEnterpriseUser user.
+  // This user logs in.
+  if (!IsPreTest()) {
+    policy::affiliation_test_helper::LoginUser(account_id_);
+
+    if (user_status() != UserStatus::UNMANAGED) {
+      policy::ProfilePolicyConnector* const connector =
+          policy::ProfilePolicyConnectorFactory::GetForBrowserContext(
+              profile());
+      connector->OverrideIsManagedForTesting(true);
+    }
+  }
+
+  if (system_token_status() == SystemTokenStatus::EXISTS) {
+    base::RunLoop loop;
+    content::BrowserThread::PostTask(
+        content::BrowserThread::IO, FROM_HERE,
+        base::BindOnce(&PlatformKeysTestBase::SetUpTestSystemSlotOnIO,
+                       base::Unretained(this), loop.QuitClosure()));
+    loop.Run();
+  }
+
+  ExtensionApiTest::SetUpOnMainThread();
+}
+
+void PlatformKeysTestBase::TearDownOnMainThread() {
+  ExtensionApiTest::TearDownOnMainThread();
+
+  if (system_token_status() == SystemTokenStatus::EXISTS) {
+    base::RunLoop loop;
+    content::BrowserThread::PostTask(
+        content::BrowserThread::IO, FROM_HERE,
+        base::BindOnce(&PlatformKeysTestBase::TearDownTestSystemSlotOnIO,
+                       base::Unretained(this), loop.QuitClosure()));
+    loop.Run();
+  }
+  EXPECT_TRUE(embedded_test_server()->ShutdownAndWaitUntilComplete());
+}
+
+void PlatformKeysTestBase::PrepareTestSystemSlotOnIO(
+    crypto::ScopedTestSystemNSSKeySlot* system_slot) {}
+
+void PlatformKeysTestBase::RunPreTest() {
+  policy::affiliation_test_helper::PreLoginUser(account_id_);
+}
+
+bool PlatformKeysTestBase::TestExtension(const std::string& page_url) {
+  DCHECK(!page_url.empty()) << "page_url cannot be empty";
+  Browser* const browser = CreateBrowser(profile());
+
+  extensions::ResultCatcher catcher;
+  ui_test_utils::NavigateToURL(browser, GURL(page_url));
+
+  if (!catcher.GetNextResult()) {
+    message_ = catcher.message();
+    return false;
+  }
+  return true;
+}
+
+bool PlatformKeysTestBase::IsPreTest() {
+  return content::IsPreTest();
+}
+
+void PlatformKeysTestBase::SetUpTestSystemSlotOnIO(
+    base::OnceClosure done_callback) {
+  test_system_slot_ = std::make_unique<crypto::ScopedTestSystemNSSKeySlot>();
+  ASSERT_TRUE(test_system_slot_->ConstructedSuccessfully());
+
+  PrepareTestSystemSlotOnIO(test_system_slot_.get());
+
+  content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
+                                   std::move(done_callback));
+}
+
+void PlatformKeysTestBase::TearDownTestSystemSlotOnIO(
+    base::OnceClosure done_callback) {
+  test_system_slot_.reset();
+
+  content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
+                                   std::move(done_callback));
+}
diff --git a/chrome/browser/extensions/api/platform_keys/platform_keys_test_base.h b/chrome/browser/extensions/api/platform_keys/platform_keys_test_base.h
new file mode 100644
index 0000000..01f5ff0
--- /dev/null
+++ b/chrome/browser/extensions/api/platform_keys/platform_keys_test_base.h
@@ -0,0 +1,106 @@
+// 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.
+
+#ifndef CHROME_BROWSER_EXTENSIONS_API_PLATFORM_KEYS_PLATFORM_KEYS_TEST_BASE_H_
+#define CHROME_BROWSER_EXTENSIONS_API_PLATFORM_KEYS_PLATFORM_KEYS_TEST_BASE_H_
+
+#include <memory>
+
+#include "base/macros.h"
+#include "chrome/browser/chromeos/login/test/https_forwarder.h"
+#include "chrome/browser/chromeos/policy/device_policy_cros_browser_test.h"
+#include "chrome/browser/extensions/extension_apitest.h"
+#include "components/policy/core/common/mock_configuration_policy_provider.h"
+#include "components/signin/core/account_id/account_id.h"
+#include "google_apis/gaia/fake_gaia.h"
+
+namespace crypto {
+class ScopedTestSystemNSSKeySlot;
+}
+
+// An ExtensionApiTest which provides additional setup for system token
+// availability, device enrollment status, user affiliation and user policy.
+// Every test case is supposed to have a PRE_ test case which must call
+// PlatformKeysTestBase::RunPreTest.
+class PlatformKeysTestBase : public ExtensionApiTest {
+ public:
+  enum class SystemTokenStatus { EXISTS, DOES_NOT_EXIST };
+
+  enum class EnrollmentStatus { ENROLLED, NOT_ENROLLED };
+
+  enum class UserStatus {
+    UNMANAGED,
+    MANAGED_AFFILIATED_DOMAIN,
+    MANAGED_OTHER_DOMAIN
+  };
+
+  PlatformKeysTestBase(SystemTokenStatus system_token_status,
+                       EnrollmentStatus enrollment_status,
+                       UserStatus user_status);
+  ~PlatformKeysTestBase() override;
+
+ protected:
+  // ExtensionApiTest:
+  void SetUp() override;
+  void SetUpCommandLine(base::CommandLine* command_line) override;
+  void SetUpInProcessBrowserTestFixture() override;
+  void SetUpOnMainThread() override;
+  void TearDownOnMainThread() override;
+
+  // Will be called with the system slot on the IO thread, if a system slot is
+  // being created.  The subclass can override this to perform its own
+  // preparations with the system slot.
+  virtual void PrepareTestSystemSlotOnIO(
+      crypto::ScopedTestSystemNSSKeySlot* system_slot);
+
+  SystemTokenStatus system_token_status() { return system_token_status_; }
+  EnrollmentStatus enrollment_status() { return enrollment_status_; }
+  UserStatus user_status() { return user_status_; }
+
+  policy::MockConfigurationPolicyProvider* mock_policy_provider() {
+    return &mock_policy_provider_;
+  }
+
+  crypto::ScopedTestSystemNSSKeySlot* test_system_slot() {
+    return test_system_slot_.get();
+  }
+
+  // This must be called from the PRE_ test cases.
+  void RunPreTest();
+
+  // Load |page_url| in a new browser in the current profile and wait for PASSED
+  // or FAILED notification. The functionality of this function is reduced
+  // functionality of RunExtensionSubtest(), but we don't use it here because it
+  // requires function InProcessBrowserTest::browser() to return non-NULL
+  // pointer. Unfortunately it returns the value which is set in constructor and
+  // can't be modified. Because on login flow there is no browser, the function
+  // InProcessBrowserTest::browser() always returns NULL. Besides this we need
+  // only very little functionality from RunExtensionSubtest(). Thus so that
+  // don't make RunExtensionSubtest() too complex we just introduce a new
+  // function.
+  bool TestExtension(const std::string& page_url);
+
+  // Returns true if called from a PRE_ test.
+  bool IsPreTest();
+
+ private:
+  void SetUpTestSystemSlotOnIO(base::OnceClosure done_callback);
+  void TearDownTestSystemSlotOnIO(base::OnceClosure done_callback);
+
+  const SystemTokenStatus system_token_status_;
+  const EnrollmentStatus enrollment_status_;
+  const UserStatus user_status_;
+
+  const AccountId account_id_;
+
+  policy::DevicePolicyCrosTestHelper device_policy_test_helper_;
+  std::unique_ptr<crypto::ScopedTestSystemNSSKeySlot> test_system_slot_;
+  policy::MockConfigurationPolicyProvider mock_policy_provider_;
+  FakeGaia fake_gaia_;
+  chromeos::HTTPSForwarder gaia_https_forwarder_;
+
+  DISALLOW_COPY_AND_ASSIGN(PlatformKeysTestBase);
+};
+
+#endif  // CHROME_BROWSER_EXTENSIONS_API_PLATFORM_KEYS_PLATFORM_KEYS_TEST_BASE_H_
diff --git a/chrome/browser/extensions/chrome_app_sorting.cc b/chrome/browser/extensions/chrome_app_sorting.cc
index d3cc43c1..29c891d 100644
--- a/chrome/browser/extensions/chrome_app_sorting.cc
+++ b/chrome/browser/extensions/chrome_app_sorting.cc
@@ -16,8 +16,8 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/extensions/extension_constants.h"
 #include "content/public/browser/notification_service.h"
+#include "extensions/browser/extension_prefs.h"
 #include "extensions/browser/extension_registry.h"
-#include "extensions/browser/extension_scoped_prefs.h"
 #include "extensions/browser/extension_system.h"
 #include "extensions/common/constants.h"
 #include "extensions/common/extension.h"
diff --git a/chrome/browser/extensions/chrome_app_sorting_unittest.cc b/chrome/browser/extensions/chrome_app_sorting_unittest.cc
index 3f561ff..3cc209a 100644
--- a/chrome/browser/extensions/chrome_app_sorting_unittest.cc
+++ b/chrome/browser/extensions/chrome_app_sorting_unittest.cc
@@ -152,28 +152,23 @@
     const char kPrefPageIndexDeprecated[] = "page_index";
 
     // Setup the deprecated preferences.
-    ExtensionScopedPrefs* scoped_prefs =
-        static_cast<ExtensionScopedPrefs*>(prefs());
-    scoped_prefs->UpdateExtensionPref(extension1()->id(),
-                                      kPrefAppLaunchIndexDeprecated,
-                                      std::make_unique<base::Value>(0));
-    scoped_prefs->UpdateExtensionPref(extension1()->id(),
-                                      kPrefPageIndexDeprecated,
-                                      std::make_unique<base::Value>(0));
+    prefs()->UpdateExtensionPref(extension1()->id(),
+                                 kPrefAppLaunchIndexDeprecated,
+                                 std::make_unique<base::Value>(0));
+    prefs()->UpdateExtensionPref(extension1()->id(), kPrefPageIndexDeprecated,
+                                 std::make_unique<base::Value>(0));
 
-    scoped_prefs->UpdateExtensionPref(extension2()->id(),
-                                      kPrefAppLaunchIndexDeprecated,
-                                      std::make_unique<base::Value>(1));
-    scoped_prefs->UpdateExtensionPref(extension2()->id(),
-                                      kPrefPageIndexDeprecated,
-                                      std::make_unique<base::Value>(0));
+    prefs()->UpdateExtensionPref(extension2()->id(),
+                                 kPrefAppLaunchIndexDeprecated,
+                                 std::make_unique<base::Value>(1));
+    prefs()->UpdateExtensionPref(extension2()->id(), kPrefPageIndexDeprecated,
+                                 std::make_unique<base::Value>(0));
 
-    scoped_prefs->UpdateExtensionPref(extension3()->id(),
-                                      kPrefAppLaunchIndexDeprecated,
-                                      std::make_unique<base::Value>(0));
-    scoped_prefs->UpdateExtensionPref(extension3()->id(),
-                                      kPrefPageIndexDeprecated,
-                                      std::make_unique<base::Value>(1));
+    prefs()->UpdateExtensionPref(extension3()->id(),
+                                 kPrefAppLaunchIndexDeprecated,
+                                 std::make_unique<base::Value>(0));
+    prefs()->UpdateExtensionPref(extension3()->id(), kPrefPageIndexDeprecated,
+                                 std::make_unique<base::Value>(1));
 
     // We insert the ids in reverse order so that we have to deal with the
     // element on the 2nd page before the 1st page is seen.
@@ -259,14 +254,11 @@
     const char kPrefPageIndexDeprecated[] = "page_index";
 
     // Setup the deprecated preference.
-    ExtensionScopedPrefs* scoped_prefs =
-        static_cast<ExtensionScopedPrefs*>(prefs());
-    scoped_prefs->UpdateExtensionPref(extension1()->id(),
-                                      kPrefAppLaunchIndexDeprecated,
-                                      std::make_unique<base::Value>(0));
-    scoped_prefs->UpdateExtensionPref(extension1()->id(),
-                                      kPrefPageIndexDeprecated,
-                                      std::make_unique<base::Value>(-1));
+    prefs()->UpdateExtensionPref(extension1()->id(),
+                                 kPrefAppLaunchIndexDeprecated,
+                                 std::make_unique<base::Value>(0));
+    prefs()->UpdateExtensionPref(extension1()->id(), kPrefPageIndexDeprecated,
+                                 std::make_unique<base::Value>(-1));
   }
   void Verify() override {
     // Make sure that the invalid page_index wasn't converted over.
diff --git a/chrome/browser/extensions/crx_installer.cc b/chrome/browser/extensions/crx_installer.cc
index aa4854f9..666b488 100644
--- a/chrome/browser/extensions/crx_installer.cc
+++ b/chrome/browser/extensions/crx_installer.cc
@@ -443,7 +443,7 @@
       // TODO(erikkay) Apply this rule for paid extensions and themes as well.
       if (ManifestURL::UpdatesFromGallery(extension)) {
         return CrxInstallError(l10n_util::GetStringFUTF16(
-            IDS_EXTENSION_DISALLOW_NON_DOWNLOADED_GALLERY_INSTALLS,
+            IDS_EXTENSION_INSTALL_GALLERY_ONLY,
             l10n_util::GetStringUTF16(IDS_EXTENSION_WEB_STORE_TITLE)));
       }
 
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index f82ba49..0444ab0 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -1340,6 +1340,11 @@
 const char kSoftwareRasterizerDescription[] =
     "Fall back to a 3D software rasterizer when the GPU cannot be used.";
 
+const char kSoleIntegrationName[] = "Sole integration";
+const char kSoleIntegrationDescription[] =
+    "Enable Sole integration for browser customization. You must restart "
+    "the browser twice for changes to take effect.";
+
 const char kSoundContentSettingName[] = "Sound content setting";
 const char kSoundContentSettingDescription[] =
     "Enable site-wide muting in content settings and tab strip context menu.";
@@ -2449,11 +2454,6 @@
 const char kArcVpnDescription[] =
     "Allow Android VPN clients to tunnel Chrome traffic.";
 
-const char kAshDisableV1AppBackButtonName[] =
-    "Disable BackButton on V1 app window";
-const char kAshDisableV1AppBackButtonDescription[] =
-    "Enable this flag to disable back button on V1 app window.";
-
 const char kAshEnableUnifiedDesktopName[] = "Unified desktop mode";
 const char kAshEnableUnifiedDesktopDescription[] =
     "Enable unified desktop mode which allows a window to span multiple "
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index 3a16208..bdcd466f 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -823,6 +823,9 @@
 extern const char kSoftwareRasterizerName[];
 extern const char kSoftwareRasterizerDescription[];
 
+extern const char kSoleIntegrationName[];
+extern const char kSoleIntegrationDescription[];
+
 extern const char kSoundContentSettingName[];
 extern const char kSoundContentSettingDescription[];
 
@@ -1511,9 +1514,6 @@
 extern const char kArcVpnName[];
 extern const char kArcVpnDescription[];
 
-extern const char kAshDisableV1AppBackButtonName[];
-extern const char kAshDisableV1AppBackButtonDescription[];
-
 extern const char kAshEnableUnifiedDesktopName[];
 extern const char kAshEnableUnifiedDesktopDescription[];
 
diff --git a/chrome/browser/generic_sensor/sensor_permission_context.cc b/chrome/browser/generic_sensor/sensor_permission_context.cc
index 4e219e7..0fba82a 100644
--- a/chrome/browser/generic_sensor/sensor_permission_context.cc
+++ b/chrome/browser/generic_sensor/sensor_permission_context.cc
@@ -31,7 +31,12 @@
   // able to access sensors (which are provided by generic sensor) in
   // cross-origin iframes. The Generic Sensor API is not allowed in
   // cross-origin iframes and this is enforced by the renderer.
-  return CONTENT_SETTING_ALLOW;
+
+  // Sensors are allowed by default in content_settings_registry.cc.
+  // If cross-origin access check is required, comparison between requesting
+  // and embedding origin must be performed.
+  return PermissionContextBase::GetPermissionStatusInternal(
+      render_frame_host, requesting_origin, embedding_origin);
 }
 
 bool SensorPermissionContext::IsRestrictedToSecureOrigins() const {
diff --git a/chrome/browser/io_thread.cc b/chrome/browser/io_thread.cc
index 7227741..c3d5264 100644
--- a/chrome/browser/io_thread.cc
+++ b/chrome/browser/io_thread.cc
@@ -97,6 +97,7 @@
 #include "net/url_request/url_request_context.h"
 #include "net/url_request/url_request_context_builder.h"
 #include "net/url_request/url_request_context_getter.h"
+#include "services/network/public/cpp/network_switches.h"
 #include "url/url_constants.h"
 
 #if BUILDFLAG(ENABLE_EXTENSIONS)
@@ -190,13 +191,13 @@
   // through a designated test server.
   const base::CommandLine& command_line =
       *base::CommandLine::ForCurrentProcess();
-  if (!command_line.HasSwitch(switches::kHostResolverRules))
+  if (!command_line.HasSwitch(network::switches::kHostResolverRules))
     return global_host_resolver;
 
   auto remapped_resolver = std::make_unique<net::MappedHostResolver>(
       std::move(global_host_resolver));
   remapped_resolver->SetRulesFromString(
-      command_line.GetSwitchValueASCII(switches::kHostResolverRules));
+      command_line.GetSwitchValueASCII(network::switches::kHostResolverRules));
   return std::move(remapped_resolver);
 }
 
diff --git a/chrome/browser/media/media_engagement_preloaded_list.cc b/chrome/browser/media/media_engagement_preloaded_list.cc
index 3fcf426..dde6d951 100644
--- a/chrome/browser/media/media_engagement_preloaded_list.cc
+++ b/chrome/browser/media/media_engagement_preloaded_list.cc
@@ -21,6 +21,12 @@
 const char MediaEngagementPreloadedList::kHistogramLoadResultName[] =
     "Media.Engagement.PreloadedList.LoadResult";
 
+const char MediaEngagementPreloadedList::kHistogramLoadTimeName[] =
+    "Media.Engagement.PreloadedList.LoadTime";
+
+const char MediaEngagementPreloadedList::kHistogramLookupTimeName[] =
+    "Media.Engagement.PreloadedList.LookupTime";
+
 // static
 MediaEngagementPreloadedList* MediaEngagementPreloadedList::GetInstance() {
   CR_DEFINE_STATIC_LOCAL(MediaEngagementPreloadedList, instance, ());
@@ -47,6 +53,7 @@
 }
 
 bool MediaEngagementPreloadedList::LoadFromFile(const base::FilePath& path) {
+  SCOPED_UMA_HISTOGRAM_TIMER(kHistogramLoadTimeName);
   DETACH_FROM_SEQUENCE(sequence_checker_);
 
   // Check the file exists.
@@ -81,6 +88,7 @@
 
 bool MediaEngagementPreloadedList::CheckOriginIsPresent(
     const url::Origin& origin) const {
+  SCOPED_UMA_HISTOGRAM_TIMER(kHistogramLookupTimeName);
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   // Check if we have loaded the data.
diff --git a/chrome/browser/media/media_engagement_preloaded_list.h b/chrome/browser/media/media_engagement_preloaded_list.h
index 7e78ffb..55d31224 100644
--- a/chrome/browser/media/media_engagement_preloaded_list.h
+++ b/chrome/browser/media/media_engagement_preloaded_list.h
@@ -39,6 +39,10 @@
   // Check whether the list we have loaded is empty.
   bool empty() const;
 
+  // The names of the histograms related to timing/perf.
+  static const char kHistogramLoadTimeName[];
+  static const char kHistogramLookupTimeName[];
+
  protected:
   friend class MediaEngagementPreloadedListTest;
 
diff --git a/chrome/browser/media/media_engagement_preloaded_list_unittest.cc b/chrome/browser/media/media_engagement_preloaded_list_unittest.cc
index 95895703..31f0a4f 100644
--- a/chrome/browser/media/media_engagement_preloaded_list_unittest.cc
+++ b/chrome/browser/media/media_engagement_preloaded_list_unittest.cc
@@ -129,6 +129,10 @@
         MediaEngagementPreloadedList::LoadResult::kParseProtoFailed);
   }
 
+  const base::HistogramTester& histogram_tester() const {
+    return histogram_tester_;
+  }
+
  protected:
   void ExpectLoadResult(MediaEngagementPreloadedList::LoadResult result) {
     histogram_tester_.ExpectBucketCount(
@@ -275,3 +279,80 @@
   ExpectCheckResultFoundHttpsOnlyCount(1);
   ExpectCheckResultFoundHttpsButWasHttpOnlyCount(1);
 }
+
+TEST_F(MediaEngagementPreloadedListTest, RecordsLoadTimeOnSuccess) {
+  histogram_tester().ExpectTotalCount(
+      MediaEngagementPreloadedList::kHistogramLoadTimeName, 0);
+
+  ASSERT_TRUE(LoadFromFile(GetFilePathRelativeToModule(kSampleDataPath)));
+  EXPECT_TRUE(IsLoaded());
+  EXPECT_FALSE(IsEmpty());
+
+  histogram_tester().ExpectTotalCount(
+      MediaEngagementPreloadedList::kHistogramLoadTimeName, 1);
+}
+
+TEST_F(MediaEngagementPreloadedListTest, RecordsLoadTimeOnFailure) {
+  histogram_tester().ExpectTotalCount(
+      MediaEngagementPreloadedList::kHistogramLoadTimeName, 0);
+
+  ASSERT_FALSE(LoadFromFile(GetFilePathRelativeToModule(kBadFormatFilePath)));
+  EXPECT_FALSE(IsLoaded());
+  EXPECT_TRUE(IsEmpty());
+
+  histogram_tester().ExpectTotalCount(
+      MediaEngagementPreloadedList::kHistogramLoadTimeName, 1);
+}
+
+TEST_F(MediaEngagementPreloadedListTest, RecordsLoadTimeWhenEmpty) {
+  histogram_tester().ExpectTotalCount(
+      MediaEngagementPreloadedList::kHistogramLoadTimeName, 0);
+
+  ASSERT_TRUE(LoadFromFile(GetFilePathRelativeToModule(kEmptyFilePath)));
+  EXPECT_TRUE(IsLoaded());
+  EXPECT_TRUE(IsEmpty());
+
+  histogram_tester().ExpectTotalCount(
+      MediaEngagementPreloadedList::kHistogramLoadTimeName, 1);
+}
+
+TEST_F(MediaEngagementPreloadedListTest, RecordsLookupTime) {
+  histogram_tester().ExpectTotalCount(
+      MediaEngagementPreloadedList::kHistogramLookupTimeName, 0);
+
+  ASSERT_TRUE(LoadFromFile(GetFilePathRelativeToModule(kSampleDataPath)));
+
+  histogram_tester().ExpectTotalCount(
+      MediaEngagementPreloadedList::kHistogramLookupTimeName, 0);
+
+  {
+    EXPECT_TRUE(CheckOriginIsPresent(GURL("https://example.com")));
+    EXPECT_TRUE(CheckOriginIsPresent(GURL("https://example.org:1234")));
+    EXPECT_TRUE(CheckOriginIsPresent(GURL("https://test--3ya.com")));
+    EXPECT_TRUE(CheckOriginIsPresent(GURL("http://123.123.123.123")));
+
+    histogram_tester().ExpectTotalCount(
+        MediaEngagementPreloadedList::kHistogramLookupTimeName, 4);
+  }
+
+  // Histograms recorded when checking the same values.
+  {
+    EXPECT_TRUE(CheckOriginIsPresent(GURL("https://example.com")));
+    EXPECT_TRUE(CheckOriginIsPresent(GURL("https://example.org:1234")));
+    EXPECT_TRUE(CheckOriginIsPresent(GURL("https://test--3ya.com")));
+    EXPECT_TRUE(CheckOriginIsPresent(GURL("http://123.123.123.123")));
+
+    histogram_tester().ExpectTotalCount(
+        MediaEngagementPreloadedList::kHistogramLookupTimeName, 8);
+  }
+
+  // Histograms recorded when checking values that are not present.
+  {
+    EXPECT_FALSE(CheckOriginIsPresent(GURL("https://example.org")));
+    EXPECT_FALSE(CheckOriginIsPresent(GURL("http://example.com")));
+    EXPECT_FALSE(CheckOriginIsPresent(GURL("http://123.123.123.124")));
+
+    histogram_tester().ExpectTotalCount(
+        MediaEngagementPreloadedList::kHistogramLookupTimeName, 11);
+  }
+}
diff --git a/chrome/browser/net/default_network_context_params.cc b/chrome/browser/net/default_network_context_params.cc
index bb546f2..79235019 100644
--- a/chrome/browser/net/default_network_context_params.cc
+++ b/chrome/browser/net/default_network_context_params.cc
@@ -13,6 +13,7 @@
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/net/chrome_mojo_proxy_resolver_factory.h"
 #include "chrome/common/channel_info.h"
+#include "chrome/common/chrome_content_client.h"
 #include "chrome/common/chrome_switches.h"
 #include "components/policy/core/common/policy_namespace.h"
 #include "components/policy/core/common/policy_service.h"
@@ -30,6 +31,8 @@
   network_context_params->enable_brotli =
       base::FeatureList::IsEnabled(features::kBrotliEncoding);
 
+  network_context_params->user_agent = GetUserAgent();
+
   std::string quic_user_agent_id = chrome::GetChannelString();
   if (!quic_user_agent_id.empty())
     quic_user_agent_id.push_back(' ');
diff --git a/chrome/browser/ntp_snippets/contextual_content_suggestions_service_factory.cc b/chrome/browser/ntp_snippets/contextual_content_suggestions_service_factory.cc
index 7075caa..29defed 100644
--- a/chrome/browser/ntp_snippets/contextual_content_suggestions_service_factory.cc
+++ b/chrome/browser/ntp_snippets/contextual_content_suggestions_service_factory.cc
@@ -9,8 +9,7 @@
 #include "build/build_config.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/search/suggestions/image_decoder_impl.h"
-#include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
-#include "chrome/browser/signin/signin_manager_factory.h"
+#include "chrome/browser/signin/identity_manager_factory.h"
 #include "components/image_fetcher/core/image_decoder.h"
 #include "components/image_fetcher/core/image_fetcher.h"
 #include "components/image_fetcher/core/image_fetcher_impl.h"
@@ -20,8 +19,6 @@
 #include "components/ntp_snippets/remote/cached_image_fetcher.h"
 #include "components/ntp_snippets/remote/remote_suggestions_database.h"
 #include "components/prefs/pref_service.h"
-#include "components/signin/core/browser/profile_oauth2_token_service.h"
-#include "components/signin/core/browser/signin_manager.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/common/service_manager_connection.h"
 #include "services/data_decoder/public/cpp/safe_json_parser.h"
@@ -75,8 +72,7 @@
     : BrowserContextKeyedServiceFactory(
           "ContextualContentSuggestionsService",
           BrowserContextDependencyManager::GetInstance()) {
-  DependsOn(ProfileOAuth2TokenServiceFactory::GetInstance());
-  DependsOn(SigninManagerFactory::GetInstance());
+  DependsOn(IdentityManagerFactory::GetInstance());
 }
 
 ContextualContentSuggestionsServiceFactory::
@@ -92,15 +88,13 @@
   }
 
   PrefService* pref_service = profile->GetPrefs();
-  SigninManagerBase* signin_manager =
-      SigninManagerFactory::GetForProfile(profile);
-  OAuth2TokenService* token_service =
-      ProfileOAuth2TokenServiceFactory::GetForProfile(profile);
+  identity::IdentityManager* identity_manager =
+      IdentityManagerFactory::GetForProfile(profile);
   scoped_refptr<net::URLRequestContextGetter> request_context =
       profile->GetRequestContext();
   auto contextual_suggestions_fetcher =
       base::MakeUnique<ContextualSuggestionsFetcherImpl>(
-          signin_manager, token_service, request_context, pref_service,
+          identity_manager, request_context, pref_service,
           base::Bind(&data_decoder::SafeJsonParser::Parse,
                      content::ServiceManagerConnection::GetForProcess()
                          ->GetConnector()));
diff --git a/chrome/browser/password_manager/password_manager_interactive_uitest.cc b/chrome/browser/password_manager/password_manager_interactive_uitest.cc
index 130d8ca..52d7016 100644
--- a/chrome/browser/password_manager/password_manager_interactive_uitest.cc
+++ b/chrome/browser/password_manager/password_manager_interactive_uitest.cc
@@ -54,9 +54,9 @@
 
 namespace password_manager {
 
-// This is a test fixture, just to enable the kEnableManualSaving feature. The
+// This is a test fixture, just to enable the kManualSaving feature. The
 // fixture should be replaced by PasswordManagerBrowserTestBase once the
-// kEnableManualSaving feature is deleted.
+// kManualSaving feature is deleted.
 class PasswordManagerBrowserTestForManualSaving
     : public PasswordManagerBrowserTestBase {
  public:
@@ -65,7 +65,7 @@
 
   void SetUp() override {
     scoped_feature_list_.InitAndEnableFeature(
-        password_manager::features::kEnableManualSaving);
+        password_manager::features::kManualSaving);
     PasswordManagerBrowserTestBase::SetUp();
   }
 
diff --git a/chrome/browser/policy/policy_prefs_browsertest.cc b/chrome/browser/policy/policy_prefs_browsertest.cc
index 14c8927e..1d2584e5 100644
--- a/chrome/browser/policy/policy_prefs_browsertest.cc
+++ b/chrome/browser/policy/policy_prefs_browsertest.cc
@@ -457,7 +457,8 @@
 
 // Verifies that policies make their corresponding preferences become managed,
 // and that the user can't override that setting.
-IN_PROC_BROWSER_TEST_F(PolicyPrefsTest, PolicyToPrefsMapping) {
+// Failed on all platforms. See crbug.com/803755.
+IN_PROC_BROWSER_TEST_F(PolicyPrefsTest, DISABLED_PolicyToPrefsMapping) {
   Schema chrome_schema = Schema::Wrap(GetChromeSchemaData());
   ASSERT_TRUE(chrome_schema.valid());
   PrefService* local_state = g_browser_process->local_state();
diff --git a/chrome/browser/previews/previews_browsertest.cc b/chrome/browser/previews/previews_browsertest.cc
index 2986755..09b3798 100644
--- a/chrome/browser/previews/previews_browsertest.cc
+++ b/chrome/browser/previews/previews_browsertest.cc
@@ -169,8 +169,16 @@
   EXPECT_FALSE(noscript_css_requested());
 }
 
+// Flaky in all platforms except Android. See crbug.com/803626 for detail.
+#if defined(OS_ANDROID)
+#define MAYBE_NoScriptPreviewsEnabledButNoTransformDirective \
+  NoScriptPreviewsEnabledButNoTransformDirective
+#else
+#define MAYBE_NoScriptPreviewsEnabledButNoTransformDirective \
+  DISABLED_NoScriptPreviewsEnabledButNoTransformDirective
+#endif
 IN_PROC_BROWSER_TEST_F(PreviewsNoScriptBrowserTest,
-                       NoScriptPreviewsEnabledButNoTransformDirective) {
+                       MAYBE_NoScriptPreviewsEnabledButNoTransformDirective) {
   base::HistogramTester histogram_tester;
   ui_test_utils::NavigateToURL(browser(), https_no_transform_url());
 
diff --git a/chrome/browser/previews/previews_infobar_delegate.cc b/chrome/browser/previews/previews_infobar_delegate.cc
index 5412803b..1052f56 100644
--- a/chrome/browser/previews/previews_infobar_delegate.cc
+++ b/chrome/browser/previews/previews_infobar_delegate.cc
@@ -210,7 +210,9 @@
   base::string16 timestamp = GetTimestampText();
   if (timestamp.empty())
     return message_text_;
-  return message_text_ + base::ASCIIToUTF16(" ") + timestamp;
+  // This string concatenation wouldn't fly for l10n, but this is only a hack
+  // for Chromium devs and not expected to ever appear for users.
+  return message_text_ + base::ASCIIToUTF16(" - ") + timestamp;
 #endif
 }
 
diff --git a/chrome/browser/profiles/profile_io_data.cc b/chrome/browser/profiles/profile_io_data.cc
index b80f35f..47f10c48 100644
--- a/chrome/browser/profiles/profile_io_data.cc
+++ b/chrome/browser/profiles/profile_io_data.cc
@@ -127,9 +127,6 @@
 
 #if defined(OS_ANDROID)
 #include "content/public/browser/android/content_protocol_handler.h"
-#else
-#include "chrome/browser/ui/search/new_tab_page_interceptor_service.h"
-#include "chrome/browser/ui/search/new_tab_page_interceptor_service_factory.h"
 #endif  // defined(OS_ANDROID)
 
 #if defined(OS_CHROMEOS)
@@ -453,15 +450,6 @@
   params->protocol_handler_interceptor =
       protocol_handler_registry->CreateJobInterceptorFactory();
 
-#if !defined(OS_ANDROID)
-  NewTabPageInterceptorService* new_tab_interceptor_service =
-      NewTabPageInterceptorServiceFactory::GetForProfile(profile);
-  if (new_tab_interceptor_service) {
-    params->new_tab_page_interceptor =
-        new_tab_interceptor_service->CreateInterceptor();
-  }
-#endif
-
 #if defined(OS_CHROMEOS)
   // Enable client certificates for the Chrome OS sign-in frame, if this feature
   // is not disabled by a flag.
diff --git a/chrome/browser/resources/md_extensions/compiled_resources2.gyp b/chrome/browser/resources/md_extensions/compiled_resources2.gyp
index 20a34daf..7485079 100644
--- a/chrome/browser/resources/md_extensions/compiled_resources2.gyp
+++ b/chrome/browser/resources/md_extensions/compiled_resources2.gyp
@@ -255,6 +255,7 @@
         '<(DEPTH)/third_party/polymer/v1_0/components-chromium/iron-a11y-announcer/compiled_resources2.gyp:iron-a11y-announcer-extracted',
         '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
         '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:i18n_behavior',
+        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:util',
         '<(EXTERNS_GYP):metrics_private',
       ],
       'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'],
diff --git a/chrome/browser/resources/md_extensions/item.html b/chrome/browser/resources/md_extensions/item.html
index 971e243..502310b 100644
--- a/chrome/browser/resources/md_extensions/item.html
+++ b/chrome/browser/resources/md_extensions/item.html
@@ -66,6 +66,8 @@
         display: flex;
         flex-direction: column;
         height: 160px;
+        /* Duration matches --drawer-transition from toolbar.html. */
+        transition: height 300ms cubic-bezier(.25, .1, .25, 1);
         width: var(--extensions-card-width, 400px);
       }
 
diff --git a/chrome/browser/resources/md_extensions/toolbar.html b/chrome/browser/resources/md_extensions/toolbar.html
index 8402419..b2d3b2f 100644
--- a/chrome/browser/resources/md_extensions/toolbar.html
+++ b/chrome/browser/resources/md_extensions/toolbar.html
@@ -7,6 +7,7 @@
 <link rel="import" href="chrome://resources/cr_elements/policy/cr_tooltip_icon.html">
 <link rel="import" href="chrome://resources/html/assert.html">
 <link rel="import" href="chrome://resources/html/cr.html">
+<link rel="import" href="chrome://resources/html/util.html">
 <link rel="import" href="chrome://resources/html/i18n_behavior.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/iron-a11y-announcer/iron-a11y-announcer.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-styles/color.html">
diff --git a/chrome/browser/resources/md_extensions/toolbar.js b/chrome/browser/resources/md_extensions/toolbar.js
index 1ecc19ac..3205f8f4 100644
--- a/chrome/browser/resources/md_extensions/toolbar.js
+++ b/chrome/browser/resources/md_extensions/toolbar.js
@@ -52,10 +52,7 @@
       canLoadUnpacked: Boolean,
 
       /** @private */
-      expanded_: {
-        type: Boolean,
-        value: false,
-      },
+      expanded_: Boolean,
     },
 
     behaviors: [I18nBehavior],
@@ -64,13 +61,6 @@
       role: 'banner',
     },
 
-    /** @override */
-    ready: function() {
-      this.$.devDrawer.addEventListener('transitionend', () => {
-        this.delegate.setProfileInDevMode(this.$['dev-mode'].checked);
-      });
-    },
-
     /**
      * @return {boolean}
      * @private
@@ -79,26 +69,42 @@
       return this.devModeControlledByPolicy || this.isSupervised;
     },
 
-    /** @private */
-    onDevModeToggleChange_: function() {
-      const drawer = this.$.devDrawer;
-      if (drawer.hidden) {
-        drawer.hidden = false;
-        // Requesting the offsetTop will cause a reflow (to account for hidden).
-        /** @suppress {suspiciousCode} */ drawer.offsetTop;
-      }
-      this.expanded_ = !this.expanded_;
-
+    /**
+     * @param {!CustomEvent} e
+     * @private
+     */
+    onDevModeToggleChange_: function(e) {
+      this.delegate.setProfileInDevMode(/** @type {boolean} */ (e.detail));
       chrome.metricsPrivate.recordUserAction(
-          'Options_ToggleDeveloperMode_' +
-          (this.expanded_ ? 'Enabled' : 'Disabled'));
+          'Options_ToggleDeveloperMode_' + (e.detail ? 'Enabled' : 'Disabled'));
     },
 
-    /** @private */
-    onInDevModeChanged_: function() {
-      // Set the initial state.
-      this.expanded_ = this.inDevMode;
-      this.$.devDrawer.hidden = !this.inDevMode;
+    /**
+     * @param {boolean} current
+     * @param {boolean} previous
+     * @private
+     */
+    onInDevModeChanged_: function(current, previous) {
+      const drawer = this.$.devDrawer;
+      if (this.inDevMode) {
+        if (drawer.hidden) {
+          drawer.hidden = false;
+          // Requesting the offsetTop will cause a reflow (to account for
+          // hidden).
+          /** @suppress {suspiciousCode} */ drawer.offsetTop;
+        }
+      } else {
+        if (previous == undefined) {
+          drawer.hidden = true;
+          return;
+        }
+
+        listenOnce(drawer, 'transitionend', e => {
+          if (!this.inDevMode)
+            drawer.hidden = true;
+        });
+      }
+      this.expanded_ = !this.expanded_;
     },
 
     /** @private */
diff --git a/chrome/browser/resources/media_router/elements/route_controls/route_controls.css b/chrome/browser/resources/media_router/elements/route_controls/route_controls.css
index 42b845b..322ee273 100644
--- a/chrome/browser/resources/media_router/elements/route_controls/route_controls.css
+++ b/chrome/browser/resources/media_router/elements/route_controls/route_controls.css
@@ -107,7 +107,6 @@
   font-size: 0.8em;
   margin: 15px 8px 3px 8px;
   vertical-align: middle;
-  white-space: nowrap;
 }
 
 #mirroring-fullscreen-video-dropdown {
diff --git a/chrome/browser/resources/print_preview/previewarea/preview_area.js b/chrome/browser/resources/print_preview/previewarea/preview_area.js
index d1cb9de..a545d6259 100644
--- a/chrome/browser/resources/print_preview/previewarea/preview_area.js
+++ b/chrome/browser/resources/print_preview/previewarea/preview_area.js
@@ -81,7 +81,8 @@
     this.printTicketStore_ = printTicketStore;
 
     /**
-     * Used to contruct the preview generator.
+     * Used to construct the preview generator and to open the GCP learn more
+     * help link.
      * @type {!print_preview.NativeLayer}
      * @private
      */
@@ -213,7 +214,8 @@
         'preview-area-open-system-dialog-button-throbber',
     OVERLAY: 'preview-area-overlay-layer',
     MARGIN_CONTROL: 'margin-control',
-    PREVIEW_AREA: 'preview-area-plugin-wrapper'
+    PREVIEW_AREA: 'preview-area-plugin-wrapper',
+    GCP_ERROR_LEARN_MORE_LINK: 'learn-more-link'
   };
 
   /**
@@ -328,6 +330,9 @@
       this.tracker.add(
           assert(this.openSystemDialogButton_), 'click',
           this.onOpenSystemDialogButtonClick_.bind(this));
+      this.tracker.add(
+          assert(this.gcpErrorLearnMoreLink_), 'click',
+          this.onGcpErrorLearnMoreClick_.bind(this));
 
       const TicketStoreEvent = print_preview.PrintTicketStore.EventType;
       [TicketStoreEvent.INITIALIZE, TicketStoreEvent.CAPABILITIES_CHANGE,
@@ -377,6 +382,7 @@
       print_preview.Component.prototype.exitDocument.call(this);
       this.overlayEl_ = null;
       this.openSystemDialogButton_ = null;
+      this.gcpErrorLearnMoreLink_ = null;
     },
 
     /** @override */
@@ -386,6 +392,8 @@
           PreviewArea.Classes_.OVERLAY)[0];
       this.openSystemDialogButton_ = this.getElement().getElementsByClassName(
           PreviewArea.Classes_.OPEN_SYSTEM_DIALOG_BUTTON)[0];
+      this.gcpErrorLearnMoreLink_ = this.getElement().getElementsByClassName(
+          PreviewArea.Classes_.GCP_ERROR_LEARN_MORE_LINK)[0];
     },
 
     /**
@@ -526,6 +534,17 @@
     },
 
     /**
+     * Called when the learn more link for a cloud destination with an invalid
+     * certificate is clicked. Calls nativeLayer to open a new tab with the help
+     * page.
+     * @private
+     */
+    onGcpErrorLearnMoreClick_: function() {
+      this.nativeLayer_.forceOpenNewTab(
+          loadTimeData.getString('gcpCertificateErrorLearnMoreURL'));
+    },
+
+    /**
      * Called when the print ticket changes. Updates the preview.
      * @private
      */
diff --git a/chrome/browser/resources/print_preview/search/destination_list_item.js b/chrome/browser/resources/print_preview/search/destination_list_item.js
index c6ef0c7..fb30034c 100644
--- a/chrome/browser/resources/print_preview/search/destination_list_item.js
+++ b/chrome/browser/resources/print_preview/search/destination_list_item.js
@@ -72,6 +72,9 @@
       this.tracker.add(
           this.getChildElement('.register-promo-button'), 'click',
           this.onRegisterPromoClicked_.bind(this));
+      this.tracker.add(
+          this.getChildElement('.learn-more-link'), 'click',
+          this.onGcpErrorLearnMoreClick_.bind(this));
     },
 
     /** @return {!print_preview.Destination} */
@@ -324,6 +327,16 @@
     },
 
     /**
+     * Called when the learn more link for an unsupported cloud destination is
+     * clicked. Opens the help page via native layer.
+     * @private
+     */
+    onGcpErrorLearnMoreClick_: function() {
+      print_preview.NativeLayer.getInstance().forceOpenNewTab(
+          loadTimeData.getString('gcpCertificateErrorLearnMoreURL'));
+    },
+
+    /**
      * Handles click and 'Enter' key down events for the extension icon element.
      * It opens extensions page with the extension associated with the
      * destination highlighted.
diff --git a/chrome/browser/resources/settings/icons.html b/chrome/browser/resources/settings/icons.html
index 432ad8e..0eb199f 100644
--- a/chrome/browser/resources/settings/icons.html
+++ b/chrome/browser/resources/settings/icons.html
@@ -100,6 +100,7 @@
       <g id="refresh"><path d="M17.65 6.35C16.2 4.9 14.21 4 12 4c-4.42 0-7.99 3.58-7.99 8s3.57 8 7.99 8c3.73 0 6.84-2.55 7.73-6h-2.08c-.82 2.33-3.04 4-5.65 4-3.31 0-6-2.69-6-6s2.69-6 6-6c1.66 0 3.14.69 4.22 1.78L13 11h7V4l-2.35 2.35z"></path></g>
       <g id="restore"><path d="M13 3c-4.97 0-9 4.03-9 9H1l3.89 3.89.07.14L9 12H6c0-3.87 3.13-7 7-7s7 3.13 7 7-3.13 7-7 7c-1.93 0-3.68-.79-4.94-2.06l-1.42 1.42C8.27 19.99 10.51 21 13 21c4.97 0 9-4.03 9-9s-4.03-9-9-9zm-1 5v5l4.28 2.54.72-1.21-3.5-2.08V8H12z"></path></g>
       <g id="rotate-right"><path d="M15.55 5.55L11 1v3.07C7.06 4.56 4 7.92 4 12s3.05 7.44 7 7.93v-2.02c-2.84-.48-5-2.94-5-5.91s2.16-5.43 5-5.91V10l4.55-4.45zM19.93 11c-.17-1.39-.72-2.73-1.62-3.89l-1.42 1.42c.54.75.88 1.6 1.02 2.47h2.02zM13 17.9v2.02c1.39-.17 2.74-.71 3.9-1.61l-1.44-1.44c-.75.54-1.59.89-2.46 1.03zm3.89-2.42l1.42 1.41c.9-1.16 1.45-2.5 1.62-3.89h-2.02c-.14.87-.48 1.72-1.02 2.48z"></path></g>
+      <g id="sensors"><path d="M10 8.5c-0.8 0-1.5 0.7-1.5 1.5s0.7 1.5 1.5 1.5s1.5-0.7 1.5-1.5S10.8 8.5 10 8.5z M7.6 5.8 C6.2 6.7 5.2 8.2 5.2 10c0 1.8 1 3.4 2.4 4.2l0.8-1.4c-1-0.6-1.6-1.6-1.6-2.8c0-1.2 0.6-2.2 1.6-2.8L7.6 5.8z M14.8 10 c0-1.8-1-3.4-2.4-4.2l-0.8 1.4c0.9 0.6 1.6 1.6 1.6 2.8c0 1.2-0.6 2.2-1.6 2.8l0.8 1.4C13.8 13.4 14.8 11.8 14.8 10z M6 3 c-2.4 1.4-4 4-4 7c0 3 1.6 5.6 4 7l0.8-1.4c-1.9-1.1-3.2-3.2-3.2-5.6c0-2.4 1.3-4.5 3.2-5.6L6 3z M13.2 4.4 c1.9 1.1 3.2 3.2 3.2 5.6c0 2.4-1.3 4.5-3.2 5.6L14 17c2.4-1.4 4-4 4-7c0-3-1.6-5.6-4-7L13.2 4.4z"></path></g>
       <g id="security"><path d="M12 1L3 5v6c0 5.55 3.84 10.74 9 12 5.16-1.26 9-6.45 9-12V5l-9-4zm0 10.99h7c-.53 4.12-3.28 7.79-7 8.94V12H5V6.3l7-3.11v8.8z"></path></g>
 <if expr="chromeos">
       <g id="alert-device-out-of-range" fill="none" fill-rule="evenodd"><path d="M-1-1h20v20H-1z"></path><path fill="#C53929" fill-rule="nonzero" d="M8.167 11.5h1.666v1.667H8.167V11.5zm0-6.667h1.666v5H8.167v-5zM8.992.667C4.392.667.667 4.4.667 9s3.725 8.333 8.325 8.333c4.608 0 8.341-3.733 8.341-8.333S13.6.667 8.992.667zm.008 15A6.665 6.665 0 0 1 2.333 9 6.665 6.665 0 0 1 9 2.333 6.665 6.665 0 0 1 15.667 9 6.665 6.665 0 0 1 9 15.667z"></path></g>
diff --git a/chrome/browser/resources/settings/privacy_page/privacy_page.html b/chrome/browser/resources/settings/privacy_page/privacy_page.html
index 1ba4c86..93b8cd1b 100644
--- a/chrome/browser/resources/settings/privacy_page/privacy_page.html
+++ b/chrome/browser/resources/settings/privacy_page/privacy_page.html
@@ -360,6 +360,22 @@
           </settings-subpage>
         </template>
       </template>
+      <template is="dom-if" if="[[enableSensorsContentSetting_]]"
+          no-search>
+        <template is="dom-if" route-path="/content/sensors" no-search>
+         <settings-subpage page-title="$i18n{siteSettingsSensors}">
+           <category-default-setting
+               toggle-off-label="$i18n{siteSettingsSensorsBlock}"
+               toggle-on-label="$i18n{siteSettingsSensorsAllow}"
+               category="{{ContentSettingsTypes.SENSORS}}">
+           </category-default-setting>
+           <category-setting-exceptions
+               category="{{ContentSettingsTypes.SENSORS}}" read-only-list
+               block-header="$i18n{siteSettingsBlock}">
+           </category-setting-exceptions>
+         </settings-subpage>
+        </template>
+      </template>
       <template is="dom-if" route-path="/content/microphone" no-search>
         <settings-subpage page-title="$i18n{siteSettingsCategoryMicrophone}">
           <media-picker label="$i18n{siteSettingsMicrophoneLabel}" type="mic">
diff --git a/chrome/browser/resources/settings/privacy_page/privacy_page.js b/chrome/browser/resources/settings/privacy_page/privacy_page.js
index e55ac46..0a5ec82 100644
--- a/chrome/browser/resources/settings/privacy_page/privacy_page.js
+++ b/chrome/browser/resources/settings/privacy_page/privacy_page.js
@@ -128,6 +128,15 @@
       }
     },
 
+    /** @private */
+    enableSensorsContentSetting_: {
+      type: Boolean,
+      readOnly: true,
+      value: function() {
+        return loadTimeData.getBoolean('enableSensorsContentSetting');
+      }
+    },
+
     /** @private {!Map<string, string>} */
     focusConfig_: {
       type: Object,
diff --git a/chrome/browser/resources/settings/route.js b/chrome/browser/resources/settings/route.js
index de01fd22..916397d 100644
--- a/chrome/browser/resources/settings/route.js
+++ b/chrome/browser/resources/settings/route.js
@@ -74,6 +74,7 @@
  *   SITE_SETTINGS_IMAGES: (undefined|!settings.Route),
  *   SITE_SETTINGS_JAVASCRIPT: (undefined|!settings.Route),
  *   SITE_SETTINGS_SOUND: (undefined|!settings.Route),
+ *   SITE_SETTINGS_SENSORS: (undefined|!settings.Route),
  *   SITE_SETTINGS_LOCATION: (undefined|!settings.Route),
  *   SITE_SETTINGS_MICROPHONE: (undefined|!settings.Route),
  *   SITE_SETTINGS_MIDI_DEVICES: (undefined|!settings.Route),
@@ -317,6 +318,7 @@
       r.SITE_SETTINGS_IMAGES = r.SITE_SETTINGS.createChild('images');
       r.SITE_SETTINGS_JAVASCRIPT = r.SITE_SETTINGS.createChild('javascript');
       r.SITE_SETTINGS_SOUND = r.SITE_SETTINGS.createChild('sound');
+      r.SITE_SETTINGS_SENSORS = r.SITE_SETTINGS.createChild('sensors');
       r.SITE_SETTINGS_LOCATION = r.SITE_SETTINGS.createChild('location');
       r.SITE_SETTINGS_MICROPHONE = r.SITE_SETTINGS.createChild('microphone');
       r.SITE_SETTINGS_NOTIFICATIONS =
diff --git a/chrome/browser/resources/settings/site_settings/category_default_setting.js b/chrome/browser/resources/settings/site_settings/category_default_setting.js
index 220b76d..9933cca 100644
--- a/chrome/browser/resources/settings/site_settings/category_default_setting.js
+++ b/chrome/browser/resources/settings/site_settings/category_default_setting.js
@@ -97,6 +97,7 @@
       case settings.ContentSettingsTypes.IMAGES:
       case settings.ContentSettingsTypes.JAVASCRIPT:
       case settings.ContentSettingsTypes.SOUND:
+      case settings.ContentSettingsTypes.SENSORS:
       case settings.ContentSettingsTypes.POPUPS:
       case settings.ContentSettingsTypes.PROTOCOL_HANDLERS:
 
diff --git a/chrome/browser/resources/settings/site_settings/constants.js b/chrome/browser/resources/settings/site_settings/constants.js
index c6a690d..a855a17 100644
--- a/chrome/browser/resources/settings/site_settings/constants.js
+++ b/chrome/browser/resources/settings/site_settings/constants.js
@@ -33,6 +33,7 @@
   PROTECTED_CONTENT: 'protectedContent',
   ADS: 'ads',
   CLIPBOARD: 'clipboard',
+  SENSORS: 'sensors',
 };
 
 /**
diff --git a/chrome/browser/resources/settings/site_settings/site_details.html b/chrome/browser/resources/settings/site_settings/site_details.html
index 9a10a9eb..238b118 100644
--- a/chrome/browser/resources/settings/site_settings/site_details.html
+++ b/chrome/browser/resources/settings/site_settings/site_details.html
@@ -149,6 +149,12 @@
           label="$i18n{siteSettingsProtectedContentIdentifiers}">
       </site-details-permission>
 </if>
+    <site-details-permission
+        category="{{ContentSettingsTypes.SENSORS}}"
+        icon="settings:sensors" id="sensors"
+        label="$i18n{siteSettingsSensors}"
+        hidden$="[[!enableSensorsContentSetting_]]">
+    </site-details-permission>
     </div>
 
     <div id="clearAndReset" class="settings-box"
diff --git a/chrome/browser/resources/settings/site_settings/site_details.js b/chrome/browser/resources/settings/site_settings/site_details.js
index 6d4f9c7..45b3afb0 100644
--- a/chrome/browser/resources/settings/site_settings/site_details.js
+++ b/chrome/browser/resources/settings/site_settings/site_details.js
@@ -74,6 +74,15 @@
       },
     },
 
+    /** @private */
+    enableSensorsContentSetting_: {
+      type: Boolean,
+      readOnly: true,
+      value: function() {
+        return loadTimeData.getBoolean('enableSensorsContentSetting');
+      },
+    },
+
     /**
      * The type of storage for the origin.
      * @private
diff --git a/chrome/browser/resources/settings/site_settings_page/site_settings_page.html b/chrome/browser/resources/settings/site_settings_page/site_settings_page.html
index c523b2f8..38a6e68 100644
--- a/chrome/browser/resources/settings/site_settings_page/site_settings_page.html
+++ b/chrome/browser/resources/settings/site_settings_page/site_settings_page.html
@@ -371,6 +371,26 @@
       <button class="subpage-arrow" is="paper-icon-button-light"
           aria-label="$i18n{siteSettingsProtectedContent}"></button>
     </div>
+    <template is="dom-if" if="[[enableSensorsContentSetting_]]">
+      <div id="sensors" class="settings-box two-line"
+          category$="[[ContentSettingsTypes.SENSORS]]"
+          data-route="SITE_SETTINGS_SENSORS" on-tap="onTapNavigate_"
+          actionable>
+        <iron-icon icon="settings:sensors"></iron-icon>
+        <div class="middle">
+          $i18n{siteSettingsSensors}
+          <div class="secondary" id="sensorsSecondary">
+            [[defaultSettingLabel_(
+                default_.sensors,
+                '$i18nPolymer{siteSettingsSensorsAllow}',
+                '$i18nPolymer{siteSettingsSensorsBlock}')]]
+          </div>
+        </div>
+        <button class="subpage-arrow" is="paper-icon-button-light"
+            aria-label="$i18n{siteSettingsSensors}"
+            aria-describedby="sensorsSecondary"></button>
+      </div>
+    </template>
   </template>
   <script src="site_settings_page.js"></script>
 </dom-module>
diff --git a/chrome/browser/resources/settings/site_settings_page/site_settings_page.js b/chrome/browser/resources/settings/site_settings_page/site_settings_page.js
index 0b1ce9dc..5a3b98d 100644
--- a/chrome/browser/resources/settings/site_settings_page/site_settings_page.js
+++ b/chrome/browser/resources/settings/site_settings_page/site_settings_page.js
@@ -67,6 +67,15 @@
       }
     },
 
+    /** @private */
+    enableSensorsContentSetting_: {
+      type: Boolean,
+      readOnly: true,
+      value: function() {
+        return loadTimeData.getBoolean('enableSensorsContentSetting');
+      }
+    },
+
     /** @type {!Map<string, string>} */
     focusConfig: {
       type: Object,
@@ -105,6 +114,7 @@
      [R.SITE_SETTINGS_PDF_DOCUMENTS, 'pdf-documents'],
      [R.SITE_SETTINGS_PROTECTED_CONTENT, 'protected-content'],
      [R.SITE_SETTINGS_CLIPBOARD, 'clipboard'],
+     [R.SITE_SETTINGS_SENSORS, 'sensors'],
     ].forEach(pair => {
       const route = pair[0];
       const id = pair[1];
diff --git a/chrome/browser/signin/account_reconcilor_factory.cc b/chrome/browser/signin/account_reconcilor_factory.cc
index 9092d4a..e7b6195 100644
--- a/chrome/browser/signin/account_reconcilor_factory.cc
+++ b/chrome/browser/signin/account_reconcilor_factory.cc
@@ -71,8 +71,6 @@
     case signin::AccountConsistencyMethod::kDiceFixAuthErrors:
       return std::make_unique<signin::AccountReconcilorDelegate>();
     case signin::AccountConsistencyMethod::kDicePrepareMigration:
-    case signin::AccountConsistencyMethod::
-        kDicePrepareMigrationChromeSyncEndpoint:
     case signin::AccountConsistencyMethod::kDiceMigration:
     case signin::AccountConsistencyMethod::kDice:
 #if BUILDFLAG(ENABLE_DICE_SUPPORT)
diff --git a/chrome/browser/signin/chrome_signin_helper.cc b/chrome/browser/signin/chrome_signin_helper.cc
index bc00330..3fa2dcc2 100644
--- a/chrome/browser/signin/chrome_signin_helper.cc
+++ b/chrome/browser/signin/chrome_signin_helper.cc
@@ -298,7 +298,7 @@
   bool is_sync_signin_tab = false;
   DiceTabHelper* tab_helper = DiceTabHelper::FromWebContents(web_contents);
   if (signin::IsDicePrepareMigrationEnabled() && tab_helper) {
-    is_sync_signin_tab = tab_helper->should_start_sync_after_web_signin();
+    is_sync_signin_tab = true;
     access_point = tab_helper->signin_access_point();
     reason = tab_helper->signin_reason();
   }
diff --git a/chrome/browser/signin/dice_browsertest.cc b/chrome/browser/signin/dice_browsertest.cc
index e3aaaa7d..a0680db 100644
--- a/chrome/browser/signin/dice_browsertest.cc
+++ b/chrome/browser/signin/dice_browsertest.cc
@@ -626,15 +626,6 @@
       : DiceBrowserTestBase(AccountConsistencyMethod::kDicePrepareMigration) {}
 };
 
-class DicePrepareMigrationChromeSynEndpointBrowserTest
-    : public DiceBrowserTestBase {
- public:
-  DicePrepareMigrationChromeSynEndpointBrowserTest()
-      : DiceBrowserTestBase(
-            AccountConsistencyMethod::kDicePrepareMigrationChromeSyncEndpoint) {
-  }
-};
-
 // Checks that signin on Gaia triggers the fetch for a refresh token.
 IN_PROC_BROWSER_TEST_F(DiceBrowserTest, Signin) {
   EXPECT_EQ(0, reconcilor_started_count_);
@@ -892,33 +883,6 @@
   WaitForReconcilorUnblockedCount(0);
 }
 
-// Checks that signin on Gaia triggers the fetch for a refresh token.
-IN_PROC_BROWSER_TEST_F(DicePrepareMigrationBrowserTest, Signin) {
-  EXPECT_EQ(0, reconcilor_started_count_);
-
-  // Navigate to Gaia and sign in.
-  NavigateToURL(kSigninURL);
-
-  // Check that the Dice request header was sent, with no signout confirmation.
-  std::string client_id = GaiaUrls::GetInstance()->oauth2_chrome_client_id();
-  EXPECT_EQ(
-      base::StringPrintf("version=%s,client_id=%s,signin_mode=all_accounts,"
-                         "signout_mode=no_confirmation",
-                         signin::kDiceProtocolVersion, client_id.c_str()),
-      dice_request_header_);
-
-  // Check that the token was requested and added to the token service.
-  SendRefreshTokenResponse();
-  EXPECT_TRUE(GetTokenService()->RefreshTokenIsAvailable(GetMainAccountID()));
-  // Sync should not be enabled.
-  EXPECT_TRUE(GetSigninManager()->GetAuthenticatedAccountId().empty());
-  EXPECT_TRUE(GetSigninManager()->GetAccountIdForAuthInProgress().empty());
-
-  EXPECT_EQ(1, reconcilor_blocked_count_);
-  WaitForReconcilorUnblockedCount(1);
-  EXPECT_EQ(1, reconcilor_started_count_);
-}
-
 IN_PROC_BROWSER_TEST_F(DicePrepareMigrationBrowserTest, Signout) {
   // Start from a signed-in state.
   SetupSignedInAccounts();
@@ -941,8 +905,7 @@
 
 // Tests that Sync is enabled if the ENABLE_SYNC response is received after the
 // refresh token.
-IN_PROC_BROWSER_TEST_F(DicePrepareMigrationChromeSynEndpointBrowserTest,
-                       EnableSyncAfterToken) {
+IN_PROC_BROWSER_TEST_F(DicePrepareMigrationBrowserTest, EnableSyncAfterToken) {
   EXPECT_EQ(0, reconcilor_started_count_);
 
   // Signin using the Chrome Sync endpoint.
@@ -955,6 +918,9 @@
   SendRefreshTokenResponse();
   EXPECT_TRUE(GetTokenService()->RefreshTokenIsAvailable(GetMainAccountID()));
 
+  // Receive ENABLE_SYNC.
+  SendEnableSyncResponse();
+
   // Check that the Dice request header was sent, with no signout confirmation.
   std::string client_id = GaiaUrls::GetInstance()->oauth2_chrome_client_id();
   EXPECT_EQ(
@@ -963,9 +929,6 @@
                          signin::kDiceProtocolVersion, client_id.c_str()),
       dice_request_header_);
 
-  // Receive ENABLE_SYNC.
-  SendEnableSyncResponse();
-
   WaitForSigninSucceeded();
   EXPECT_EQ(GetMainAccountID(),
             GetSigninManager()->GetAuthenticatedAccountId());
@@ -986,8 +949,7 @@
 
 // Tests that Sync is enabled if the ENABLE_SYNC response is received before the
 // refresh token.
-IN_PROC_BROWSER_TEST_F(DicePrepareMigrationChromeSynEndpointBrowserTest,
-                       EnableSyncBeforeToken) {
+IN_PROC_BROWSER_TEST_F(DicePrepareMigrationBrowserTest, EnableSyncBeforeToken) {
   EXPECT_EQ(0, reconcilor_started_count_);
 
   // Signin using the Chrome Sync endpoint.
@@ -1002,6 +964,11 @@
       https_server_.GetURL(kEnableSyncURL),
       content::NotificationService::AllSources());
 
+  // Receive token.
+  EXPECT_FALSE(GetTokenService()->RefreshTokenIsAvailable(GetMainAccountID()));
+  SendRefreshTokenResponse();
+  EXPECT_TRUE(GetTokenService()->RefreshTokenIsAvailable(GetMainAccountID()));
+
   // Check that the Dice request header was sent, with no signout confirmation.
   std::string client_id = GaiaUrls::GetInstance()->oauth2_chrome_client_id();
   EXPECT_EQ(
@@ -1010,11 +977,6 @@
                          signin::kDiceProtocolVersion, client_id.c_str()),
       dice_request_header_);
 
-  // Receive token.
-  EXPECT_FALSE(GetTokenService()->RefreshTokenIsAvailable(GetMainAccountID()));
-  SendRefreshTokenResponse();
-  EXPECT_TRUE(GetTokenService()->RefreshTokenIsAvailable(GetMainAccountID()));
-
   WaitForSigninSucceeded();
   EXPECT_EQ(GetMainAccountID(),
             GetSigninManager()->GetAuthenticatedAccountId());
diff --git a/chrome/browser/signin/dice_response_handler.cc b/chrome/browser/signin/dice_response_handler.cc
index 5cb3d61..7799ebf2 100644
--- a/chrome/browser/signin/dice_response_handler.cc
+++ b/chrome/browser/signin/dice_response_handler.cc
@@ -148,13 +148,9 @@
       dice_response_handler_(dice_response_handler),
       timeout_closure_(
           base::Bind(&DiceResponseHandler::DiceTokenFetcher::OnTimeout,
-                     base::Unretained(this))) {
+                     base::Unretained(this))),
+      should_enable_sync_(false) {
   DCHECK(dice_response_handler_);
-  // When DICE migration is enabled, Chrome is not using the Gaia chrome sync
-  // endpoint when the user is signing in to Chrome. So the delegate must be
-  // asked to start syncing as soon as the refresh token is received.
-  should_enable_sync_ = signin::GetAccountConsistencyMethod() ==
-                        signin::AccountConsistencyMethod::kDicePrepareMigration;
   if (signin::IsDicePrepareMigrationEnabled()) {
     account_reconcilor_lock_ =
         base::MakeUnique<AccountReconcilor::Lock>(account_reconcilor);
diff --git a/chrome/browser/signin/dice_response_handler_unittest.cc b/chrome/browser/signin/dice_response_handler_unittest.cc
index 101b144..5db318d1 100644
--- a/chrome/browser/signin/dice_response_handler_unittest.cc
+++ b/chrome/browser/signin/dice_response_handler_unittest.cc
@@ -438,29 +438,6 @@
   EXPECT_EQ(account_id, enable_sync_account_id_);
 }
 
-// Checks that the delegate is always called to enable sync as soon as the
-// refresh token is fetched when prepare DICE migration is enabled.
-TEST_F(DiceResponseHandlerTest, SigninEnableSyncAlwaysForPrepareDiceMigration) {
-  signin::ScopedAccountConsistencyDicePrepareMigration scoped_dice;
-  DiceResponseParams dice_params = MakeDiceParams(DiceAction::SIGNIN);
-  const auto& account_info = dice_params.signin_info->account_info;
-  std::string account_id = account_tracker_service_.PickAccountIdForAccount(
-      account_info.gaia_id, account_info.email);
-  ASSERT_FALSE(token_service_.RefreshTokenIsAvailable(account_id));
-  dice_response_handler_->ProcessDiceHeader(
-      dice_params, std::make_unique<TestProcessDiceHeaderDelegate>(this));
-  // Check that a GaiaAuthFetcher has been created.
-  ASSERT_THAT(signin_client_.consumer_, testing::NotNull());
-  // Simulate GaiaAuthFetcher success.
-  signin_client_.consumer_->OnClientOAuthSuccess(
-      GaiaAuthConsumer::ClientOAuthResult("refresh_token", "access_token", 10,
-                                          false /* is_child_account */));
-  // Check that the token has been inserted in the token service.
-  EXPECT_TRUE(token_service_.RefreshTokenIsAvailable(account_id));
-  // Check that delegate was not called to enable sync.
-  EXPECT_EQ(account_id, enable_sync_account_id_);
-}
-
 TEST_F(DiceResponseHandlerTest, Timeout) {
   signin::ScopedAccountConsistencyDice scoped_dice;
   DiceResponseParams dice_params = MakeDiceParams(DiceAction::SIGNIN);
diff --git a/chrome/browser/signin/dice_tab_helper.cc b/chrome/browser/signin/dice_tab_helper.cc
index 5897268..ea63480 100644
--- a/chrome/browser/signin/dice_tab_helper.cc
+++ b/chrome/browser/signin/dice_tab_helper.cc
@@ -25,7 +25,6 @@
     signin_metrics::Reason reason) {
   signin_access_point_ = access_point;
   signin_reason_ = reason;
-  should_start_sync_after_web_signin_ = true;
   did_finish_loading_signin_page_ = false;
 
   if (signin_reason_ == signin_metrics::Reason::REASON_SIGNIN_PRIMARY_ACCOUNT) {
@@ -35,36 +34,9 @@
   }
 }
 
-void DiceTabHelper::DidStartNavigation(
-    content::NavigationHandle* navigation_handle) {
-  if (signin::GetAccountConsistencyMethod() !=
-      signin::AccountConsistencyMethod::kDicePrepareMigration) {
-    // Chrome relies on a Gaia signal to enable Chrome sync for all DICE methods
-    // different than prepare migration.
-    return;
-  }
-
-  if (!should_start_sync_after_web_signin_)
-    return;
-
-  if (!navigation_handle->IsInMainFrame()) {
-    VLOG(1) << "Ignore subframe navigation to " << navigation_handle->GetURL();
-    return;
-  }
-  if (navigation_handle->GetURL().GetOrigin() !=
-      GaiaUrls::GetInstance()->gaia_url()) {
-    VLOG(1) << "Avoid starting sync after a user navigation to "
-            << navigation_handle->GetURL()
-            << " which is outside of Gaia domain ("
-            << GaiaUrls::GetInstance()->gaia_url() << ")";
-    should_start_sync_after_web_signin_ = false;
-    return;
-  }
-}
-
 void DiceTabHelper::DidFinishLoad(content::RenderFrameHost* render_frame_host,
                                   const GURL& validated_url) {
-  if (!should_start_sync_after_web_signin_ || did_finish_loading_signin_page_)
+  if (did_finish_loading_signin_page_)
     return;
 
   if (validated_url.GetOrigin() == GaiaUrls::GetInstance()->gaia_url()) {
diff --git a/chrome/browser/signin/dice_tab_helper.h b/chrome/browser/signin/dice_tab_helper.h
index c336b0cf..a71a851 100644
--- a/chrome/browser/signin/dice_tab_helper.h
+++ b/chrome/browser/signin/dice_tab_helper.h
@@ -26,19 +26,12 @@
 
   signin_metrics::Reason signin_reason() { return signin_reason_; }
 
-  // Returns true if sync should start after a Google web-signin flow.
-  bool should_start_sync_after_web_signin() {
-    return should_start_sync_after_web_signin_;
-  }
-
   // Initializes the DiceTabHelper for a new signin flow. Must be called once
   // per signin flow happening in the tab.
   void InitializeSigninFlow(signin_metrics::AccessPoint access_point,
                             signin_metrics::Reason reason);
 
   // content::WebContentsObserver:
-  void DidStartNavigation(
-      content::NavigationHandle* navigation_handle) override;
   void DidFinishLoad(content::RenderFrameHost* render_frame_host,
                      const GURL& validated_url) override;
 
@@ -50,7 +43,6 @@
       signin_metrics::AccessPoint::ACCESS_POINT_UNKNOWN;
   signin_metrics::Reason signin_reason_ =
       signin_metrics::Reason::REASON_UNKNOWN_REASON;
-  bool should_start_sync_after_web_signin_ = true;
   bool did_finish_loading_signin_page_ = false;
 
   DISALLOW_COPY_AND_ASSIGN(DiceTabHelper);
diff --git a/chrome/browser/signin/dice_tab_helper_unittest.cc b/chrome/browser/signin/dice_tab_helper_unittest.cc
index a6b01e97..824121a 100644
--- a/chrome/browser/signin/dice_tab_helper_unittest.cc
+++ b/chrome/browser/signin/dice_tab_helper_unittest.cc
@@ -27,7 +27,6 @@
             dice_tab_helper->signin_access_point());
   EXPECT_EQ(signin_metrics::Reason::REASON_UNKNOWN_REASON,
             dice_tab_helper->signin_reason());
-  EXPECT_TRUE(dice_tab_helper->should_start_sync_after_web_signin());
 
   // Initialize the signin flow.
   signin_metrics::AccessPoint access_point =
diff --git a/chrome/browser/signin/signin_promo.cc b/chrome/browser/signin/signin_promo.cc
index c9c68e7..7b933749 100644
--- a/chrome/browser/signin/signin_promo.cc
+++ b/chrome/browser/signin/signin_promo.cc
@@ -275,17 +275,10 @@
 }
 
 GURL GetSigninURLForDice(Profile* profile, const std::string& email) {
-  GURL url;
-  if (signin::GetAccountConsistencyMethod() ==
-      signin::AccountConsistencyMethod::kDicePrepareMigration) {
-    // Add account does not support an email hint, so the email will not be
-    // autofilled when the Dice prepare migration is enabled.
-    url = GaiaUrls::GetInstance()->add_account_url();
-  } else {
-    url = GaiaUrls::GetInstance()->signin_chrome_sync_dice();
-    if (!email.empty())
-      url = net::AppendQueryParameter(url, "email_hint", email);
-  }
+  DCHECK(signin::IsDicePrepareMigrationEnabled());
+  GURL url = GaiaUrls::GetInstance()->signin_chrome_sync_dice();
+  if (!email.empty())
+    url = net::AppendQueryParameter(url, "email_hint", email);
   // Pass www.gooogle.com as the continue URL as otherwise Gaia navigates to
   // myaccount which may be very confusing for the user.
   return net::AppendQueryParameter(
diff --git a/chrome/browser/supervised_user/supervised_user_browsertest.cc b/chrome/browser/supervised_user/supervised_user_browsertest.cc
index e9aad6d4..603e7e1 100644
--- a/chrome/browser/supervised_user/supervised_user_browsertest.cc
+++ b/chrome/browser/supervised_user/supervised_user_browsertest.cc
@@ -40,6 +40,7 @@
 #include "content/public/test/browser_test_utils.h"
 #include "content/public/test/test_utils.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
+#include "services/network/public/cpp/network_switches.h"
 #include "testing/gmock/include/gmock/gmock.h"
 
 using content::InterstitialPage;
@@ -121,10 +122,10 @@
     // Enable the test server and remap all URLs to it.
     ASSERT_TRUE(embedded_test_server()->Start());
     std::string host_port = embedded_test_server()->host_port_pair().ToString();
-    command_line->AppendSwitchASCII(switches::kHostResolverRules,
-        "MAP *.example.com " + host_port + "," +
-        "MAP *.new-example.com " + host_port + "," +
-        "MAP *.a.com " + host_port);
+    command_line->AppendSwitchASCII(network::switches::kHostResolverRules,
+                                    "MAP *.example.com " + host_port + "," +
+                                        "MAP *.new-example.com " + host_port +
+                                        "," + "MAP *.a.com " + host_port);
 
     command_line->AppendSwitchASCII(switches::kSupervisedUserId, "asdf");
   }
diff --git a/chrome/browser/sync/sync_ui_util.cc b/chrome/browser/sync/sync_ui_util.cc
index 761e1dd..757f98fc 100644
--- a/chrome/browser/sync/sync_ui_util.cc
+++ b/chrome/browser/sync/sync_ui_util.cc
@@ -345,46 +345,6 @@
   return result_type;
 }
 
-// Returns the status info for use on the new tab page, where we want slightly
-// different information than in the settings panel.
-MessageType GetStatusInfoForNewTabPage(Profile* profile,
-                                       ProfileSyncService* service,
-                                       const SigninManagerBase& signin,
-                                       base::string16* status_label,
-                                       base::string16* link_label) {
-  DCHECK(status_label);
-  DCHECK(link_label);
-
-  if (service->IsFirstSetupComplete() && service->IsPassphraseRequired()) {
-    if (service->passphrase_required_reason() == syncer::REASON_ENCRYPTION) {
-      // First machine migrating to passwords.  Show as a promotion.
-      if (status_label && link_label) {
-        status_label->assign(
-            l10n_util::GetStringFUTF16(
-                IDS_SYNC_NTP_PASSWORD_PROMO,
-                l10n_util::GetStringUTF16(IDS_PRODUCT_NAME)));
-        link_label->assign(
-            l10n_util::GetStringUTF16(IDS_SYNC_NTP_PASSWORD_ENABLE));
-      }
-      return SYNC_PROMO;
-    } else {
-      // NOT first machine.
-      // Show a link and present as an error ("needs attention").
-      if (status_label && link_label) {
-        status_label->assign(base::string16());
-        link_label->assign(
-            l10n_util::GetStringUTF16(IDS_SYNC_CONFIGURE_ENCRYPTION));
-      }
-      return SYNC_ERROR;
-    }
-  }
-
-  // Fallback to default.
-  ActionType action_type = NO_ACTION;
-  return GetStatusInfo(profile, service, signin, WITH_HTML, status_label,
-                       link_label, &action_type);
-}
-
 }  // namespace
 
 MessageType GetStatusLabels(Profile* profile,
@@ -400,17 +360,6 @@
                                      status_label, link_label, action_type);
 }
 
-MessageType GetStatusLabelsForNewTabPage(Profile* profile,
-                                         ProfileSyncService* service,
-                                         const SigninManagerBase& signin,
-                                         base::string16* status_label,
-                                         base::string16* link_label) {
-  DCHECK(status_label);
-  DCHECK(link_label);
-  return sync_ui_util::GetStatusInfoForNewTabPage(profile, service, signin,
-                                                  status_label, link_label);
-}
-
 #if !defined(OS_CHROMEOS)
 AvatarSyncErrorType GetMessagesForAvatarSyncError(
     Profile* profile,
diff --git a/chrome/browser/sync/sync_ui_util.h b/chrome/browser/sync/sync_ui_util.h
index a416fa4c..101e5a7 100644
--- a/chrome/browser/sync/sync_ui_util.h
+++ b/chrome/browser/sync/sync_ui_util.h
@@ -68,15 +68,6 @@
                             base::string16* link_label,
                             ActionType* action_type);
 
-// Same as above but for use specifically on the New Tab Page.
-// |status_label| may contain an HTML-formatted link.
-MessageType GetStatusLabelsForNewTabPage(
-    Profile* profile,
-    browser_sync::ProfileSyncService* service,
-    const SigninManagerBase& signin,
-    base::string16* status_label,
-    base::string16* link_label);
-
 #if !defined(OS_CHROMEOS)
 // Gets the error message and button label for the sync errors that should be
 // exposed to the user through the titlebar avatar button.
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 1a43eba..f8cdf4f 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -855,10 +855,8 @@
       "scoped_tabbed_browser_displayer.h",
       "search/instant_controller.cc",
       "search/instant_controller.h",
-      "search/new_tab_page_interceptor_service.cc",
-      "search/new_tab_page_interceptor_service.h",
-      "search/new_tab_page_interceptor_service_factory.cc",
-      "search/new_tab_page_interceptor_service_factory.h",
+      "search/new_tab_page_navigation_throttle.cc",
+      "search/new_tab_page_navigation_throttle.h",
       "search/ntp_user_data_logger.cc",
       "search/ntp_user_data_logger.h",
       "search/search_ipc_router.cc",
@@ -1167,6 +1165,7 @@
       "//components/zoom",
       "//device/bluetooth",
       "//mash/public/interfaces",
+      "//services/device/public/cpp:device_features",
       "//services/device/public/interfaces",
       "//services/metrics/public/cpp:metrics_cpp",
       "//third_party/libaddressinput",
@@ -1553,6 +1552,7 @@
       "//components/session_manager/core",
       "//components/user_manager",
       "//services/data_decoder/public/cpp",
+      "//services/device/public/cpp:device_features",
       "//services/device/public/interfaces",
       "//services/ui/public/cpp",
       "//services/ui/public/interfaces",
@@ -3403,9 +3403,6 @@
       "app_list/search/webstore/webstore_provider.h",
       "app_list/search/webstore/webstore_result.cc",
       "app_list/search/webstore/webstore_result.h",
-      "app_list/speech_auth_helper.cc",
-      "app_list/speech_auth_helper.h",
-      "app_list/start_page_observer.h",
       "app_list/start_page_service.cc",
       "app_list/start_page_service.h",
       "app_list/start_page_service_factory.cc",
diff --git a/chrome/browser/ui/app_list/app_list_model_updater.h b/chrome/browser/ui/app_list/app_list_model_updater.h
index 479b7d1..ce504f32 100644
--- a/chrome/browser/ui/app_list/app_list_model_updater.h
+++ b/chrome/browser/ui/app_list/app_list_model_updater.h
@@ -13,7 +13,6 @@
 #include "ash/app_list/model/app_list_folder_item.h"
 #include "ash/app_list/model/app_list_model.h"
 #include "ash/app_list/model/search/search_result.h"
-#include "ash/app_list/model/speech/speech_ui_model.h"
 #include "base/strings/string16.h"
 
 class ChromeAppListItem;
@@ -53,8 +52,6 @@
       const base::string16& tablet_accessible_name,
       const base::string16& clamshell_accessible_name) {}
   virtual void SetSearchHintText(const base::string16& hint_text) {}
-  virtual void SetSearchSpeechRecognitionButton(
-      app_list::SpeechRecognitionState state) {}
   virtual void UpdateSearchBox(const base::string16& text,
                                bool initiated_by_user) {}
   virtual void PublishSearchResults(
diff --git a/chrome/browser/ui/app_list/app_list_service.h b/chrome/browser/ui/app_list/app_list_service.h
index d30c25826..11f9142 100644
--- a/chrome/browser/ui/app_list/app_list_service.h
+++ b/chrome/browser/ui/app_list/app_list_service.h
@@ -75,13 +75,6 @@
   // profile to local prefs as the default app list profile.
   virtual void ShowForProfile(Profile* requested_profile) = 0;
 
-  // Shows the app list, and switches to voice search. Used by always-on
-  // hotwording.
-  virtual void ShowForVoiceSearch(
-      Profile* profile,
-      const scoped_refptr<content::SpeechRecognitionSessionPreamble>& preamble)
-      = 0;
-
   // Shows the app list, and reveals the page that contains |extension_id|. This
   // should only be called for things that show in the app list, and only when
   // they begin or complete installing. If |start_discovery_tracking| is set,
diff --git a/chrome/browser/ui/app_list/app_list_service_disabled.cc b/chrome/browser/ui/app_list/app_list_service_disabled.cc
index 4b0161b..6bb7f7a4 100644
--- a/chrome/browser/ui/app_list/app_list_service_disabled.cc
+++ b/chrome/browser/ui/app_list/app_list_service_disabled.cc
@@ -54,10 +54,6 @@
 
   void Show() override {}
   void ShowForProfile(Profile* profile) override {}
-  void ShowForVoiceSearch(
-      Profile* profile,
-      const scoped_refptr<content::SpeechRecognitionSessionPreamble>& preamble)
-      override {}
   void ShowForAppInstall(Profile* profile,
                          const std::string& extension_id,
                          bool start_discovery_tracking) override {}
diff --git a/chrome/browser/ui/app_list/app_list_service_impl.cc b/chrome/browser/ui/app_list/app_list_service_impl.cc
index c2fbabdc..a93099a8 100644
--- a/chrome/browser/ui/app_list/app_list_service_impl.cc
+++ b/chrome/browser/ui/app_list/app_list_service_impl.cc
@@ -359,13 +359,6 @@
                  weak_factory_.GetWeakPtr()));
 }
 
-void AppListServiceImpl::ShowForVoiceSearch(
-    Profile* profile,
-    const scoped_refptr<content::SpeechRecognitionSessionPreamble>& preamble) {
-  ShowForProfile(profile);
-  view_delegate_->StartSpeechRecognitionForHotword(preamble);
-}
-
 void AppListServiceImpl::ShowForAppInstall(Profile* profile,
                                            const std::string& extension_id,
                                            bool start_discovery_tracking) {
diff --git a/chrome/browser/ui/app_list/app_list_service_impl.h b/chrome/browser/ui/app_list/app_list_service_impl.h
index 4da867f..98af63b 100644
--- a/chrome/browser/ui/app_list/app_list_service_impl.h
+++ b/chrome/browser/ui/app_list/app_list_service_impl.h
@@ -52,10 +52,6 @@
   base::FilePath GetProfilePath(const base::FilePath& user_data_dir) override;
   void SetProfilePath(const base::FilePath& profile_path) override;
   void Show() override;
-  void ShowForVoiceSearch(
-      Profile* profile,
-      const scoped_refptr<content::SpeechRecognitionSessionPreamble>& preamble)
-      override;
   void ShowForAppInstall(Profile* profile,
                          const std::string& extension_id,
                          bool start_discovery_tracking) override;
diff --git a/chrome/browser/ui/app_list/app_list_view_delegate.cc b/chrome/browser/ui/app_list/app_list_view_delegate.cc
index b1cd812..8e1375cfc 100644
--- a/chrome/browser/ui/app_list/app_list_view_delegate.cc
+++ b/chrome/browser/ui/app_list/app_list_view_delegate.cc
@@ -12,7 +12,6 @@
 #include "ash/app_list/model/app_list_model.h"
 #include "ash/app_list/model/app_list_view_state.h"
 #include "ash/app_list/model/search/search_model.h"
-#include "ash/app_list/model/speech/speech_ui_model.h"
 #include "ash/public/interfaces/constants.mojom.h"
 #include "base/command_line.h"
 #include "base/metrics/histogram_macros.h"
@@ -85,27 +84,6 @@
 
 }  // namespace
 
-namespace app_list {
-
-SpeechRecognitionState ToSpeechRecognitionState(SpeechRecognizerState state) {
-  switch (state) {
-    case SPEECH_RECOGNIZER_OFF:
-      return SPEECH_RECOGNITION_OFF;
-    case SPEECH_RECOGNIZER_READY:
-      return SPEECH_RECOGNITION_READY;
-    case SPEECH_RECOGNIZER_RECOGNIZING:
-      return SPEECH_RECOGNITION_RECOGNIZING;
-    case SPEECH_RECOGNIZER_IN_SPEECH:
-      return SPEECH_RECOGNITION_IN_SPEECH;
-    case SPEECH_RECOGNIZER_STOPPING:
-      return SPEECH_RECOGNITION_STOPPING;
-    case SPEECH_RECOGNIZER_NETWORK_ERROR:
-      return SPEECH_RECOGNITION_NETWORK_ERROR;
-  }
-}
-
-}  // namespace app_list
-
 AppListViewDelegate::AppListViewDelegate(AppListControllerDelegate* controller)
     : controller_(controller),
       profile_(nullptr),
@@ -116,14 +94,6 @@
       observer_binding_(this),
       weak_ptr_factory_(this) {
   CHECK(controller_);
-  speech_ui_.reset(new app_list::SpeechUIModel);
-
-#if defined(GOOGLE_CHROME_BUILD)
-  gfx::ImageSkia* image;
-  image = ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
-      IDR_APP_LIST_GOOGLE_LOGO_VOICE_SEARCH);
-  speech_ui_->set_logo(*image);
-#endif
 
   registrar_.Add(this, chrome::NOTIFICATION_APP_TERMINATING,
                  content::NotificationService::AllSources());
@@ -155,14 +125,8 @@
     // delete |model_|'s search results to clear any dangling pointers.
     search_model_->results()->DeleteAll();
 
-    // Note: |search_resource_manager_| has a reference to |speech_ui_| so must
-    // be destroyed first.
     search_resource_manager_.reset();
     search_controller_.reset();
-    app_list::StartPageService* start_page_service =
-        app_list::StartPageService::Get(profile_);
-    if (start_page_service)
-      start_page_service->RemoveObserver(this);
     app_sync_ui_state_watcher_.reset();
     model_ = nullptr;
     search_model_ = nullptr;
@@ -172,11 +136,8 @@
   template_url_service_observer_.RemoveAll();
 
   profile_ = new_profile;
-  if (!profile_) {
-    speech_ui_->SetSpeechRecognitionState(app_list::SPEECH_RECOGNITION_OFF,
-                                          false);
+  if (!profile_)
     return;
-  }
 
   // If we are in guest mode, the new profile should be an incognito profile.
   // Otherwise, this may later hit a check (same condition as this one) in
@@ -218,19 +179,8 @@
 }
 
 void AppListViewDelegate::SetUpSearchUI() {
-  app_list::StartPageService* start_page_service =
-      app_list::StartPageService::Get(profile_);
-  if (start_page_service)
-    start_page_service->AddObserver(this);
-
-  speech_ui_->SetSpeechRecognitionState(
-      start_page_service
-          ? app_list::ToSpeechRecognitionState(start_page_service->state())
-          : app_list::SPEECH_RECOGNITION_OFF,
-      false);
-
-  search_resource_manager_.reset(new app_list::SearchResourceManager(
-      profile_, model_updater_, speech_ui_.get()));
+  search_resource_manager_.reset(
+      new app_list::SearchResourceManager(profile_, model_updater_));
 
   search_controller_ =
       app_list::CreateSearchController(profile_, model_updater_, controller_);
@@ -258,10 +208,6 @@
   return search_model_;
 }
 
-app_list::SpeechUIModel* AppListViewDelegate::GetSpeechUI() {
-  return speech_ui_.get();
-}
-
 void AppListViewDelegate::StartSearch(const base::string16& raw_query) {
   if (search_controller_) {
     search_controller_->Start(raw_query);
@@ -310,44 +256,6 @@
     service->AppListHidden();
 }
 
-void AppListViewDelegate::StartSpeechRecognition() {
-  StartSpeechRecognitionForHotword(nullptr);
-}
-
-void AppListViewDelegate::StopSpeechRecognition() {
-  app_list::StartPageService* service =
-      app_list::StartPageService::Get(profile_);
-  if (service)
-    service->StopSpeechRecognition();
-}
-
-void AppListViewDelegate::StartSpeechRecognitionForHotword(
-    const scoped_refptr<content::SpeechRecognitionSessionPreamble>& preamble) {
-  app_list::StartPageService* service =
-      app_list::StartPageService::Get(profile_);
-
-  // Don't start the recognizer or stop the hotword session if there is a
-  // network error. Show the network error message instead.
-  if (service) {
-    if (service->state() == SPEECH_RECOGNIZER_NETWORK_ERROR) {
-      speech_ui_->SetSpeechRecognitionState(
-          app_list::SPEECH_RECOGNITION_NETWORK_ERROR, true);
-      return;
-    }
-    service->StartSpeechRecognition(preamble);
-  }
-}
-
-void AppListViewDelegate::OnSpeechSoundLevelChanged(int16_t level) {
-  speech_ui_->UpdateSoundLevel(level);
-}
-
-void AppListViewDelegate::OnSpeechRecognitionStateChanged(
-    SpeechRecognizerState new_state) {
-  speech_ui_->SetSpeechRecognitionState(
-      app_list::ToSpeechRecognitionState(new_state), false);
-}
-
 views::View* AppListViewDelegate::CreateStartPageWebView(
     const gfx::Size& size) {
   app_list::StartPageService* service =
@@ -370,12 +278,6 @@
   return web_view;
 }
 
-bool AppListViewDelegate::IsSpeechRecognitionEnabled() {
-  app_list::StartPageService* service =
-      app_list::StartPageService::Get(profile_);
-  return service && service->GetSpeechRecognitionContents();
-}
-
 void AppListViewDelegate::GetWallpaperProminentColors(
     std::vector<SkColor>* colors) {
   *colors = wallpaper_prominent_colors_;
diff --git a/chrome/browser/ui/app_list/app_list_view_delegate.h b/chrome/browser/ui/app_list/app_list_view_delegate.h
index e62a1edc..c1c04e73 100644
--- a/chrome/browser/ui/app_list/app_list_view_delegate.h
+++ b/chrome/browser/ui/app_list/app_list_view_delegate.h
@@ -18,7 +18,6 @@
 #include "base/memory/weak_ptr.h"
 #include "base/scoped_observer.h"
 #include "chrome/browser/ui/app_list/chrome_app_list_model_updater.h"
-#include "chrome/browser/ui/app_list/start_page_observer.h"
 #include "components/search_engines/template_url_service.h"
 #include "components/search_engines/template_url_service_observer.h"
 #include "content/public/browser/notification_observer.h"
@@ -32,7 +31,6 @@
 namespace app_list {
 class SearchController;
 class SearchResourceManager;
-class SpeechUIModel;
 }
 
 namespace content {
@@ -44,7 +42,6 @@
 class Profile;
 
 class AppListViewDelegate : public app_list::AppListViewDelegate,
-                            public app_list::StartPageObserver,
                             public ash::mojom::WallpaperObserver,
                             public content::NotificationObserver,
                             public TemplateURLServiceObserver {
@@ -58,17 +55,12 @@
   void SetProfile(Profile* profile);
   Profile* profile() { return profile_; }
 
-  // Invoked to start speech recognition based on a hotword trigger.
-  void StartSpeechRecognitionForHotword(
-      const scoped_refptr<content::SpeechRecognitionSessionPreamble>& preamble);
-
   // Gets the model updater.
   AppListModelUpdater* GetModelUpdater();
 
   // Overridden from app_list::AppListViewDelegate:
   app_list::AppListModel* GetModel() override;
   app_list::SearchModel* GetSearchModel() override;
-  app_list::SpeechUIModel* GetSpeechUI() override;
   void StartSearch(const base::string16& raw_query) override;
   void OpenSearchResult(app_list::SearchResult* result,
                         int event_flags) override;
@@ -78,10 +70,7 @@
   void ViewInitialized() override;
   void Dismiss() override;
   void ViewClosing() override;
-  void StartSpeechRecognition() override;
-  void StopSpeechRecognition() override;
   views::View* CreateStartPageWebView(const gfx::Size& size) override;
-  bool IsSpeechRecognitionEnabled() override;
   void GetWallpaperProminentColors(std::vector<SkColor>* colors) override;
   void ActivateItem(const std::string& id, int event_flags) override;
   ui::MenuModel* GetContextMenuModel(const std::string& id) override;
@@ -98,11 +87,6 @@
   // Updates the speech webview and start page for the current |profile_|.
   void SetUpSearchUI();
 
-  // Overridden from app_list::StartPageObserver:
-  void OnSpeechSoundLevelChanged(int16_t level) override;
-  void OnSpeechRecognitionStateChanged(
-      SpeechRecognizerState new_state) override;
-
   // Overridden from ash::mojom::WallpaperObserver:
   void OnWallpaperColorsChanged(
       const std::vector<SkColor>& prominent_colors) override;
@@ -126,9 +110,6 @@
   // Will change if |profile_| changes.
   ChromeAppListModelUpdater* model_updater_;
 
-  // Note: order ensures |search_resource_manager_| is destroyed before
-  // |speech_ui_|.
-  std::unique_ptr<app_list::SpeechUIModel> speech_ui_;
   std::unique_ptr<app_list::SearchResourceManager> search_resource_manager_;
   std::unique_ptr<app_list::SearchController> search_controller_;
 
diff --git a/chrome/browser/ui/app_list/chrome_app_list_model_updater.cc b/chrome/browser/ui/app_list/chrome_app_list_model_updater.cc
index 257cc36b..ae66198 100644
--- a/chrome/browser/ui/app_list/chrome_app_list_model_updater.cc
+++ b/chrome/browser/ui/app_list/chrome_app_list_model_updater.cc
@@ -80,11 +80,6 @@
   search_model_->search_box()->SetHintText(hint_text);
 }
 
-void ChromeAppListModelUpdater::SetSearchSpeechRecognitionButton(
-    app_list::SpeechRecognitionState state) {
-  search_model_->search_box()->SetSpeechRecognitionButton(state);
-}
-
 void ChromeAppListModelUpdater::UpdateSearchBox(const base::string16& text,
                                                 bool initiated_by_user) {
   search_model_->search_box()->Update(text, initiated_by_user);
diff --git a/chrome/browser/ui/app_list/chrome_app_list_model_updater.h b/chrome/browser/ui/app_list/chrome_app_list_model_updater.h
index ed82e93..d555f9db 100644
--- a/chrome/browser/ui/app_list/chrome_app_list_model_updater.h
+++ b/chrome/browser/ui/app_list/chrome_app_list_model_updater.h
@@ -44,8 +44,6 @@
       const base::string16& tablet_accessible_name,
       const base::string16& clamshell_accessible_name) override;
   void SetSearchHintText(const base::string16& hint_text) override;
-  void SetSearchSpeechRecognitionButton(
-      app_list::SpeechRecognitionState state) override;
   void UpdateSearchBox(const base::string16& text,
                        bool initiated_by_user) override;
   void PublishSearchResults(
diff --git a/chrome/browser/ui/app_list/extension_app_model_builder_unittest.cc b/chrome/browser/ui/app_list/extension_app_model_builder_unittest.cc
index 371ebcc8..b899486 100644
--- a/chrome/browser/ui/app_list/extension_app_model_builder_unittest.cc
+++ b/chrome/browser/ui/app_list/extension_app_model_builder_unittest.cc
@@ -265,9 +265,9 @@
   sorting->ClearOrdinals(kPackagedApp1Id);
 
   // Creates a corrupted ordinal case.
-  extensions::ExtensionScopedPrefs* scoped_prefs =
+  extensions::ExtensionPrefs* prefs =
       extensions::ExtensionPrefs::Get(profile_.get());
-  scoped_prefs->UpdateExtensionPref(
+  prefs->UpdateExtensionPref(
       kHostedAppId, "page_ordinal",
       std::make_unique<base::Value>("a corrupted ordinal"));
 
diff --git a/chrome/browser/ui/app_list/search/search_resource_manager.cc b/chrome/browser/ui/app_list/search/search_resource_manager.cc
index 987eb61b..9a37439 100644
--- a/chrome/browser/ui/app_list/search/search_resource_manager.cc
+++ b/chrome/browser/ui/app_list/search/search_resource_manager.cc
@@ -6,46 +6,28 @@
 
 #include <memory>
 
-#include "ash/app_list/model/speech/speech_ui_model.h"
 #include "base/memory/ptr_util.h"
 #include "chrome/browser/ui/app_list/app_list_model_updater.h"
 #include "chrome/browser/ui/app_list/start_page_service.h"
 #include "chrome/grit/generated_resources.h"
 #include "chrome/grit/theme_resources.h"
-#include "ui/app_list/app_list_features.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/resource/resource_bundle.h"
 
 namespace app_list {
 
 SearchResourceManager::SearchResourceManager(Profile* profile,
-                                             AppListModelUpdater* model_updater,
-                                             SpeechUIModel* speech_ui)
-    : model_updater_(model_updater),
-      speech_ui_(speech_ui),
-      is_fullscreen_app_list_enabled_(features::IsFullscreenAppListEnabled()) {
-  speech_ui_->AddObserver(this);
+                                             AppListModelUpdater* model_updater)
+    : model_updater_(model_updater) {
   // Give |SearchBoxModel| tablet and clamshell A11y Announcements.
   model_updater_->SetSearchTabletAndClamshellAccessibleName(
       l10n_util::GetStringUTF16(IDS_SEARCH_BOX_ACCESSIBILITY_NAME_TABLET),
       l10n_util::GetStringUTF16(IDS_SEARCH_BOX_ACCESSIBILITY_NAME));
-  OnSpeechRecognitionStateChanged(speech_ui_->state());
+  model_updater_->SetSearchHintText(
+      l10n_util::GetStringUTF16(IDS_SEARCH_BOX_HINT_FULLSCREEN));
 }
 
 SearchResourceManager::~SearchResourceManager() {
-  speech_ui_->RemoveObserver(this);
-}
-
-void SearchResourceManager::OnSpeechRecognitionStateChanged(
-    SpeechRecognitionState new_state) {
-  if (is_fullscreen_app_list_enabled_) {
-    model_updater_->SetSearchHintText(
-        l10n_util::GetStringUTF16(IDS_SEARCH_BOX_HINT_FULLSCREEN));
-  } else {
-    model_updater_->SetSearchHintText(
-        l10n_util::GetStringUTF16(IDS_SEARCH_BOX_HINT));
-    model_updater_->SetSearchSpeechRecognitionButton(new_state);
-  }
 }
 
 }  // namespace app_list
diff --git a/chrome/browser/ui/app_list/search/search_resource_manager.h b/chrome/browser/ui/app_list/search/search_resource_manager.h
index 7122dfd..4f91652 100644
--- a/chrome/browser/ui/app_list/search/search_resource_manager.h
+++ b/chrome/browser/ui/app_list/search/search_resource_manager.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_UI_APP_LIST_SEARCH_SEARCH_RESOURCE_MANAGER_H_
 #define CHROME_BROWSER_UI_APP_LIST_SEARCH_SEARCH_RESOURCE_MANAGER_H_
 
-#include "ash/app_list/model/speech/speech_ui_model_observer.h"
 #include "base/macros.h"
 
 class AppListModelUpdater;
@@ -13,25 +12,14 @@
 
 namespace app_list {
 
-class SpeechUIModel;
-
 // Manages the strings and assets of the app-list search box.
-class SearchResourceManager : public SpeechUIModelObserver {
+class SearchResourceManager {
  public:
-  SearchResourceManager(Profile* profile,
-                        AppListModelUpdater* model_updater,
-                        SpeechUIModel* speech_ui);
-  ~SearchResourceManager() override;
+  SearchResourceManager(Profile* profile, AppListModelUpdater* model_updater);
+  ~SearchResourceManager();
 
  private:
-  // SpeechUIModelObserver overrides:
-  void OnSpeechRecognitionStateChanged(
-      SpeechRecognitionState new_state) override;
-
   AppListModelUpdater* model_updater_;
-  SpeechUIModel* speech_ui_;
-
-  const bool is_fullscreen_app_list_enabled_;
 
   DISALLOW_COPY_AND_ASSIGN(SearchResourceManager);
 };
diff --git a/chrome/browser/ui/app_list/speech_auth_helper.cc b/chrome/browser/ui/app_list/speech_auth_helper.cc
deleted file mode 100644
index 63a3e8fb..0000000
--- a/chrome/browser/ui/app_list/speech_auth_helper.cc
+++ /dev/null
@@ -1,125 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/ui/app_list/speech_auth_helper.h"
-
-#include <string>
-
-#include "base/bind.h"
-#include "base/time/clock.h"
-#include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
-#include "chrome/browser/signin/signin_manager_factory.h"
-#include "components/signin/core/browser/profile_oauth2_token_service.h"
-#include "components/signin/core/browser/signin_manager.h"
-#include "content/public/browser/browser_thread.h"
-
-namespace app_list {
-
-static const char* kAuthScope =
-    "https://www.googleapis.com/auth/webhistory";
-static const int kMinTokenRefreshDelaySeconds = 300;  // 5 minutes
-
-
-SpeechAuthHelper::SpeechAuthHelper(Profile* profile, base::Clock* clock)
-    : OAuth2TokenService::Consumer(kAuthScope),
-      clock_(clock),
-      token_service_(ProfileOAuth2TokenServiceFactory::GetForProfile(profile)),
-      weak_factory_(this) {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-
-  // If token_service_ is NULL, we can't do anything. This might be NULL if the
-  // profile is a guest user.
-  if (!token_service_)
-    return;
-
-  SigninManagerBase* signin_manager =
-      SigninManagerFactory::GetForProfile(profile);
-  // Again, this might be NULL, and if it is, we can't proceed.
-  if (!signin_manager)
-    return;
-
-  authenticated_account_id_ = signin_manager->GetAuthenticatedAccountId();
-  if (!token_service_->RefreshTokenIsAvailable(authenticated_account_id_)) {
-    // Wait for the OAuth2 refresh token to be available before trying to obtain
-    // a speech token.
-    token_service_->AddObserver(this);
-  } else {
-    FetchAuthToken();
-  }
-}
-
-SpeechAuthHelper::~SpeechAuthHelper() {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  if (token_service_)
-    token_service_->RemoveObserver(this);
-}
-
-void SpeechAuthHelper::OnGetTokenSuccess(
-    const OAuth2TokenService::Request* request,
-    const std::string& access_token,
-    const base::Time& expiration_time) {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  auth_token_ = access_token;
-  auth_token_request_.reset();
-
-  base::Time now = clock_->Now();
-  base::TimeDelta delay = expiration_time - now;
-  if (delay.InSeconds() < kMinTokenRefreshDelaySeconds)
-    delay = base::TimeDelta::FromSeconds(kMinTokenRefreshDelaySeconds);
-  ScheduleTokenFetch(delay);
-}
-
-void SpeechAuthHelper::OnGetTokenFailure(
-    const OAuth2TokenService::Request* request,
-    const GoogleServiceAuthError& error) {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  auth_token_ = "";
-  auth_token_request_.reset();
-
-  // Try again later.
-  // TODO(amistry): Implement backoff.
-  ScheduleTokenFetch(
-      base::TimeDelta::FromSeconds(kMinTokenRefreshDelaySeconds));
-}
-
-void SpeechAuthHelper::OnRefreshTokenAvailable(const std::string& account_id) {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  if (authenticated_account_id_ == account_id)
-    FetchAuthToken();
-}
-
-void SpeechAuthHelper::ScheduleTokenFetch(const base::TimeDelta& fetch_delay) {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  content::BrowserThread::PostDelayedTask(
-      content::BrowserThread::UI,
-      FROM_HERE,
-      base::Bind(&SpeechAuthHelper::FetchAuthToken,
-                 weak_factory_.GetWeakPtr()),
-      fetch_delay);
-}
-
-void SpeechAuthHelper::FetchAuthToken() {
-  // The process of fetching and refreshing OAuth tokens is started from the
-  // consustructor, and so token_service_ and authenticated_account_id_ are
-  // guaranteed to be valid at this point.
-  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  OAuth2TokenService::ScopeSet scopes;
-  scopes.insert(kAuthScope);
-  auth_token_request_ = token_service_->StartRequest(
-      authenticated_account_id_,
-      scopes,
-      this);
-}
-
-std::string SpeechAuthHelper::GetToken() const {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  return auth_token_;
-}
-
-std::string SpeechAuthHelper::GetScope() const {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  return kAuthScope;
-}
-
-}  // namespace app_list
diff --git a/chrome/browser/ui/app_list/speech_auth_helper.h b/chrome/browser/ui/app_list/speech_auth_helper.h
deleted file mode 100644
index 13f1eee..0000000
--- a/chrome/browser/ui/app_list/speech_auth_helper.h
+++ /dev/null
@@ -1,67 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_UI_APP_LIST_SPEECH_AUTH_HELPER_H_
-#define CHROME_BROWSER_UI_APP_LIST_SPEECH_AUTH_HELPER_H_
-
-#include <memory>
-#include <string>
-
-#include "base/macros.h"
-#include "base/memory/weak_ptr.h"
-#include "components/signin/core/browser/profile_oauth2_token_service.h"
-
-class Profile;
-class ProfileOAuth2TokenService;
-
-namespace base {
-class Clock;
-}
-
-namespace app_list {
-
-// SpeechAuthHelper is a helper class to generate oauth tokens for audio
-// history. This encalsulates generating and refreshing the auth token for a
-// given profile. All functions should be called on the UI thread.
-class SpeechAuthHelper : public OAuth2TokenService::Consumer,
-                         public OAuth2TokenService::Observer {
- public:
-  SpeechAuthHelper(Profile* profile, base::Clock* clock);
-  ~SpeechAuthHelper() override;
-
-  // Returns the current auth token. If the auth service is not available, or
-  // there was a failure in obtaining a token, return the empty string.
-  std::string GetToken() const;
-
-  // Returns the OAuth scope associated with the auth token.
-  std::string GetScope() const;
-
- private:
-  // Overridden from OAuth2TokenService::Consumer:
-  void OnGetTokenSuccess(const OAuth2TokenService::Request* request,
-                         const std::string& access_token,
-                         const base::Time& expiration_time) override;
-  void OnGetTokenFailure(const OAuth2TokenService::Request* request,
-                         const GoogleServiceAuthError& error) override;
-
-  // Overridden from OAuth2TokenService::Observer:
-  void OnRefreshTokenAvailable(const std::string& account_id) override;
-
-  void ScheduleTokenFetch(const base::TimeDelta& fetch_delay);
-  void FetchAuthToken();
-
-  base::Clock* clock_;
-  ProfileOAuth2TokenService* token_service_;
-  std::string authenticated_account_id_;
-  std::string auth_token_;
-  std::unique_ptr<OAuth2TokenService::Request> auth_token_request_;
-
-  base::WeakPtrFactory<SpeechAuthHelper> weak_factory_;
-
-  DISALLOW_COPY_AND_ASSIGN(SpeechAuthHelper);
-};
-
-}  // namespace app_list
-
-#endif  // CHROME_BROWSER_UI_APP_LIST_SPEECH_AUTH_HELPER_H_
diff --git a/chrome/browser/ui/app_list/speech_auth_helper_unittest.cc b/chrome/browser/ui/app_list/speech_auth_helper_unittest.cc
deleted file mode 100644
index 5dd813c..0000000
--- a/chrome/browser/ui/app_list/speech_auth_helper_unittest.cc
+++ /dev/null
@@ -1,121 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/ui/app_list/speech_auth_helper.h"
-
-#include <memory>
-#include <utility>
-
-#include "base/strings/utf_string_conversions.h"
-#include "base/test/simple_test_clock.h"
-#include "chrome/browser/signin/fake_profile_oauth2_token_service_builder.h"
-#include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
-#include "chrome/browser/signin/signin_manager_factory.h"
-#include "chrome/test/base/testing_browser_process.h"
-#include "chrome/test/base/testing_profile.h"
-#include "chrome/test/base/testing_profile_manager.h"
-#include "components/signin/core/browser/fake_profile_oauth2_token_service.h"
-#include "components/signin/core/browser/signin_manager.h"
-#include "components/signin/core/browser/signin_manager_base.h"
-#include "components/sync_preferences/pref_service_syncable.h"
-#include "content/public/test/test_browser_thread_bundle.h"
-#include "google_apis/gaia/google_service_auth_error.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace app_list {
-
-static const char* kTestGaiaId = "gaia_id";
-static const char* kTestUser = "test.user@chromium.org.test";
-static const char* kScope = "https://www.googleapis.com/auth/webhistory";
-static const char* kAccessToken = "fake_access_token";
-
-class SpeechAuthHelperTest : public testing::Test {
- public:
-  SpeechAuthHelperTest()
-      : testing_profile_manager_(new TestingProfileManager(
-          TestingBrowserProcess::GetGlobal())) {
-  }
-
-  void SetUp() override {
-    // Set up FakeProfileOAuth2TokenService.
-    TestingProfile::TestingFactories factories;
-    factories.push_back(std::make_pair(
-        ProfileOAuth2TokenServiceFactory::GetInstance(),
-        &BuildAutoIssuingFakeProfileOAuth2TokenService));
-
-    ASSERT_TRUE(testing_profile_manager_->SetUp());
-    profile_ = testing_profile_manager_->CreateTestingProfile(
-        kTestUser, std::unique_ptr<sync_preferences::PrefServiceSyncable>(),
-        base::UTF8ToUTF16(kTestUser), 0, std::string(), factories);
-
-    // Set up the authenticated user name and ID.
-    SigninManagerFactory::GetForProfile(profile_)->SetAuthenticatedAccountInfo(
-        kTestGaiaId, kTestUser);
-  }
-
- protected:
-  void SetupRefreshToken() {
-    std::string account_id = SigninManagerFactory::GetForProfile(profile_)
-                                 ->GetAuthenticatedAccountId();
-    GetFakeProfileOAuth2TokenService()->UpdateCredentials(account_id,
-                                                          "fake_refresh_token");
-  }
-
-  FakeProfileOAuth2TokenService* GetFakeProfileOAuth2TokenService() {
-    return static_cast<FakeProfileOAuth2TokenService*>(
-        ProfileOAuth2TokenServiceFactory::GetForProfile(profile_));
-  }
-
-  base::SimpleTestClock test_clock_;
-  content::TestBrowserThreadBundle thread_bundle;
-  std::unique_ptr<TestingProfileManager> testing_profile_manager_;
-  Profile* profile_;
-  std::unique_ptr<SpeechAuthHelper> auth_helper_;
-};
-
-TEST_F(SpeechAuthHelperTest, TokenFetch) {
-  SetupRefreshToken();
-  SpeechAuthHelper helper(profile_, &test_clock_);
-  EXPECT_TRUE(helper.GetToken().empty());
-
-  OAuth2TokenService::ScopeSet scopes;
-  scopes.insert(kScope);
-  GetFakeProfileOAuth2TokenService()->IssueTokenForScope(scopes,
-                                                         kAccessToken,
-                                                         base::Time::Max());
-
-  EXPECT_EQ(kAccessToken, helper.GetToken());
-  EXPECT_EQ(kScope, helper.GetScope());
-}
-
-TEST_F(SpeechAuthHelperTest, TokenFetchDelayedRefreshToken) {
-  SpeechAuthHelper helper(profile_, &test_clock_);
-  SetupRefreshToken();
-  EXPECT_TRUE(helper.GetToken().empty());
-
-  OAuth2TokenService::ScopeSet scopes;
-  scopes.insert(kScope);
-  GetFakeProfileOAuth2TokenService()->IssueTokenForScope(scopes,
-                                                         kAccessToken,
-                                                         base::Time::Max());
-
-  EXPECT_EQ(kAccessToken, helper.GetToken());
-  EXPECT_EQ(kScope, helper.GetScope());
-}
-
-TEST_F(SpeechAuthHelperTest, TokenFetchFailed) {
-  SetupRefreshToken();
-  SpeechAuthHelper helper(profile_, &test_clock_);
-  EXPECT_TRUE(helper.GetToken().empty());
-
-  OAuth2TokenService::ScopeSet scopes;
-  scopes.insert(kScope);
-  GetFakeProfileOAuth2TokenService()->IssueErrorForScope(
-      scopes, GoogleServiceAuthError(GoogleServiceAuthError::SERVICE_ERROR));
-
-  EXPECT_TRUE(helper.GetToken().empty());
-  EXPECT_EQ(kScope, helper.GetScope());
-}
-
-}  // namespace app_list
diff --git a/chrome/browser/ui/app_list/start_page_observer.h b/chrome/browser/ui/app_list/start_page_observer.h
deleted file mode 100644
index 8213508..0000000
--- a/chrome/browser/ui/app_list/start_page_observer.h
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_UI_APP_LIST_START_PAGE_OBSERVER_H_
-#define CHROME_BROWSER_UI_APP_LIST_START_PAGE_OBSERVER_H_
-
-#include <stdint.h>
-
-#include "ash/app_list/model/speech/speech_ui_model.h"
-#include "base/strings/string16.h"
-#include "chrome/browser/speech/speech_recognizer_delegate.h"
-
-namespace app_list {
-
-class StartPageObserver {
- public:
-  // Invoked when a sound level of speech recognition is changed.
-  virtual void OnSpeechSoundLevelChanged(int16_t level) = 0;
-
-  // Invoked when the online speech recognition state is changed.
-  virtual void OnSpeechRecognitionStateChanged(
-      SpeechRecognizerState new_state) = 0;
-
- protected:
-  virtual ~StartPageObserver() {}
-};
-
-}  // namespace app_list
-
-#endif  // CHROME_BROWSER_UI_APP_LIST_START_PAGE_OBSERVER_H_
diff --git a/chrome/browser/ui/app_list/start_page_service.cc b/chrome/browser/ui/app_list/start_page_service.cc
index 5ced437b..b4146c13 100644
--- a/chrome/browser/ui/app_list/start_page_service.cc
+++ b/chrome/browser/ui/app_list/start_page_service.cc
@@ -23,9 +23,6 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/search_engines/template_url_service_factory.h"
 #include "chrome/browser/search_engines/ui_thread_search_terms_data.h"
-#include "chrome/browser/speech/speech_recognizer.h"
-#include "chrome/browser/ui/app_list/speech_auth_helper.h"
-#include "chrome/browser/ui/app_list/start_page_observer.h"
 #include "chrome/browser/ui/app_list/start_page_service_factory.h"
 #include "chrome/browser/ui/browser_navigator.h"
 #include "chrome/browser/ui/browser_navigator_params.h"
@@ -103,11 +100,6 @@
   false,
 };
 
-bool InSpeechRecognition(SpeechRecognizerState state) {
-  return state == SPEECH_RECOGNIZER_RECOGNIZING ||
-         state == SPEECH_RECOGNIZER_IN_SPEECH;
-}
-
 }  // namespace
 
 class StartPageService::ProfileDestroyObserver
@@ -203,42 +195,6 @@
   DISALLOW_COPY_AND_ASSIGN(StartPageWebContentsDelegate);
 };
 
-
-class StartPageService::AudioStatus
-    : public chromeos::CrasAudioHandler::AudioObserver {
- public:
-  explicit AudioStatus(StartPageService* start_page_service)
-      : start_page_service_(start_page_service) {
-    chromeos::CrasAudioHandler::Get()->AddAudioObserver(this);
-    CheckAndUpdate();
-  }
-
-  ~AudioStatus() override {
-    chromeos::CrasAudioHandler::Get()->RemoveAudioObserver(this);
-  }
-
-  bool CanListen() {
-    chromeos::CrasAudioHandler* audio_handler =
-        chromeos::CrasAudioHandler::Get();
-    return (audio_handler->GetPrimaryActiveInputNode() != 0) &&
-           !audio_handler->IsInputMuted();
-  }
-
- private:
-  void CheckAndUpdate() {
-    start_page_service_->OnMicrophoneChanged(CanListen());
-  }
-
-  // chromeos::CrasAudioHandler::AudioObserver:
-  void OnInputMuteChanged(bool /* mute_on */) override { CheckAndUpdate(); }
-
-  void OnActiveInputNodeChanged() override { CheckAndUpdate(); }
-
-  StartPageService* start_page_service_;
-
-  DISALLOW_COPY_AND_ASSIGN(AudioStatus);
-};
-
 class StartPageService::NetworkChangeObserver
     : public net::NetworkChangeNotifier::NetworkChangeObserver {
  public:
@@ -292,13 +248,8 @@
 StartPageService::StartPageService(Profile* profile)
     : profile_(profile),
       profile_destroy_observer_(new ProfileDestroyObserver(this)),
-      state_(SPEECH_RECOGNIZER_READY),
-      speech_button_toggled_manually_(false),
-      speech_result_obtained_(false),
       webui_finished_loading_(false),
-      speech_auth_helper_(new SpeechAuthHelper(profile, &clock_)),
       network_available_(true),
-      microphone_available_(true),
       search_engine_is_google_(false),
       backoff_entry_(&kDoodleBackoffPolicy),
       weak_factory_(this) {
@@ -316,34 +267,8 @@
 StartPageService::~StartPageService() {
 }
 
-void StartPageService::AddObserver(StartPageObserver* observer) {
-  observers_.AddObserver(observer);
-}
-
-void StartPageService::RemoveObserver(StartPageObserver* observer) {
-  observers_.RemoveObserver(observer);
-}
-
-void StartPageService::OnMicrophoneChanged(bool available) {
-  microphone_available_ = available;
-  UpdateRecognitionState();
-}
-
 void StartPageService::OnNetworkChanged(bool available) {
   network_available_ = available;
-  UpdateRecognitionState();
-}
-
-void StartPageService::UpdateRecognitionState() {
-  if (ShouldEnableSpeechRecognition()) {
-    if (state_ == SPEECH_RECOGNIZER_OFF ||
-        state_ == SPEECH_RECOGNIZER_NETWORK_ERROR)
-      OnSpeechRecognitionStateChanged(SPEECH_RECOGNIZER_READY);
-  } else {
-    OnSpeechRecognitionStateChanged(network_available_
-                                        ? SPEECH_RECOGNIZER_OFF
-                                        : SPEECH_RECOGNIZER_NETWORK_ERROR);
-  }
 }
 
 void StartPageService::Init() {
@@ -364,10 +289,6 @@
     LoadContents();
 }
 
-bool StartPageService::ShouldEnableSpeechRecognition() const {
-  return microphone_available_ && network_available_;
-}
-
 void StartPageService::AppListShown() {
   if (!contents_) {
     LoadContents();
@@ -377,113 +298,17 @@
     contents_->GetWebUI()->CallJavascriptFunctionUnsafe(
         "appList.startPage.onAppListShown");
   }
-
-  audio_status_.reset(new AudioStatus(this));
 }
 
 void StartPageService::AppListHidden() {
-  if (speech_recognizer_) {
-    StopSpeechRecognition();
-  }
-
-  audio_status_.reset();
-}
-
-void StartPageService::StartSpeechRecognition(
-    const scoped_refptr<content::SpeechRecognitionSessionPreamble>& preamble) {
-  DCHECK(contents_);
-  speech_button_toggled_manually_ = true;
-
-  if (!speech_recognizer_) {
-    std::string profile_locale;
-    profile_locale = profile_->GetPrefs()->GetString(
-        prefs::kApplicationLocale);
-    if (profile_locale.empty())
-      profile_locale = g_browser_process->GetApplicationLocale();
-
-    speech_recognizer_.reset(
-        new SpeechRecognizer(weak_factory_.GetWeakPtr(),
-                             profile_->GetRequestContext(),
-                             profile_locale));
-  }
-
-  speech_recognizer_->Start(preamble);
-}
-
-void StartPageService::StopSpeechRecognition() {
-  // A call to Stop() isn't needed since deleting the recognizer implicitly
-  // stops.
-  speech_recognizer_.reset();
-
-  // When the SpeechRecognizer is destroyed above, we get stuck in the current
-  // speech state instead of being reset into the READY state. Reset the speech
-  // state explicitly so that speech works when the launcher is opened again.
-  OnSpeechRecognitionStateChanged(SPEECH_RECOGNIZER_READY);
 }
 
 content::WebContents* StartPageService::GetStartPageContents() {
   return contents_.get();
 }
 
-content::WebContents* StartPageService::GetSpeechRecognitionContents() {
-  if (app_list::switches::IsVoiceSearchEnabled()) {
-    if (!contents_)
-      LoadContents();
-    return contents_.get();
-  }
-  return NULL;
-}
-
-void StartPageService::OnSpeechResult(
-    const base::string16& query, bool is_final) {
-  if (is_final) {
-    speech_result_obtained_ = true;
-    RecordAction(UserMetricsAction("AppList_SearchedBySpeech"));
-  }
-}
-
-void StartPageService::OnSpeechSoundLevelChanged(int16_t level) {
-  for (auto& observer : observers_)
-    observer.OnSpeechSoundLevelChanged(level);
-}
-
-void StartPageService::OnSpeechRecognitionStateChanged(
-    SpeechRecognizerState new_state) {
-  // Sometimes this can be called even though there are no audio input devices.
-  if (audio_status_ && !audio_status_->CanListen())
-    new_state = SPEECH_RECOGNIZER_OFF;
-  if (!microphone_available_)
-    new_state = SPEECH_RECOGNIZER_OFF;
-  if (!network_available_)
-    new_state = SPEECH_RECOGNIZER_NETWORK_ERROR;
-
-  if (state_ == new_state)
-    return;
-
-  if ((new_state == SPEECH_RECOGNIZER_READY ||
-       new_state == SPEECH_RECOGNIZER_OFF ||
-       new_state == SPEECH_RECOGNIZER_NETWORK_ERROR) &&
-      speech_recognizer_) {
-    speech_recognizer_->Stop();
-  }
-
-  if (!InSpeechRecognition(state_) && InSpeechRecognition(new_state)) {
-      RecordAction(UserMetricsAction("AppList_VoiceSearchStartedManually"));
-  } else if (InSpeechRecognition(state_) && !InSpeechRecognition(new_state) &&
-             !speech_result_obtained_) {
-    RecordAction(UserMetricsAction("AppList_VoiceSearchCanceled"));
-  }
-  speech_button_toggled_manually_ = false;
-  speech_result_obtained_ = false;
-  state_ = new_state;
-  for (auto& observer : observers_)
-    observer.OnSpeechRecognitionStateChanged(new_state);
-}
-
 void StartPageService::Shutdown() {
   UnloadContents();
-  audio_status_.reset();
-  speech_auth_helper_.reset();
   network_change_observer_.reset();
 }
 
diff --git a/chrome/browser/ui/app_list/start_page_service.h b/chrome/browser/ui/app_list/start_page_service.h
index 7f37f830..5b93f11 100644
--- a/chrome/browser/ui/app_list/start_page_service.h
+++ b/chrome/browser/ui/app_list/start_page_service.h
@@ -19,7 +19,6 @@
 #include "base/strings/string16.h"
 #include "base/time/default_clock.h"
 #include "build/build_config.h"
-#include "chrome/browser/speech/speech_recognizer_delegate.h"
 #include "components/keyed_service/core/keyed_service.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_contents_observer.h"
@@ -43,24 +42,17 @@
 
 namespace app_list {
 
-class SpeechAuthHelper;
-class StartPageObserver;
-
 // StartPageService collects data to be displayed in app list's start page
 // and hosts the start page contents.
 class StartPageService : public KeyedService,
                          public content::WebContentsObserver,
-                         public net::URLFetcherDelegate,
-                         public SpeechRecognizerDelegate {
+                         public net::URLFetcherDelegate {
  public:
   typedef std::vector<scoped_refptr<const extensions::Extension> >
       ExtensionList;
   // Gets the instance for the given profile. May return nullptr.
   static StartPageService* Get(Profile* profile);
 
-  void AddObserver(StartPageObserver* observer);
-  void RemoveObserver(StartPageObserver* observer);
-
   void Init();
 
   // Loads the start page WebContents if it hasn't already been loaded.
@@ -69,31 +61,17 @@
   void AppListShown();
   void AppListHidden();
 
-  void StartSpeechRecognition(
-      const scoped_refptr<content::SpeechRecognitionSessionPreamble>& preamble);
-  void StopSpeechRecognition();
-
   // Called when the WebUI has finished loading.
   void WebUILoaded();
 
   // They return essentially the same web contents but might return NULL when
   // some flag disables the feature.
   content::WebContents* GetStartPageContents();
-  content::WebContents* GetSpeechRecognitionContents();
 
   void set_search_engine_is_google(bool search_engine_is_google) {
     search_engine_is_google_ = search_engine_is_google;
   }
   Profile* profile() { return profile_; }
-  SpeechRecognizerState state() { return state_; }
-
-  // Overridden from app_list::SpeechRecognizerDelegate:
-  void OnSpeechResult(const base::string16& query, bool is_final) override;
-  void OnSpeechSoundLevelChanged(int16_t level) override;
-  void OnSpeechRecognitionStateChanged(
-      SpeechRecognizerState new_state) override;
-  void GetSpeechAuthParameters(std::string* auth_scope,
-                               std::string* auth_token) override {}
 
  protected:
   // Protected for testing.
@@ -112,10 +90,6 @@
   // getUserMedia() request from the web contents.
   class StartPageWebContentsDelegate;
 
-  // This class observes the change of audio input device availability and
-  // checks if currently the system has valid audio input.
-  class AudioStatus;
-
   // This class observes network change events and disables/enables voice search
   // based on network connectivity.
   class NetworkChangeObserver;
@@ -139,37 +113,21 @@
   void DidFinishNavigation(
       content::NavigationHandle* navigation_handle) override;
 
-  // Change the known microphone availability. |available| should be true if
-  // the microphone exists and is available for use.
-  void OnMicrophoneChanged(bool available);
   // Change the known network connectivity state. |available| should be true if
   // at least one network is connected to.
   void OnNetworkChanged(bool available);
-  // Enables/disables voice recognition based on network and microphone state.
-  void UpdateRecognitionState();
-  // Determines whether speech recognition should be enabled, based on the
-  // current state of the StartPageService.
-  bool ShouldEnableSpeechRecognition() const;
 
   Profile* profile_;
   std::unique_ptr<content::WebContents> contents_;
   std::unique_ptr<StartPageWebContentsDelegate> contents_delegate_;
   std::unique_ptr<ProfileDestroyObserver> profile_destroy_observer_;
-  SpeechRecognizerState state_;
-  base::ObserverList<StartPageObserver> observers_;
-  bool speech_button_toggled_manually_;
-  bool speech_result_obtained_;
 
   bool webui_finished_loading_;
   std::vector<base::Closure> pending_webui_callbacks_;
 
   base::DefaultClock clock_;
-  std::unique_ptr<SpeechRecognizer> speech_recognizer_;
-  std::unique_ptr<SpeechAuthHelper> speech_auth_helper_;
 
   bool network_available_;
-  bool microphone_available_;
-  std::unique_ptr<AudioStatus> audio_status_;
   std::unique_ptr<NetworkChangeObserver> network_change_observer_;
 
   bool search_engine_is_google_;
diff --git a/chrome/browser/ui/ash/app_list/app_list_presenter_delegate_mus.cc b/chrome/browser/ui/ash/app_list/app_list_presenter_delegate_mus.cc
index aef11f08..fd13e8a327 100644
--- a/chrome/browser/ui/ash/app_list/app_list_presenter_delegate_mus.cc
+++ b/chrome/browser/ui/ash/app_list/app_list_presenter_delegate_mus.cc
@@ -15,32 +15,6 @@
 #include "ui/views/mus/pointer_watcher_event_router.h"
 #include "ui/wm/core/window_util.h"
 
-namespace {
-
-// Gets the point at the center of the display. The calculation should exclude
-// the virtual keyboard area. If the height of the display area is less than
-// |minimum_height|, its bottom will be extended to that height (so that the
-// app list never starts above the top of the screen).
-gfx::Point GetCenterOfDisplay(int64_t display_id, int minimum_height) {
-  // TODO(mfomitchev): account for virtual keyboard.
-  std::vector<display::Display> displays =
-      display::Screen::GetScreen()->GetAllDisplays();
-  auto it = std::find_if(displays.begin(), displays.end(),
-                         [display_id](const display::Display& display) {
-                           return display.id() == display_id;
-                         });
-  DCHECK(it != displays.end());
-  gfx::Rect bounds = it->bounds();
-
-  // Apply the |minimum_height|.
-  if (bounds.height() < minimum_height)
-    bounds.set_height(minimum_height);
-
-  return bounds.CenterPoint();
-}
-
-}  // namespace
-
 AppListPresenterDelegateMus::AppListPresenterDelegateMus(
     app_list::AppListPresenterImpl* presenter,
     app_list::AppListViewDelegateFactory* view_delegate_factory)
@@ -72,9 +46,6 @@
   params.is_side_shelf = true;
   view->Initialize(params);
 
-  view->MaybeSetAnchorPoint(
-      GetCenterOfDisplay(display_id, GetMinimumBoundsHeightForAppList(view)));
-
   // TODO(mfomitchev): Setup updating bounds on keyboard bounds change.
   // TODO(mfomitchev): Setup dismissing on maximize (touch-view) mode start/end.
   // TODO(mfomitchev): Setup DnD.
@@ -93,13 +64,6 @@
   DCHECK(!presenter_->GetTargetVisibility());
 }
 
-void AppListPresenterDelegateMus::UpdateBounds() {
-  if (!view_ || !presenter_->GetTargetVisibility())
-    return;
-
-  view_->UpdateBounds();
-}
-
 gfx::Vector2d AppListPresenterDelegateMus::GetVisibilityAnimationOffset(
     aura::Window* root_window) {
   // TODO(mfomitchev): Classic ash does different animation here depending on
diff --git a/chrome/browser/ui/ash/app_list/app_list_presenter_delegate_mus.h b/chrome/browser/ui/ash/app_list/app_list_presenter_delegate_mus.h
index 3e3496d..f7f8a66e 100644
--- a/chrome/browser/ui/ash/app_list/app_list_presenter_delegate_mus.h
+++ b/chrome/browser/ui/ash/app_list/app_list_presenter_delegate_mus.h
@@ -34,7 +34,6 @@
             int current_apps_page) override;
   void OnShown(int64_t display_id) override;
   void OnDismissed() override;
-  void UpdateBounds() override;
   gfx::Vector2d GetVisibilityAnimationOffset(
       aura::Window* root_window) override;
   base::TimeDelta GetVisibilityAnimationDuration(aura::Window* root_window,
diff --git a/chrome/browser/ui/cocoa/page_info/page_info_bubble_controller.mm b/chrome/browser/ui/cocoa/page_info/page_info_bubble_controller.mm
index 6e435b5..38af117 100644
--- a/chrome/browser/ui/cocoa/page_info/page_info_bubble_controller.mm
+++ b/chrome/browser/ui/cocoa/page_info/page_info_bubble_controller.mm
@@ -1228,8 +1228,8 @@
       [label setFrameOrigin:point];
     }
 
-    label.textColor = skia::SkColorToSRGBNSColor(
-        PageInfoUI::GetPermissionDecisionTextColor());
+    label.textColor =
+        skia::SkColorToSRGBNSColor(PageInfoUI::GetSecondaryTextColor());
     point.y += NSHeight(label.frame);
   }
 
diff --git a/chrome/browser/ui/cocoa/status_bubble_mac.h b/chrome/browser/ui/cocoa/status_bubble_mac.h
index 10107f25b..8c03a306 100644
--- a/chrome/browser/ui/cocoa/status_bubble_mac.h
+++ b/chrome/browser/ui/cocoa/status_bubble_mac.h
@@ -12,6 +12,7 @@
 #include <stdint.h>
 
 #include "base/compiler_specific.h"
+#include "base/mac/scoped_nsobject.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "base/strings/string16.h"
@@ -23,6 +24,7 @@
 }
 
 class StatusBubbleMacTest;
+@class StatusBubbleWindow;
 
 class StatusBubbleMac : public StatusBubble {
  public:
@@ -91,7 +93,7 @@
 
   // Is the status bubble attached to the browser window? It should be attached
   // when shown and during any fades, but should be detached when hidden.
-  bool is_attached() { return [window_ parentWindow] != nil; }
+  bool is_attached();
 
   // Begins fading the status bubble window in or out depending on the value
   // of |show|.  This must be called from the appropriate fade state,
@@ -146,6 +148,9 @@
   // concerns.
   unsigned long OSDependentCornerFlags(NSRect window_frame);
 
+  // Returns the status bubble window as an NSWindow. For use in tests.
+  NSWindow* GetWindow();
+
   // The window we attach ourselves to.
   NSWindow* parent_;  // WEAK
 
@@ -153,7 +158,7 @@
   id delegate_;  // WEAK
 
   // The window we own.
-  NSWindow* window_;
+  base::scoped_nsobject<StatusBubbleWindow> window_;
 
   // The status text we want to display when there are no URLs to display.
   NSString* status_text_;
diff --git a/chrome/browser/ui/cocoa/status_bubble_mac.mm b/chrome/browser/ui/cocoa/status_bubble_mac.mm
index 3718bc8..f70d9ae 100644
--- a/chrome/browser/ui/cocoa/status_bubble_mac.mm
+++ b/chrome/browser/ui/cocoa/status_bubble_mac.mm
@@ -64,10 +64,100 @@
 
 }  // namespace
 
+// StatusBubbleWindow becomes a child of |statusBubbleParentWindow|, but waits
+// until |statusBubbleParentWindow| is visible. This works around macOS
+// bugs/features which make unexpected things happen when adding a child window
+// to a window that's in another space, miniaturized, or hidden
+// (https://crbug.com/783521, https://crbug.com/798792).
+@interface StatusBubbleWindow : NSWindow
+
+// The window which this window should become a child of. May be changed or
+// nilled out at any time.
+@property(assign, nonatomic) NSWindow* statusBubbleParentWindow;
+
+@end
+
+@implementation StatusBubbleWindow {
+  BOOL observingParentWindowVisibility_;
+}
+@synthesize statusBubbleParentWindow = statusBubbleParentWindow_;
+
+- (void)dealloc {
+  // StatusBubbleMac is expected to always clear statusBubbleParentWindow
+  // before releasing StatusBubbleWindow. If that changes, it's OK to remove
+  // this DCHECK as long as StatusBubbleWindow will never outlive its parent.
+  DCHECK(!statusBubbleParentWindow_);
+
+  [self stopObserving];
+  [super dealloc];
+}
+
+- (void)setStatusBubbleParentWindow:(NSWindow*)statusBubbleParentWindow {
+  if (statusBubbleParentWindow_ == statusBubbleParentWindow)
+    return;
+
+  // First, detach from the current parent window, if any.
+  if (statusBubbleParentWindow_) {
+    [self stopObserving];
+    [self orderOut:nil];  // Also removes |self| from its parent window.
+  }
+
+  // Assign the new parent window.
+  statusBubbleParentWindow_ = statusBubbleParentWindow;
+
+  if (statusBubbleParentWindow_) {
+    // Attach to the new parent window if it's visible and on the active space.
+    [self maybeAttach];
+
+    if (!self.parentWindow) {
+      // If maybeAttach bailed, start observing the window's visibility and the
+      // active space, and try again when they change.
+      observingParentWindowVisibility_ = YES;
+      [statusBubbleParentWindow_ addObserver:self
+                                  forKeyPath:@"visible"
+                                     options:0
+                                     context:nil];
+      [[NSWorkspace sharedWorkspace].notificationCenter
+          addObserver:self
+             selector:@selector(maybeAttach)
+                 name:NSWorkspaceActiveSpaceDidChangeNotification
+               object:[NSWorkspace sharedWorkspace]];
+    }
+  }
+}
+
+- (void)stopObserving {
+  if (!observingParentWindowVisibility_)
+    return;
+  observingParentWindowVisibility_ = NO;
+  [statusBubbleParentWindow_ removeObserver:self
+                                 forKeyPath:@"visible"
+                                    context:nil];
+  [[NSWorkspace sharedWorkspace].notificationCenter removeObserver:self];
+}
+
+- (void)maybeAttach {
+  if (![statusBubbleParentWindow_ isVisible])
+    return;
+  if (![statusBubbleParentWindow_ isOnActiveSpace])
+    return;
+  [self stopObserving];
+  // Adding |self| as a child window also orders it in.
+  [statusBubbleParentWindow_ addChildWindow:self ordered:NSWindowAbove];
+}
+
+- (void)observeValueForKeyPath:(NSString*)keyPath
+                      ofObject:(id)object
+                        change:(NSDictionary<NSKeyValueChangeKey, id>*)change
+                       context:(void*)context {
+  [self maybeAttach];
+}
+
+@end
+
 StatusBubbleMac::StatusBubbleMac(NSWindow* parent, id delegate)
     : parent_(parent),
       delegate_(delegate),
-      window_(nil),
       status_text_(nil),
       url_text_(nil),
       state_(kBubbleHidden),
@@ -86,8 +176,6 @@
 
   completion_handler_factory_.InvalidateWeakPtrs();
   Detach();
-  [window_ release];
-  window_ = nil;
 }
 
 void StatusBubbleMac::SetStatus(const base::string16& status) {
@@ -326,10 +414,11 @@
 void StatusBubbleMac::Create() {
   DCHECK(!window_);
 
-  window_ = [[NSWindow alloc] initWithContentRect:ui::kWindowSizeDeterminedLater
-                                        styleMask:NSBorderlessWindowMask
-                                          backing:NSBackingStoreBuffered
-                                            defer:NO];
+  window_.reset([[StatusBubbleWindow alloc]
+      initWithContentRect:ui::kWindowSizeDeterminedLater
+                styleMask:NSBorderlessWindowMask
+                  backing:NSBackingStoreBuffered
+                    defer:NO]);
   [window_ setCollectionBehavior:[window_ collectionBehavior] |
                                  NSWindowCollectionBehaviorTransient];
   [window_ setMovableByWindowBackground:NO];
@@ -354,7 +443,7 @@
 void StatusBubbleMac::Attach() {
   if (is_attached())
     return;
-  [parent_ addChildWindow:window_ ordered:NSWindowAbove];
+  [window_ setStatusBubbleParentWindow:parent_];
   [[window_ contentView] setThemeProvider:parent_];
 }
 
@@ -370,13 +459,17 @@
   if (state_ != kBubbleHidden) {
     frame = CalculateWindowFrame(/*expand=*/false);
   }
+  // See https://crbug.com/28107 and https://crbug.com/29054.
   [window_ setFrame:frame display:NO];
-  [parent_ removeChildWindow:window_];  // See crbug.com/28107 ...
-  [window_ orderOut:nil];               // ... and crbug.com/29054.
+  [window_ setStatusBubbleParentWindow:nil];
 
   [[window_ contentView] setThemeProvider:nil];
 }
 
+bool StatusBubbleMac::is_attached() {
+  return [window_ statusBubbleParentWindow] != nil;
+}
+
 void StatusBubbleMac::AnimationDidStop() {
   DCHECK([NSThread isMainThread]);
   DCHECK(state_ == kBubbleShowingFadeIn || state_ == kBubbleHidingFadeOut);
@@ -700,3 +793,7 @@
 
   return corner_flags;
 }
+
+NSWindow* StatusBubbleMac::GetWindow() {
+  return window_;
+}
diff --git a/chrome/browser/ui/cocoa/status_bubble_mac_unittest.mm b/chrome/browser/ui/cocoa/status_bubble_mac_unittest.mm
index 8714c1cb..b31159f8 100644
--- a/chrome/browser/ui/cocoa/status_bubble_mac_unittest.mm
+++ b/chrome/browser/ui/cocoa/status_bubble_mac_unittest.mm
@@ -93,7 +93,7 @@
  public:
   void SetUp() override {
     CocoaTest::SetUp();
-    NSWindow* window = test_window();
+    CocoaTestHelperWindow* window = test_window();
     EXPECT_TRUE(window);
     delegate_.reset(
         [[StatusBubbleMacTestDelegate alloc] initWithWindow: window]);
@@ -133,7 +133,7 @@
     BubbleView* bubbleView = [bubble_->window_ contentView];
     return [bubbleView content];
   }
-  NSWindow* GetWindow() { return bubble_->window_; }
+  NSWindow* GetWindow() { return bubble_->GetWindow(); }
   NSWindow* parent() {
     return bubble_->parent_;
   }
@@ -679,3 +679,21 @@
   bubble_->SetStatus(UTF8ToUTF16("Showing"));
   bubble_->SwitchParentWindow(test_window());
 }
+
+TEST_F(StatusBubbleMacTest, WaitsUntilVisible) {
+  [test_window() orderOut:nil];
+  bubble_->SetStatus(UTF8ToUTF16("Show soon"));
+  EXPECT_NSEQ(nil, GetWindow().parentWindow);
+
+  [test_window() orderBack:nil];
+  EXPECT_NSNE(nil, GetWindow().parentWindow);
+}
+
+TEST_F(StatusBubbleMacTest, WaitsUntilOnActiveSpace) {
+  test_window().pretendIsOnActiveSpace = NO;
+  bubble_->SetStatus(UTF8ToUTF16("Show soon"));
+  EXPECT_NSEQ(nil, GetWindow().parentWindow);
+
+  test_window().pretendIsOnActiveSpace = YES;
+  EXPECT_NSNE(nil, GetWindow().parentWindow);
+}
diff --git a/chrome/browser/ui/page_info/page_info.cc b/chrome/browser/ui/page_info/page_info.cc
index 1f4606c..d39a79f4 100644
--- a/chrome/browser/ui/page_info/page_info.cc
+++ b/chrome/browser/ui/page_info/page_info.cc
@@ -320,7 +320,8 @@
 // email security-dev@chromium.org.
 const PageInfo::ChooserUIInfo kChooserUIInfo[] = {
     {CONTENT_SETTINGS_TYPE_USB_CHOOSER_DATA, &GetUsbChooserContext,
-     IDS_PAGE_INFO_USB_DEVICE_LABEL, IDS_PAGE_INFO_DELETE_USB_DEVICE, "name"},
+     IDS_PAGE_INFO_USB_DEVICE_LABEL, IDS_PAGE_INFO_USB_DEVICE_SECONDARY_LABEL,
+     IDS_PAGE_INFO_DELETE_USB_DEVICE, "name"},
 };
 
 }  // namespace
diff --git a/chrome/browser/ui/page_info/page_info.h b/chrome/browser/ui/page_info/page_info.h
index 59031e8..79e0fa8 100644
--- a/chrome/browser/ui/page_info/page_info.h
+++ b/chrome/browser/ui/page_info/page_info.h
@@ -127,6 +127,7 @@
     ContentSettingsType content_settings_type;
     ChooserContextBase* (*get_context)(Profile*);
     int label_string_id;
+    int secondary_label_string_id;
     int delete_tooltip_string_id;
     const char* ui_name_key;
   };
diff --git a/chrome/browser/ui/page_info/page_info_ui.cc b/chrome/browser/ui/page_info/page_info_ui.cc
index e58ddec2..5a0ae1d 100644
--- a/chrome/browser/ui/page_info/page_info_ui.cc
+++ b/chrome/browser/ui/page_info/page_info_ui.cc
@@ -355,7 +355,7 @@
 }
 
 // static
-SkColor PageInfoUI::GetPermissionDecisionTextColor() {
+SkColor PageInfoUI::GetSecondaryTextColor() {
   return SK_ColorGRAY;
 }
 
diff --git a/chrome/browser/ui/page_info/page_info_ui.h b/chrome/browser/ui/page_info/page_info_ui.h
index b783404..60c0e8d 100644
--- a/chrome/browser/ui/page_info/page_info_ui.h
+++ b/chrome/browser/ui/page_info/page_info_ui.h
@@ -168,7 +168,7 @@
       const GURL& url);
 
   // Returns the color to use for the permission decision reason strings.
-  static SkColor GetPermissionDecisionTextColor();
+  static SkColor GetSecondaryTextColor();
 
   // Returns the UI string describing the given object |info|.
   static base::string16 ChosenObjectToUIString(const ChosenObjectInfo& info);
diff --git a/chrome/browser/ui/search/new_tab_page_interceptor_browsertest.cc b/chrome/browser/ui/search/new_tab_page_interceptor_browsertest.cc
deleted file mode 100644
index 0e1bdc7..0000000
--- a/chrome/browser/ui/search/new_tab_page_interceptor_browsertest.cc
+++ /dev/null
@@ -1,111 +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 <memory>
-
-#include "base/files/file_path.h"
-#include "base/strings/utf_string_conversions.h"
-#include "chrome/browser/browser_process.h"
-#include "chrome/browser/search/search.h"
-#include "chrome/browser/search_engines/template_url_service_factory.h"
-#include "chrome/browser/search_engines/ui_thread_search_terms_data.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/tabs/tab_strip_model.h"
-#include "chrome/common/url_constants.h"
-#include "chrome/test/base/in_process_browser_test.h"
-#include "chrome/test/base/search_test_utils.h"
-#include "chrome/test/base/ui_test_utils.h"
-#include "components/search_engines/template_url_service.h"
-#include "content/public/browser/navigation_controller.h"
-#include "content/public/browser/navigation_entry.h"
-#include "content/public/browser/web_contents.h"
-#include "net/test/embedded_test_server/embedded_test_server.h"
-#include "net/test/url_request/url_request_mock_http_job.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "url/gurl.h"
-
-using content::BrowserThread;
-
-class NewTabPageInterceptorTest : public InProcessBrowserTest {
- public:
-  NewTabPageInterceptorTest() {}
-
-  void SetUpOnMainThread() override {
-    base::FilePath path =
-        ui_test_utils::GetTestFilePath(base::FilePath(), base::FilePath());
-    BrowserThread::PostTask(
-        BrowserThread::IO, FROM_HERE,
-        base::BindOnce(&net::URLRequestMockHTTPJob::AddUrlHandlers, path));
-  }
-
-  void ChangeDefaultSearchProvider(const char* new_tab_path) {
-    TemplateURLService* template_url_service =
-        TemplateURLServiceFactory::GetForProfile(browser()->profile());
-    search_test_utils::WaitForTemplateURLServiceToLoad(template_url_service);
-    UIThreadSearchTermsData::SetGoogleBaseURL("https://mock.http/");
-    std::string base_url("{google:baseURL}");
-    TemplateURLData data;
-    data.SetShortName(base::ASCIIToUTF16("Google"));
-    data.SetKeyword(base::UTF8ToUTF16(base_url));
-    data.SetURL(base_url + "url?bar={searchTerms}");
-    data.new_tab_url = base_url + new_tab_path;
-    TemplateURL* template_url =
-        template_url_service->Add(std::make_unique<TemplateURL>(data));
-    template_url_service->SetUserSelectedDefaultSearchProvider(template_url);
-  }
-};
-
-IN_PROC_BROWSER_TEST_F(NewTabPageInterceptorTest, NoInterception) {
-  net::EmbeddedTestServer https_test_server(
-      net::EmbeddedTestServer::TYPE_HTTPS);
-  ASSERT_TRUE(https_test_server.Start());
-  GURL new_tab_url = https_test_server.GetURL("/instant_extended.html");
-  ChangeDefaultSearchProvider("instant_extended.html");
-
-  ui_test_utils::NavigateToURL(browser(), new_tab_url);
-  content::WebContents* contents =
-      browser()->tab_strip_model()->GetWebContentsAt(0);
-  // A correct, 200-OK file works correctly.
-  EXPECT_EQ(new_tab_url,
-            contents->GetController().GetLastCommittedEntry()->GetURL());
-}
-
-IN_PROC_BROWSER_TEST_F(NewTabPageInterceptorTest, 404Interception) {
-  GURL new_tab_url =
-      net::URLRequestMockHTTPJob::GetMockHttpsUrl("page404.html");
-  ChangeDefaultSearchProvider("page404.html");
-
-  ui_test_utils::NavigateToURL(browser(), new_tab_url);
-  content::WebContents* contents =
-      browser()->tab_strip_model()->GetWebContentsAt(0);
-  // 404 makes a redirect to the local NTP.
-  EXPECT_EQ(GURL(chrome::kChromeSearchLocalNtpUrl),
-            contents->GetController().GetLastCommittedEntry()->GetURL());
-}
-
-IN_PROC_BROWSER_TEST_F(NewTabPageInterceptorTest, 204Interception) {
-  GURL new_tab_url =
-      net::URLRequestMockHTTPJob::GetMockHttpsUrl("page204.html");
-  ChangeDefaultSearchProvider("page204.html");
-
-  ui_test_utils::NavigateToURL(browser(), new_tab_url);
-  content::WebContents* contents =
-      browser()->tab_strip_model()->GetWebContentsAt(0);
-  // 204 makes a redirect to the local NTP.
-  EXPECT_EQ(GURL(chrome::kChromeSearchLocalNtpUrl),
-            contents->GetController().GetLastCommittedEntry()->GetURL());
-}
-
-IN_PROC_BROWSER_TEST_F(NewTabPageInterceptorTest, FailedRequestInterception) {
-  GURL new_tab_url =
-      net::URLRequestMockHTTPJob::GetMockHttpsUrl("notarealfile.html");
-  ChangeDefaultSearchProvider("notarealfile.html");
-
-  ui_test_utils::NavigateToURL(browser(), new_tab_url);
-  content::WebContents* contents =
-      browser()->tab_strip_model()->GetWebContentsAt(0);
-  // Failed navigation makes a redirect to the local NTP.
-  EXPECT_EQ(GURL(chrome::kChromeSearchLocalNtpUrl),
-            contents->GetController().GetLastCommittedEntry()->GetURL());
-}
diff --git a/chrome/browser/ui/search/new_tab_page_interceptor_service.cc b/chrome/browser/ui/search/new_tab_page_interceptor_service.cc
deleted file mode 100644
index 44d2b031..0000000
--- a/chrome/browser/ui/search/new_tab_page_interceptor_service.cc
+++ /dev/null
@@ -1,130 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/ui/search/new_tab_page_interceptor_service.h"
-
-#include <utility>
-
-#include "base/location.h"
-#include "base/logging.h"
-#include "base/macros.h"
-#include "base/metrics/histogram_macros.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/search/search.h"
-#include "chrome/browser/search_engines/template_url_service_factory.h"
-#include "chrome/common/url_constants.h"
-#include "components/search_engines/template_url_service.h"
-#include "content/public/browser/browser_thread.h"
-#include "net/base/net_errors.h"
-#include "net/http/http_status_code.h"
-#include "net/url_request/url_request.h"
-#include "net/url_request/url_request_interceptor.h"
-#include "net/url_request/url_request_job.h"
-#include "net/url_request/url_request_redirect_job.h"
-#include "url/gurl.h"
-
-// Implementation of the URLRequestInterceptor for the New Tab Page. Will look
-// at incoming response from the server and possibly divert to the local NTP.
-class NewTabPageInterceptor : public net::URLRequestInterceptor {
- public:
-  explicit NewTabPageInterceptor(const GURL& new_tab_url)
-      : new_tab_url_(new_tab_url), weak_factory_(this) {
-    DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  }
-
-  ~NewTabPageInterceptor() override {
-    DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
-  }
-
-  base::WeakPtr<NewTabPageInterceptor> GetWeakPtr() {
-    DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-    return weak_factory_.GetWeakPtr();
-  }
-
-  void SetNewTabPageURL(const GURL& new_tab_page_url) {
-    DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
-    new_tab_url_ = new_tab_page_url;
-  }
-
- private:
-  // Overrides from net::URLRequestInterceptor:
-  net::URLRequestJob* MaybeInterceptRequest(
-      net::URLRequest* request,
-      net::NetworkDelegate* network_delegate) const override {
-    DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
-    return nullptr;
-  }
-
-  net::URLRequestJob* MaybeInterceptResponse(
-      net::URLRequest* request,
-      net::NetworkDelegate* network_delegate) const override {
-    DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
-    if ((request->url() != new_tab_url_) ||
-        (new_tab_url_ == chrome::kChromeSearchLocalNtpUrl)) {
-      return nullptr;
-    }
-    // User has canceled this navigation so it shouldn't be redirected.
-    // TODO(maksims): Remove request->status() and use int net_error
-    // once MaybeInterceptResponse() starts to pass that.
-    if (request->status().status() == net::URLRequestStatus::CANCELED ||
-        (request->status().status() == net::URLRequestStatus::FAILED &&
-         request->status().error() == net::ERR_ABORTED)) {
-      return nullptr;
-    }
-
-    // Request to NTP was successful.
-    // TODO(maksims): Remove request->status() and use int net_error
-    // once MaybeInterceptResponse() starts to pass that.
-    if (request->status().is_success() &&
-        request->GetResponseCode() != net::HTTP_NO_CONTENT &&
-        request->GetResponseCode() < 400) {
-      return nullptr;
-    }
-
-    // Failure to load the NTP correctly; redirect to Local NTP.
-    UMA_HISTOGRAM_ENUMERATION("InstantExtended.CacheableNTPLoad",
-                              search::CACHEABLE_NTP_LOAD_FAILED,
-                              search::CACHEABLE_NTP_LOAD_MAX);
-    return new net::URLRequestRedirectJob(
-        request, network_delegate, GURL(chrome::kChromeSearchLocalNtpUrl),
-        net::URLRequestRedirectJob::REDIRECT_307_TEMPORARY_REDIRECT,
-        "NTP Request Interceptor");
-  }
-
-  GURL new_tab_url_;
-  base::WeakPtrFactory<NewTabPageInterceptor> weak_factory_;
-
-  DISALLOW_COPY_AND_ASSIGN(NewTabPageInterceptor);
-};
-
-NewTabPageInterceptorService::NewTabPageInterceptorService(Profile* profile)
-    : profile_(profile),
-      template_url_service_(TemplateURLServiceFactory::GetForProfile(profile)) {
-  DCHECK(profile_);
-  if (template_url_service_)
-    template_url_service_->AddObserver(this);
-}
-
-NewTabPageInterceptorService::~NewTabPageInterceptorService() {
-  if (template_url_service_)
-    template_url_service_->RemoveObserver(this);
-}
-
-void NewTabPageInterceptorService::OnTemplateURLServiceChanged() {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  GURL new_tab_page_url(search::GetNewTabPageURL(profile_));
-  content::BrowserThread::PostTask(
-      content::BrowserThread::IO, FROM_HERE,
-      base::BindOnce(&NewTabPageInterceptor::SetNewTabPageURL, interceptor_,
-                     new_tab_page_url));
-}
-
-std::unique_ptr<net::URLRequestInterceptor>
-NewTabPageInterceptorService::CreateInterceptor() {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  std::unique_ptr<NewTabPageInterceptor> interceptor(
-      new NewTabPageInterceptor(search::GetNewTabPageURL(profile_)));
-  interceptor_ = interceptor->GetWeakPtr();
-  return std::move(interceptor);
-}
diff --git a/chrome/browser/ui/search/new_tab_page_interceptor_service.h b/chrome/browser/ui/search/new_tab_page_interceptor_service.h
deleted file mode 100644
index ff5f22c..0000000
--- a/chrome/browser/ui/search/new_tab_page_interceptor_service.h
+++ /dev/null
@@ -1,46 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_UI_SEARCH_NEW_TAB_PAGE_INTERCEPTOR_SERVICE_H_
-#define CHROME_BROWSER_UI_SEARCH_NEW_TAB_PAGE_INTERCEPTOR_SERVICE_H_
-
-#include <memory>
-
-#include "base/macros.h"
-#include "base/memory/weak_ptr.h"
-#include "components/keyed_service/core/keyed_service.h"
-#include "components/search_engines/template_url_service_observer.h"
-
-class NewTabPageInterceptor;
-class Profile;
-class TemplateURLService;
-
-namespace net {
-class URLRequestInterceptor;
-}
-
-// Owns a NewTabPageInterceptor.
-class NewTabPageInterceptorService : public KeyedService,
-                                     public TemplateURLServiceObserver {
- public:
-  explicit NewTabPageInterceptorService(Profile* profile);
-  ~NewTabPageInterceptorService() override;
-
-  // TemplateURLServiceObserver override.
-  void OnTemplateURLServiceChanged() override;
-
-  std::unique_ptr<net::URLRequestInterceptor> CreateInterceptor();
-
- private:
-  Profile* profile_;
-  base::WeakPtr<NewTabPageInterceptor> interceptor_;
-  // The TemplateURLService that we are observing. It will outlive this
-  // NewTabPageInterceptorService due to the dependency declared in
-  // NewTabPageInterceptorServiceFactory.
-  TemplateURLService* template_url_service_;
-
-  DISALLOW_COPY_AND_ASSIGN(NewTabPageInterceptorService);
-};
-
-#endif  // CHROME_BROWSER_UI_SEARCH_NEW_TAB_PAGE_INTERCEPTOR_SERVICE_H_
diff --git a/chrome/browser/ui/search/new_tab_page_interceptor_service_factory.cc b/chrome/browser/ui/search/new_tab_page_interceptor_service_factory.cc
deleted file mode 100644
index 0aa11814..0000000
--- a/chrome/browser/ui/search/new_tab_page_interceptor_service_factory.cc
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/ui/search/new_tab_page_interceptor_service_factory.h"
-
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/search/instant_service_factory.h"
-#include "chrome/browser/search_engines/template_url_service_factory.h"
-#include "chrome/browser/ui/search/new_tab_page_interceptor_service.h"
-#include "components/keyed_service/content/browser_context_dependency_manager.h"
-#include "content/public/browser/browser_thread.h"
-
-// static
-NewTabPageInterceptorServiceFactory*
-NewTabPageInterceptorServiceFactory::GetInstance() {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  return base::Singleton<NewTabPageInterceptorServiceFactory>::get();
-}
-
-// static
-NewTabPageInterceptorService*
-NewTabPageInterceptorServiceFactory::GetForProfile(Profile* profile) {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  if (profile->IsOffTheRecord())
-    return nullptr;
-
-  return static_cast<NewTabPageInterceptorService*>(
-      GetInstance()->GetServiceForBrowserContext(profile, true));
-}
-
-NewTabPageInterceptorServiceFactory::NewTabPageInterceptorServiceFactory()
-    : BrowserContextKeyedServiceFactory(
-          "NTP Request Interceptor Service Factory",
-          BrowserContextDependencyManager::GetInstance()) {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  DependsOn(TemplateURLServiceFactory::GetInstance());
-}
-
-NewTabPageInterceptorServiceFactory::~NewTabPageInterceptorServiceFactory() {
-}
-
-KeyedService* NewTabPageInterceptorServiceFactory::BuildServiceInstanceFor(
-    content::BrowserContext* context) const {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  Profile* profile = Profile::FromBrowserContext(context);
-  return new NewTabPageInterceptorService(profile);
-}
diff --git a/chrome/browser/ui/search/new_tab_page_interceptor_service_factory.h b/chrome/browser/ui/search/new_tab_page_interceptor_service_factory.h
deleted file mode 100644
index 37dee82c..0000000
--- a/chrome/browser/ui/search/new_tab_page_interceptor_service_factory.h
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_UI_SEARCH_NEW_TAB_PAGE_INTERCEPTOR_SERVICE_FACTORY_H_
-#define CHROME_BROWSER_UI_SEARCH_NEW_TAB_PAGE_INTERCEPTOR_SERVICE_FACTORY_H_
-
-#include "base/macros.h"
-#include "base/memory/singleton.h"
-#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
-#include "components/keyed_service/core/keyed_service.h"
-
-class NewTabPageInterceptorService;
-class Profile;
-
-namespace content {
-class BrowserContext;
-}
-
-// Owns and creates NewTabPageInterceptorService instances.
-class NewTabPageInterceptorServiceFactory
-    : public BrowserContextKeyedServiceFactory {
- public:
-  static NewTabPageInterceptorService* GetForProfile(Profile* profile);
-  static NewTabPageInterceptorServiceFactory* GetInstance();
-
- private:
-  friend struct base::DefaultSingletonTraits<
-      NewTabPageInterceptorServiceFactory>;
-
-  NewTabPageInterceptorServiceFactory();
-  ~NewTabPageInterceptorServiceFactory() override;
-
-  // BrowserContextKeyedServiceFactory:
-  KeyedService* BuildServiceInstanceFor(
-      content::BrowserContext* context) const override;
-
-  DISALLOW_COPY_AND_ASSIGN(NewTabPageInterceptorServiceFactory);
-};
-
-#endif  // CHROME_BROWSER_UI_SEARCH_NEW_TAB_PAGE_INTERCEPTOR_SERVICE_FACTORY_H_
diff --git a/chrome/browser/ui/search/new_tab_page_navigation_throttle.cc b/chrome/browser/ui/search/new_tab_page_navigation_throttle.cc
new file mode 100644
index 0000000..b964991
--- /dev/null
+++ b/chrome/browser/ui/search/new_tab_page_navigation_throttle.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 "chrome/browser/ui/search/new_tab_page_navigation_throttle.h"
+
+#include "base/metrics/histogram_macros.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/search/search.h"
+#include "chrome/common/url_constants.h"
+#include "content/public/browser/navigation_handle.h"
+#include "content/public/browser/web_contents.h"
+#include "net/http/http_status_code.h"
+#include "url/gurl.h"
+
+NewTabPageNavigationThrottle::NewTabPageNavigationThrottle(
+    content::NavigationHandle* navigation_handle)
+    : content::NavigationThrottle(navigation_handle) {}
+
+NewTabPageNavigationThrottle::~NewTabPageNavigationThrottle() = default;
+
+const char* NewTabPageNavigationThrottle::GetNameForLogging() {
+  return "NewTabPageNavigationThrottle";
+}
+
+// static
+std::unique_ptr<content::NavigationThrottle>
+NewTabPageNavigationThrottle::MaybeCreateThrottleFor(
+    content::NavigationHandle* handle) {
+  content::WebContents* web_contents = handle->GetWebContents();
+  Profile* profile =
+      Profile::FromBrowserContext(web_contents->GetBrowserContext());
+  if (web_contents->GetVisibleURL() != chrome::kChromeUINewTabURL ||
+      !search::IsInstantNTPURL(handle->GetURL(), profile) ||
+      handle->GetURL() == chrome::kChromeSearchLocalNtpUrl) {
+    return nullptr;
+  }
+
+  return std::make_unique<NewTabPageNavigationThrottle>(handle);
+}
+
+content::NavigationThrottle::ThrottleCheckResult
+NewTabPageNavigationThrottle::WillProcessResponse() {
+  const net::HttpResponseHeaders* headers =
+      navigation_handle()->GetResponseHeaders();
+  if (!headers)
+    return content::NavigationThrottle::PROCEED;
+
+  int response_code = headers->response_code();
+  if (response_code < 400 && response_code != net::HTTP_NO_CONTENT)
+    return content::NavigationThrottle::PROCEED;
+
+  return OpenLocalNewTabPage();
+}
+
+content::NavigationThrottle::ThrottleCheckResult
+NewTabPageNavigationThrottle::WillFailRequest() {
+  return OpenLocalNewTabPage();
+}
+
+content::NavigationThrottle::ThrottleCheckResult
+NewTabPageNavigationThrottle::OpenLocalNewTabPage() {
+  UMA_HISTOGRAM_ENUMERATION("InstantExtended.CacheableNTPLoad",
+                            search::CACHEABLE_NTP_LOAD_FAILED,
+                            search::CACHEABLE_NTP_LOAD_MAX);
+  navigation_handle()->GetWebContents()->OpenURL(
+      content::OpenURLParams(GURL(chrome::kChromeSearchLocalNtpUrl),
+                             navigation_handle()->GetReferrer(),
+                             navigation_handle()->GetFrameTreeNodeId(),
+                             WindowOpenDisposition::CURRENT_TAB,
+                             navigation_handle()->GetPageTransition(),
+                             false /* is_renderer_initiated */));
+  return content::NavigationThrottle::CANCEL_AND_IGNORE;
+}
diff --git a/chrome/browser/ui/search/new_tab_page_navigation_throttle.h b/chrome/browser/ui/search/new_tab_page_navigation_throttle.h
new file mode 100644
index 0000000..be0498b
--- /dev/null
+++ b/chrome/browser/ui/search/new_tab_page_navigation_throttle.h
@@ -0,0 +1,38 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_SEARCH_NEW_TAB_PAGE_NAVIGATION_THROTTLE_H_
+#define CHROME_BROWSER_UI_SEARCH_NEW_TAB_PAGE_NAVIGATION_THROTTLE_H_
+
+#include <memory>
+
+#include "content/public/browser/navigation_throttle.h"
+
+namespace content {
+class NavigationHandle;
+}  // namespace content
+
+// A NavigationThrottle that opens the local New Tab Page when there is any
+// issue opening the remote New Tab Page.
+class NewTabPageNavigationThrottle : public content::NavigationThrottle {
+ public:
+  // Returns a NavigationThrottle when:
+  // - we are navigating to the new tab page, and
+  // - the main frame is pointed at the new tab URL.
+  static std::unique_ptr<content::NavigationThrottle> MaybeCreateThrottleFor(
+      content::NavigationHandle* handle);
+
+  explicit NewTabPageNavigationThrottle(content::NavigationHandle* handle);
+  ~NewTabPageNavigationThrottle() override;
+
+  // content::NavigationThrottle:
+  ThrottleCheckResult WillFailRequest() override;
+  ThrottleCheckResult WillProcessResponse() override;
+  const char* GetNameForLogging() override;
+
+ private:
+  ThrottleCheckResult OpenLocalNewTabPage();
+};
+
+#endif  // CHROME_BROWSER_UI_SEARCH_NEW_TAB_PAGE_NAVIGATION_THROTTLE_H_
diff --git a/chrome/browser/ui/search/new_tab_page_navigation_throttle_browsertest.cc b/chrome/browser/ui/search/new_tab_page_navigation_throttle_browsertest.cc
new file mode 100644
index 0000000..dc40271c
--- /dev/null
+++ b/chrome/browser/ui/search/new_tab_page_navigation_throttle_browsertest.cc
@@ -0,0 +1,97 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/search/search.h"
+#include "chrome/browser/search_engines/template_url_service_factory.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/search/local_ntp_test_utils.h"
+#include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/common/chrome_paths.h"
+#include "chrome/common/url_constants.h"
+#include "chrome/test/base/in_process_browser_test.h"
+#include "chrome/test/base/search_test_utils.h"
+#include "chrome/test/base/ui_test_utils.h"
+#include "components/search_engines/template_url_service.h"
+#include "content/public/browser/navigation_entry.h"
+#include "content/public/browser/web_contents.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
+#include "url/gurl.h"
+
+namespace {
+
+class NewTabPageNavigationThrottleTest : public InProcessBrowserTest {
+ public:
+  NewTabPageNavigationThrottleTest()
+      : https_test_server_(net::EmbeddedTestServer::TYPE_HTTPS) {
+    https_test_server()->AddDefaultHandlers(
+        base::FilePath(FILE_PATH_LITERAL("chrome/test/data")));
+  }
+
+  void SetNewTabPage(const std::string& ntp_url) {
+    // Set the new tab page.
+    local_ntp_test_utils::SetUserSelectedDefaultSearchProvider(
+        browser()->profile(), https_test_server()->base_url().spec(), ntp_url);
+
+    // Ensure we are using the newly set new_tab_url and won't be directed
+    // to the local new tab page.
+    TemplateURLService* service =
+        TemplateURLServiceFactory::GetForProfile(browser()->profile());
+    search_test_utils::WaitForTemplateURLServiceToLoad(service);
+    ASSERT_EQ(search::GetNewTabPageURL(browser()->profile()), ntp_url);
+  }
+
+  // Navigates to the New Tab Page and then returns the GURL that ultimately was
+  // navigated to.
+  GURL NavigateToNewTabPage() {
+    ui_test_utils::NavigateToURL(browser(), GURL(chrome::kChromeUINewTabURL));
+    content::WebContents* contents =
+        browser()->tab_strip_model()->GetWebContentsAt(0);
+    return contents->GetController().GetLastCommittedEntry()->GetURL();
+  }
+
+  net::EmbeddedTestServer* https_test_server() { return &https_test_server_; }
+
+  net::EmbeddedTestServer https_test_server_;
+};
+
+IN_PROC_BROWSER_TEST_F(NewTabPageNavigationThrottleTest, NoThrottle) {
+  ASSERT_TRUE(https_test_server()->Start());
+  std::string ntp_url =
+      https_test_server()->GetURL("/instant_extended.html").spec();
+  SetNewTabPage(ntp_url);
+  // A correct, 200-OK file works correctly.
+  EXPECT_EQ(ntp_url, NavigateToNewTabPage());
+}
+
+IN_PROC_BROWSER_TEST_F(NewTabPageNavigationThrottleTest,
+                       FailedRequestThrottle) {
+  ASSERT_TRUE(https_test_server()->Start());
+  SetNewTabPage(https_test_server()->GetURL("/instant_extended.html").spec());
+  ASSERT_TRUE(https_test_server()->ShutdownAndWaitUntilComplete());
+  // Failed navigation makes a redirect to the local NTP.
+  EXPECT_EQ(chrome::kChromeSearchLocalNtpUrl, NavigateToNewTabPage());
+}
+
+IN_PROC_BROWSER_TEST_F(NewTabPageNavigationThrottleTest, LocalNewTabPage) {
+  ASSERT_TRUE(https_test_server()->Start());
+  SetNewTabPage(chrome::kChromeSearchLocalNtpUrl);
+  // Already going to the local NTP, so we should arrive there as expected.
+  EXPECT_EQ(chrome::kChromeSearchLocalNtpUrl, NavigateToNewTabPage());
+}
+
+IN_PROC_BROWSER_TEST_F(NewTabPageNavigationThrottleTest, 404Throttle) {
+  ASSERT_TRUE(https_test_server()->Start());
+  SetNewTabPage(https_test_server()->GetURL("/page404.html").spec());
+  // 404 makes a redirect to the local NTP.
+  EXPECT_EQ(chrome::kChromeSearchLocalNtpUrl, NavigateToNewTabPage());
+}
+
+IN_PROC_BROWSER_TEST_F(NewTabPageNavigationThrottleTest, 204Throttle) {
+  ASSERT_TRUE(https_test_server()->Start());
+  SetNewTabPage(https_test_server()->GetURL("/page204.html").spec());
+  // 204 makes a redirect to the local NTP.
+  EXPECT_EQ(chrome::kChromeSearchLocalNtpUrl, NavigateToNewTabPage());
+}
+
+}  // namespace
diff --git a/chrome/browser/ui/sync/one_click_signin_sync_starter.cc b/chrome/browser/ui/sync/one_click_signin_sync_starter.cc
index bd917010..4a0b19f 100644
--- a/chrome/browser/ui/sync/one_click_signin_sync_starter.cc
+++ b/chrome/browser/ui/sync/one_click_signin_sync_starter.cc
@@ -311,9 +311,9 @@
       break;
     }
     case Profile::CREATE_STATUS_INITIALIZED:
-        // Pre-DICE, the refresh token is copied to the new profile and the user
-        // does not need to autehnticate in the new profile.
-        CopyCredentialsToNewProfileAndFinishSignin(new_profile);
+      // Pre-DICE, the refresh token is copied to the new profile and the user
+      // does not need to autehnticate in the new profile.
+      CopyCredentialsToNewProfileAndFinishSignin(new_profile);
       break;
     case Profile::CREATE_STATUS_REMOTE_FAIL:
     case Profile::CREATE_STATUS_CANCELED:
diff --git a/chrome/browser/ui/views/find_bar_views_interactive_uitest.cc b/chrome/browser/ui/views/find_bar_views_interactive_uitest.cc
index 2833d86..7bc0fefc 100644
--- a/chrome/browser/ui/views/find_bar_views_interactive_uitest.cc
+++ b/chrome/browser/ui/views/find_bar_views_interactive_uitest.cc
@@ -509,7 +509,13 @@
   EXPECT_TRUE(details.number_of_matches() > 0);
 }
 
-IN_PROC_BROWSER_TEST_F(FindInPageTest, CtrlEnter) {
+// Slow flakiness on Linux. crbug.com/803743
+#if defined(OS_LINUX)
+#define MAYBE_CtrlEnter DISABLED_CtrlEnter
+#else
+#define MAYBE_CtrlEnter CtrlEnter
+#endif
+IN_PROC_BROWSER_TEST_F(FindInPageTest, MAYBE_CtrlEnter) {
   ui_test_utils::NavigateToURL(browser(),
                                GURL("data:text/html,This is some text with a "
                                     "<a href=\"about:blank\">link</a>."));
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 eb8e3d4..ab55a514 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
@@ -63,8 +63,8 @@
     SkColorSetARGBMacro(0xff, 0x25, 0x4f, 0xae);
 
 bool IsV1AppBackButtonEnabled() {
-  return !base::CommandLine::ForCurrentProcess()->HasSwitch(
-      ash::switches::kAshDisableV1AppBackButton);
+  return base::CommandLine::ForCurrentProcess()->HasSwitch(
+      ash::switches::kAshEnableV1AppBackButton);
 }
 
 }  // namespace
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.h b/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.h
index da83bad..bc43040 100644
--- a/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.h
+++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.h
@@ -91,7 +91,8 @@
   FRIEND_TEST_ALL_PREFIXES(BrowserNonClientFrameViewAshTest,
                            AvatarDisplayOnTeleportedWindow);
   FRIEND_TEST_ALL_PREFIXES(HostedAppNonClientFrameViewAshTest, HostedAppFrame);
-  FRIEND_TEST_ALL_PREFIXES(BrowserNonClientFrameViewAshTest, V1BackButton);
+  FRIEND_TEST_ALL_PREFIXES(BrowserNonClientFrameViewAshBackButtonTest,
+                           V1BackButton);
   FRIEND_TEST_ALL_PREFIXES(ImmersiveModeControllerAshHostedAppBrowserTest,
                            FrameLayout);
 
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash_browsertest.cc b/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash_browsertest.cc
index 642c00ee..1dcfd95f 100644
--- a/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash_browsertest.cc
+++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash_browsertest.cc
@@ -571,8 +571,26 @@
             frame_header->app_and_domain_render_text_->display_rect());
 }
 
+namespace {
+
+class BrowserNonClientFrameViewAshBackButtonTest : public InProcessBrowserTest {
+ public:
+  BrowserNonClientFrameViewAshBackButtonTest() = default;
+  ~BrowserNonClientFrameViewAshBackButtonTest() override = default;
+
+  void SetUpCommandLine(base::CommandLine* command_line) override {
+    command_line->AppendSwitch(ash::switches::kAshEnableV1AppBackButton);
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(BrowserNonClientFrameViewAshBackButtonTest);
+};
+
+}  // namespace
+
 // Test if the V1 apps' frame has a back button.
-IN_PROC_BROWSER_TEST_F(BrowserNonClientFrameViewAshTest, V1BackButton) {
+IN_PROC_BROWSER_TEST_F(BrowserNonClientFrameViewAshBackButtonTest,
+                       V1BackButton) {
   browser()->window()->Close();
 
   // Open a new app window.
diff --git a/chrome/browser/ui/views/infobars/confirm_infobar.cc b/chrome/browser/ui/views/infobars/confirm_infobar.cc
index 46fa954..a2e00d8 100644
--- a/chrome/browser/ui/views/infobars/confirm_infobar.cc
+++ b/chrome/browser/ui/views/infobars/confirm_infobar.cc
@@ -11,7 +11,6 @@
 #include "chrome/browser/infobars/infobar_service.h"
 #include "chrome/browser/ui/views/elevation_icon_setter.h"
 #include "chrome/browser/ui/views/harmony/chrome_layout_provider.h"
-#include "components/infobars/core/confirm_infobar_delegate.h"
 #include "ui/base/material_design/material_design_controller.h"
 #include "ui/base/window_open_disposition.h"
 #include "ui/native_theme/native_theme.h"
@@ -19,6 +18,7 @@
 #include "ui/views/controls/button/md_text_button.h"
 #include "ui/views/controls/label.h"
 #include "ui/views/controls/link.h"
+#include "ui/views/view_properties.h"
 
 // InfoBarService -------------------------------------------------------------
 
@@ -84,28 +84,19 @@
     AddViewToContentArea(label_);
 
     if (delegate->GetButtons() & ConfirmInfoBarDelegate::BUTTON_OK) {
-      ok_button_ = views::MdTextButton::Create(
-          this, delegate->GetButtonLabel(ConfirmInfoBarDelegate::BUTTON_OK));
+      ok_button_ = CreateButton(ConfirmInfoBarDelegate::BUTTON_OK);
       ok_button_->SetProminent(true);
       if (delegate->OKButtonTriggersUACPrompt()) {
         elevation_icon_setter_.reset(new ElevationIconSetter(
             ok_button_,
             base::Bind(&ConfirmInfoBar::Layout, base::Unretained(this))));
       }
-      AddViewToContentArea(ok_button_);
-      ok_button_->SizeToPreferredSize();
     }
 
     if (delegate->GetButtons() & ConfirmInfoBarDelegate::BUTTON_CANCEL) {
-      cancel_button_ = views::MdTextButton::Create(
-          this,
-          delegate->GetButtonLabel(ConfirmInfoBarDelegate::BUTTON_CANCEL));
-      if (delegate->GetButtons() == ConfirmInfoBarDelegate::BUTTON_CANCEL) {
-        // Apply prominent styling only if the cancel button is the only button.
+      cancel_button_ = CreateButton(ConfirmInfoBarDelegate::BUTTON_CANCEL);
+      if (delegate->GetButtons() == ConfirmInfoBarDelegate::BUTTON_CANCEL)
         cancel_button_->SetProminent(true);
-      }
-      AddViewToContentArea(cancel_button_);
-      cancel_button_->SizeToPreferredSize();
     }
 
     base::string16 link_text(delegate->GetLinkText());
@@ -151,6 +142,20 @@
   return delegate()->AsConfirmInfoBarDelegate();
 }
 
+views::MdTextButton* ConfirmInfoBar::CreateButton(
+    ConfirmInfoBarDelegate::InfoBarButton type) {
+  auto* button =
+      views::MdTextButton::Create(this, GetDelegate()->GetButtonLabel(type));
+  button->SetProperty(
+      views::kMarginsKey,
+      new gfx::Insets(ChromeLayoutProvider::Get()->GetDistanceMetric(
+                          DISTANCE_TOAST_CONTROL_VERTICAL),
+                      0));
+  AddViewToContentArea(button);
+  button->SizeToPreferredSize();
+  return button;
+}
+
 int ConfirmInfoBar::NonLabelWidth() const {
   ChromeLayoutProvider* layout_provider = ChromeLayoutProvider::Get();
 
diff --git a/chrome/browser/ui/views/infobars/confirm_infobar.h b/chrome/browser/ui/views/infobars/confirm_infobar.h
index 7853bd9..441fcef 100644
--- a/chrome/browser/ui/views/infobars/confirm_infobar.h
+++ b/chrome/browser/ui/views/infobars/confirm_infobar.h
@@ -8,9 +8,9 @@
 #include "base/compiler_specific.h"
 #include "base/macros.h"
 #include "chrome/browser/ui/views/infobars/infobar_view.h"
+#include "components/infobars/core/confirm_infobar_delegate.h"
 #include "ui/views/controls/link_listener.h"
 
-class ConfirmInfoBarDelegate;
 class ElevationIconSetter;
 
 namespace views {
@@ -41,6 +41,9 @@
 
   ConfirmInfoBarDelegate* GetDelegate();
 
+  // Creates a button suitable for use as either OK or Cancel.
+  views::MdTextButton* CreateButton(ConfirmInfoBarDelegate::InfoBarButton type);
+
   // Returns the width of all content other than the label and link.  Layout()
   // uses this to determine how much space the label and link can take.
   int NonLabelWidth() const;
diff --git a/chrome/browser/ui/views/infobars/infobar_view.cc b/chrome/browser/ui/views/infobars/infobar_view.cc
index 37819cd..e7683e1a 100644
--- a/chrome/browser/ui/views/infobars/infobar_view.cc
+++ b/chrome/browser/ui/views/infobars/infobar_view.cc
@@ -11,6 +11,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/ui/infobar_container_delegate.h"
 #include "chrome/browser/ui/views/harmony/chrome_layout_provider.h"
+#include "chrome/browser/ui/views/harmony/chrome_typography.h"
 #include "chrome/browser/ui/views/infobars/infobar_background.h"
 #include "chrome/grit/generated_resources.h"
 #include "components/infobars/core/infobar_delegate.h"
@@ -34,6 +35,7 @@
 #include "ui/views/controls/label.h"
 #include "ui/views/controls/link.h"
 #include "ui/views/controls/menu/menu_runner.h"
+#include "ui/views/view_properties.h"
 #include "ui/views/widget/widget.h"
 #include "ui/views/window/non_client_view.h"
 
@@ -50,6 +52,21 @@
   return SK_ColorBLACK;
 }
 
+int GetElementSpacing() {
+  return ChromeLayoutProvider::Get()->GetDistanceMetric(
+      DISTANCE_UNRELATED_CONTROL_HORIZONTAL);
+}
+
+gfx::Insets GetCloseButtonSpacing() {
+  auto* provider = ChromeLayoutProvider::Get();
+  const gfx::Insets vector_button_insets =
+      provider->GetInsetsMetric(views::INSETS_VECTOR_IMAGE_BUTTON);
+  return gfx::Insets(
+             provider->GetDistanceMetric(DISTANCE_TOAST_CONTROL_VERTICAL),
+             GetElementSpacing()) -
+         vector_button_insets;
+}
+
 }  // namespace
 
 
@@ -92,21 +109,31 @@
 }
 
 views::Label* InfoBarView::CreateLabel(const base::string16& text) const {
-  views::Label* label = new views::Label(text);
+  views::Label* label = new views::Label(text, CONTEXT_BODY_TEXT_LARGE);
   label->SizeToPreferredSize();
   label->SetBackgroundColor(background()->get_color());
   label->SetEnabledColor(GetInfobarTextColor());
   label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
+  label->SetProperty(
+      views::kMarginsKey,
+      new gfx::Insets(ChromeLayoutProvider::Get()->GetDistanceMetric(
+                          DISTANCE_TOAST_LABEL_VERTICAL),
+                      0));
   return label;
 }
 
 views::Link* InfoBarView::CreateLink(const base::string16& text,
                                      views::LinkListener* listener) const {
-  views::Link* link = new views::Link(text);
+  views::Link* link = new views::Link(text, CONTEXT_BODY_TEXT_LARGE);
   link->SizeToPreferredSize();
   link->SetHorizontalAlignment(gfx::ALIGN_LEFT);
   link->set_listener(listener);
   link->SetBackgroundColor(background()->get_color());
+  link->SetProperty(
+      views::kMarginsKey,
+      new gfx::Insets(ChromeLayoutProvider::Get()->GetDistanceMetric(
+                          DISTANCE_TOAST_LABEL_VERTICAL),
+                      0));
   return link;
 }
 
@@ -123,28 +150,24 @@
   // |child_container_| should be the only child.
   DCHECK_EQ(1, child_count());
 
-  ChromeLayoutProvider* layout_provider = ChromeLayoutProvider::Get();
-
-  const int related_control_distance = layout_provider->GetDistanceMetric(
-      views::DISTANCE_RELATED_CONTROL_HORIZONTAL);
-  const int unrelated_control_distance =
-      layout_provider->GetDistanceMetric(DISTANCE_UNRELATED_CONTROL_HORIZONTAL);
-
   // Even though other views are technically grandchildren, we'll lay them out
   // here on behalf of |child_container_|.
-  int start_x = related_control_distance;
-  if (icon_ != NULL) {
-    icon_->SetPosition(gfx::Point(start_x, OffsetY(icon_)));
-    start_x = icon_->bounds().right() + related_control_distance;
+  const int spacing = GetElementSpacing();
+  int start_x = 0;
+  if (icon_) {
+    icon_->SetPosition(gfx::Point(spacing, OffsetY(icon_)));
+    start_x = icon_->bounds().right();
   }
 
-  int content_minimum_width = ContentMinimumWidth();
+  const int content_minimum_width = ContentMinimumWidth();
+  if (content_minimum_width > 0)
+    start_x += spacing + content_minimum_width;
+
+  const gfx::Insets close_button_spacing = GetCloseButtonSpacing();
   close_button_->SizeToPreferredSize();
   close_button_->SetPosition(gfx::Point(
-      std::max(
-          start_x + content_minimum_width +
-              ((content_minimum_width > 0) ? unrelated_control_distance : 0),
-          width() - related_control_distance - close_button_->width()),
+      std::max(start_x + close_button_spacing.left(),
+               width() - close_button_spacing.right() - close_button_->width()),
       OffsetY(close_button_)));
 
   // For accessibility reasons, the close button should come last.
@@ -162,6 +185,11 @@
       icon_ = new views::ImageView;
       icon_->SetImage(image.ToImageSkia());
       icon_->SizeToPreferredSize();
+      icon_->SetProperty(
+          views::kMarginsKey,
+          new gfx::Insets(ChromeLayoutProvider::Get()->GetDistanceMetric(
+                              DISTANCE_TOAST_LABEL_VERTICAL),
+                          0));
       child_container_->AddChildView(icon_);
     }
 
@@ -171,19 +199,24 @@
     close_button_->SetAccessibleName(
         l10n_util::GetStringUTF16(IDS_ACCNAME_CLOSE));
     close_button_->SetFocusForPlatform();
+    gfx::Insets close_button_spacing = GetCloseButtonSpacing();
+    close_button_->SetProperty(
+        views::kMarginsKey, new gfx::Insets(close_button_spacing.top(), 0,
+                                            close_button_spacing.bottom(), 0));
     // Subclasses should already be done adding child views by this point (see
     // related DCHECK in Layout()).
     child_container_->AddChildView(close_button_);
   }
 
   // Ensure the infobar is tall enough to display its contents.
-  int height = InfoBarContainerDelegate::kDefaultBarTargetHeight;
-  const int kMinimumVerticalPadding = 6;
+  int height = 0;
   for (int i = 0; i < child_container_->child_count(); ++i) {
-    const int child_height = child_container_->child_at(i)->height();
-    height = std::max(height, child_height + kMinimumVerticalPadding);
+    View* child = child_container_->child_at(i);
+    const gfx::Insets* const margins = child->GetProperty(views::kMarginsKey);
+    const int margin_height = margins ? margins->height() : 0;
+    height = std::max(height, child->height() + margin_height);
   }
-  SetBarTargetHeight(height);
+  SetBarTargetHeight(height + InfoBarContainerDelegate::kSeparatorLineHeight);
 }
 
 void InfoBarView::ButtonPressed(views::Button* sender,
@@ -204,14 +237,12 @@
   // Ensure we don't return a value greater than EndX(), so children can safely
   // set something's width to "EndX() - StartX()" without risking that being
   // negative.
-  const int padding = ChromeLayoutProvider::Get()->GetDistanceMetric(
-      views::DISTANCE_RELATED_CONTROL_HORIZONTAL);
-  return std::min((icon_ ? icon_->bounds().right() : 0) + padding, EndX());
+  return std::min((icon_ ? icon_->bounds().right() : 0) + GetElementSpacing(),
+                  EndX());
 }
 
 int InfoBarView::EndX() const {
-  return close_button_->x() - ChromeLayoutProvider::Get()->GetDistanceMetric(
-                                  DISTANCE_UNRELATED_CONTROL_HORIZONTAL);
+  return close_button_->x() - GetCloseButtonSpacing().left();
 }
 
 int InfoBarView::OffsetY(views::View* view) const {
@@ -282,18 +313,18 @@
 }
 
 gfx::Size InfoBarView::CalculatePreferredSize() const {
-  ChromeLayoutProvider* layout_provider = ChromeLayoutProvider::Get();
+  int width = 0;
 
-  const int related_control_spacing = layout_provider->GetDistanceMetric(
-      views::DISTANCE_RELATED_CONTROL_HORIZONTAL);
-  const int unrelated_control_spacing =
-      layout_provider->GetDistanceMetric(DISTANCE_UNRELATED_CONTROL_HORIZONTAL);
+  const int spacing = GetElementSpacing();
+  if (icon_)
+    width += spacing + icon_->width();
+
+  const int content_width = ContentMinimumWidth();
+  if (content_width)
+    width += spacing + content_width;
 
   return gfx::Size(
-      related_control_spacing +
-          (icon_ ? (icon_->width() + related_control_spacing) : 0) +
-          ContentMinimumWidth() + unrelated_control_spacing +
-          close_button_->width() + related_control_spacing,
+      width + GetCloseButtonSpacing().width() + close_button_->width(),
       total_height());
 }
 
diff --git a/chrome/browser/ui/views/page_info/chosen_object_view.cc b/chrome/browser/ui/views/page_info/chosen_object_view.cc
index ffb8df3..3e291cf 100644
--- a/chrome/browser/ui/views/page_info/chosen_object_view.cc
+++ b/chrome/browser/ui/views/page_info/chosen_object_view.cc
@@ -26,6 +26,8 @@
   // |ChosenObjectView| layout (fills parent):
   // *------------------------------------*
   // | Icon | Chosen Object Name      | X |
+  // |------|-------------------------|---|
+  // |      | USB device              |   |
   // *------------------------------------*
   //
   // Where the icon and close button columns are fixed widths.
@@ -35,23 +37,34 @@
   views::GridLayout* layout =
       SetLayoutManager(std::make_unique<views::GridLayout>(this));
   const int column_set_id = 0;
+
+  const int related_label_padding =
+      ChromeLayoutProvider::Get()->GetDistanceMetric(
+          views::DISTANCE_RELATED_LABEL_HORIZONTAL);
   views::ColumnSet* column_set = layout->AddColumnSet(column_set_id);
   column_set->AddColumn(views::GridLayout::CENTER, views::GridLayout::CENTER,
                         kFixed, views::GridLayout::FIXED,
                         PageInfoBubbleView::kIconColumnWidth, 0);
-  column_set->AddPaddingColumn(kFixed,
-                               ChromeLayoutProvider::Get()->GetDistanceMetric(
-                                   views::DISTANCE_RELATED_LABEL_HORIZONTAL));
+  column_set->AddPaddingColumn(kFixed, related_label_padding);
   column_set->AddColumn(views::GridLayout::LEADING, views::GridLayout::CENTER,
                         kStretchy, views::GridLayout::USE_PREF, 0, 0);
+  column_set->AddPaddingColumn(kFixed, related_label_padding);
   column_set->AddColumn(views::GridLayout::TRAILING, views::GridLayout::CENTER,
                         kFixed, views::GridLayout::USE_PREF,
                         PageInfoBubbleView::kIconColumnWidth, 0);
 
   layout->StartRow(kStretchy, column_set_id);
-  // Create the chosen object icon and label.
+  // This padding is added to the top and bottom of each chosen object row, so
+  // use half. This is also consistent with |PermissionSelectorRow|'s behavior.
+  const int list_item_padding = ChromeLayoutProvider::Get()->GetDistanceMetric(
+                                    DISTANCE_CONTROL_LIST_VERTICAL) /
+                                2;
+  layout->StartRowWithPadding(kStretchy, column_set_id, kFixed,
+                              list_item_padding);
+  // Create the chosen object icon.
   icon_ = new views::ImageView();
   layout->AddView(icon_);
+  // Create the label that displays the chosen object name.
   views::Label* label = new views::Label(
       l10n_util::GetStringFUTF16(info_->ui_info.label_string_id,
                                  PageInfoUI::ChosenObjectToUIString(*info_)),
@@ -82,6 +95,16 @@
   delete_button_->SetTooltipText(
       l10n_util::GetStringUTF16(info_->ui_info.delete_tooltip_string_id));
   layout->AddView(delete_button_);
+
+  // Display secondary text underneath the name of the chosen object to describe
+  // what the chosen object actually is.
+  layout->StartRow(kStretchy, column_set_id);
+  views::Label* secondary_label = new views::Label(
+      l10n_util::GetStringUTF16(info_->ui_info.secondary_label_string_id));
+  secondary_label->SetEnabledColor(PageInfoUI::GetSecondaryTextColor());
+  layout->SkipColumns(1);
+  layout->AddView(secondary_label);
+  layout->AddPaddingRow(column_set_id, list_item_padding);
 }
 
 void ChosenObjectView::AddObserver(ChosenObjectViewObserver* observer) {
diff --git a/chrome/browser/ui/views/page_info/page_info_bubble_view_unittest.cc b/chrome/browser/ui/views/page_info/page_info_bubble_view_unittest.cc
index 2f4b9c2..3c46ce1f 100644
--- a/chrome/browser/ui/views/page_info/page_info_bubble_view_unittest.cc
+++ b/chrome/browser/ui/views/page_info/page_info_bubble_view_unittest.cc
@@ -298,7 +298,7 @@
 
   ChosenObjectView* object_view = static_cast<ChosenObjectView*>(
       api_->permissions_view()->child_at(kExpectedChildren));
-  EXPECT_EQ(3, object_view->child_count());
+  EXPECT_EQ(4, object_view->child_count());
 
   const int kLabelIndex = 1;
   views::Label* label =
diff --git a/chrome/browser/ui/views/page_info/permission_selector_row.cc b/chrome/browser/ui/views/page_info/permission_selector_row.cc
index 4984a6d..19bd5b1 100644
--- a/chrome/browser/ui/views/page_info/permission_selector_row.cc
+++ b/chrome/browser/ui/views/page_info/permission_selector_row.cc
@@ -319,7 +319,7 @@
     layout->SkipColumns(1);
     views::Label* permission_decision_reason = new views::Label(reason);
     permission_decision_reason->SetEnabledColor(
-        PageInfoUI::GetPermissionDecisionTextColor());
+        PageInfoUI::GetSecondaryTextColor());
 
     views::ColumnSet* column_set =
         layout->GetColumnSet(PageInfoBubbleView::kPermissionColumnSetId);
diff --git a/chrome/browser/ui/webui/chromeos/login/encryption_migration_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/encryption_migration_screen_handler.cc
index 55c82d3..409c352 100644
--- a/chrome/browser/ui/webui/chromeos/login/encryption_migration_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/encryption_migration_screen_handler.cc
@@ -581,11 +581,13 @@
 
 void EncryptionMigrationScreenHandler::OnMountExistingVault(
     base::Optional<cryptohome::BaseReply> reply) {
-  if (cryptohome::BaseReplyToMountError(reply) !=
-      cryptohome::MOUNT_ERROR_NONE) {
+  cryptohome::MountError return_code =
+      cryptohome::MountExReplyToMountError(reply);
+  if (return_code != cryptohome::MOUNT_ERROR_NONE) {
     RecordMigrationResultMountFailure(IsResumingIncompleteMigration(),
                                       IsArcKiosk());
     UpdateUIState(UIState::MIGRATION_FAILED);
+    LOG(ERROR) << "Mount existing vault failed. Error: " << return_code;
     return;
   }
 
diff --git a/chrome/browser/ui/webui/print_preview/print_preview_ui.cc b/chrome/browser/ui/webui/print_preview/print_preview_ui.cc
index 0031061..eccc085 100644
--- a/chrome/browser/ui/webui/print_preview/print_preview_ui.cc
+++ b/chrome/browser/ui/webui/print_preview/print_preview_ui.cc
@@ -241,6 +241,8 @@
   source->AddString(
       "noDestsPromoLearnMoreUrl",
       chrome::kCloudPrintNoDestinationsLearnMoreURL);
+  source->AddString("gcpCertificateErrorLearnMoreURL",
+                    chrome::kCloudPrintCertificateErrorLearnMoreURL);
   source->AddLocalizedString("pageRangeLimitInstruction",
                              IDS_PRINT_PREVIEW_PAGE_RANGE_LIMIT_INSTRUCTION);
   source->AddLocalizedString(
diff --git a/chrome/browser/ui/webui/settings/chromeos/cups_printers_handler.cc b/chrome/browser/ui/webui/settings/chromeos/cups_printers_handler.cc
index 6d0cf18..6d3643e 100644
--- a/chrome/browser/ui/webui/settings/chromeos/cups_printers_handler.cc
+++ b/chrome/browser/ui/webui/settings/chromeos/cups_printers_handler.cc
@@ -33,6 +33,9 @@
 #include "chromeos/dbus/debug_daemon_client.h"
 #include "chromeos/printing/ppd_cache.h"
 #include "chromeos/printing/ppd_provider.h"
+#include "chromeos/printing/printer_configuration.h"
+#include "chromeos/printing/printing_constants.h"
+#include "chromeos/printing/uri_components.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/web_ui.h"
@@ -40,34 +43,16 @@
 #include "net/base/filename_util.h"
 #include "net/url_request/url_request_context_getter.h"
 #include "printing/backend/print_backend.h"
-#include "url/third_party/mozilla/url_parse.h"
 
 namespace chromeos {
 namespace settings {
 
 namespace {
 
-constexpr char kIppScheme[] = "ipp";
-constexpr char kIppsScheme[] = "ipps";
-
-constexpr int kIppPort = 631;
-// IPPS commonly uses the HTTPS port despite the spec saying it should use the
-// IPP port.
-constexpr int kIppsPort = 443;
-
 // These values are written to logs.  New enum values can be added, but existing
 // enums must never be renumbered or deleted and reused.
 enum PpdSourceForHistogram { kUser = 0, kScs = 1, kPpdSourceMax };
 
-// A parsed representation of a printer uri.
-struct PrinterUri {
-  bool encrypted = false;
-  std::string scheme;
-  std::string host;
-  int port = url::SpecialPort::PORT_INVALID;
-  std::string path;
-};
-
 void RecordPpdSource(const PpdSourceForHistogram& source) {
   UMA_HISTOGRAM_ENUMERATION("Printing.CUPS.PpdSource", source, kPpdSourceMax);
 }
@@ -82,43 +67,6 @@
   UMA_HISTOGRAM_BOOLEAN("Printing.CUPS.IppAttributesSuccess", success);
 }
 
-// Parses |printer_uri| into its components and written into |uri|.  Returns
-// true if the uri was parsed successfully, returns false otherwise.  No changes
-// are made to |uri| if this function returns false.
-bool ParseUri(const std::string& printer_uri, PrinterUri* uri) {
-  DCHECK(uri);
-  const char* uri_ptr = printer_uri.c_str();
-  url::Parsed parsed;
-  url::ParseStandardURL(uri_ptr, printer_uri.length(), &parsed);
-  if (!parsed.scheme.is_valid() || !parsed.host.is_valid() ||
-      !parsed.path.is_valid()) {
-    return false;
-  }
-  base::StringPiece scheme(&uri_ptr[parsed.scheme.begin], parsed.scheme.len);
-  base::StringPiece host(&uri_ptr[parsed.host.begin], parsed.host.len);
-  base::StringPiece path(&uri_ptr[parsed.path.begin], parsed.path.len);
-
-  bool encrypted = scheme != kIppScheme;
-  int port = ParsePort(uri_ptr, parsed.port);
-  // Port not specified.
-  if (port == url::SpecialPort::PORT_UNSPECIFIED ||
-      port == url::SpecialPort::PORT_INVALID) {
-    if (scheme == kIppScheme) {
-      port = kIppPort;
-    } else if (scheme == kIppsScheme) {
-      port = kIppsPort;
-    }
-  }
-
-  uri->encrypted = encrypted;
-  uri->scheme = scheme.as_string();
-  uri->host = host.as_string();
-  uri->port = port;
-  uri->path = path.as_string();
-
-  return true;
-}
-
 // Returns true if |printer_uri| is an IPP uri.
 bool IsIppUri(base::StringPiece printer_uri) {
   base::StringPiece::size_type separator_location =
@@ -136,15 +84,17 @@
 // error to attempt this with a non-IPP printer.
 void QueryAutoconf(const std::string& printer_uri,
                    const PrinterInfoCallback& callback) {
-  PrinterUri uri;
+  auto optional = ParseUri(printer_uri);
   // Behavior for querying a non-IPP uri is undefined and disallowed.
-  if (!IsIppUri(printer_uri) || !ParseUri(printer_uri, &uri)) {
+  if (!IsIppUri(printer_uri) || !optional.has_value()) {
     LOG(WARNING) << "Printer uri is invalid: " << printer_uri;
     callback.Run(false, "", "", "", false);
     return;
   }
 
-  QueryIppPrinter(uri.host, uri.port, uri.path, uri.encrypted, callback);
+  UriComponents uri = optional.value();
+  QueryIppPrinter(uri.host(), uri.port(), uri.path(), uri.encrypted(),
+                  callback);
 }
 
 // Create an empty CupsPrinterInfo dictionary value. It should be consistent
@@ -193,8 +143,8 @@
   printer_info->SetString("printerModel", printer.model());
   printer_info->SetString("printerMakeAndModel", printer.make_and_model());
 
-  PrinterUri uri;
-  if (!ParseUri(printer.uri(), &uri)) {
+  auto optional = printer.GetUriComponents();
+  if (!optional.has_value()) {
     // Uri is invalid so we set default values.
     LOG(WARNING) << "Could not parse uri.  Defaulting values";
     printer_info->SetString("printerAddress", "");
@@ -204,7 +154,9 @@
     return printer_info;
   }
 
-  if (base::ToLowerASCII(uri.scheme) == "usb") {
+  UriComponents uri = optional.value();
+
+  if (base::ToLowerASCII(uri.scheme()) == "usb") {
     // USB has URI path (and, maybe, query) components that aren't really
     // associated with a queue -- the mapping between printing semantics and URI
     // semantics breaks down a bit here.  From the user's point of view, the
@@ -213,12 +165,12 @@
                             printer.uri().substr(strlen("usb://")));
   } else {
     printer_info->SetString("printerAddress",
-                            PrinterAddress(uri.host, uri.port));
-    if (!uri.path.empty()) {
-      printer_info->SetString("printerQueue", uri.path.substr(1));
+                            PrinterAddress(uri.host(), uri.port()));
+    if (!uri.path().empty()) {
+      printer_info->SetString("printerQueue", uri.path().substr(1));
     }
   }
-  printer_info->SetString("printerProtocol", base::ToLowerASCII(uri.scheme));
+  printer_info->SetString("printerProtocol", base::ToLowerASCII(uri.scheme()));
 
   return printer_info;
 }
@@ -532,9 +484,17 @@
   CHECK(args->GetDictionary(0, &printer_dict));
 
   std::unique_ptr<Printer> printer = DictToPrinter(*printer_dict);
-  PrinterUri uri;
-  if (!printer || !ParseUri(printer->uri(), &uri)) {
-    LOG(ERROR) << "Failed to parse printer";
+  if (!printer) {
+    LOG(ERROR) << "Failed to parse printer URI";
+    OnAddPrinterError(PrinterSetupResult::kFatalError);
+    return;
+  }
+
+  auto optional = printer->GetUriComponents();
+  if (!optional.has_value()) {
+    // If the returned optional does not contain a value then it means that the
+    // printer's uri was not able to be parsed successfully.
+    LOG(ERROR) << "Failed to parse printer URI";
     OnAddPrinterError(PrinterSetupResult::kFatalError);
     return;
   }
@@ -837,11 +797,17 @@
   CHECK(args->GetString(0, &printer_id));
 
   std::unique_ptr<Printer> printer = printers_manager_->GetPrinter(printer_id);
-  PrinterUri uri;
-  if (printer == nullptr || !ParseUri(printer->uri(), &uri)) {
+  if (printer == nullptr) {
     // Printer disappeared, so we don't have information about it anymore and
-    // can't really do much.  Or the printer uri was not parsed successfully.
-    // Fail the add.
+    // can't really do much. Fail the add.
+    FireWebUIListener("on-add-cups-printer", base::Value(false),
+                      base::Value(printer_id));
+    return;
+  }
+
+  auto optional = printer->GetUriComponents();
+  if (!optional.has_value()) {
+    // The printer uri was not parsed successfully. Fail the add.
     FireWebUIListener("on-add-cups-printer", base::Value(false),
                       base::Value(printer_id));
     return;
diff --git a/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc b/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc
index d4a395d..9aaebc4 100644
--- a/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc
+++ b/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc
@@ -31,6 +31,7 @@
 #include "components/strings/grit/components_strings.h"
 #include "components/subresource_filter/core/browser/subresource_filter_features.h"
 #include "content/public/browser/web_ui_data_source.h"
+#include "services/device/public/cpp/device_features.h"
 #include "ui/base/l10n/l10n_util.h"
 
 #if defined(OS_CHROMEOS)
@@ -1925,6 +1926,9 @@
     {"siteSettingsSoundAllowRecommended",
      IDS_SETTINGS_SITE_SETTINGS_SOUND_ALLOW_RECOMMENDED},
     {"siteSettingsSoundBlock", IDS_SETTINGS_SITE_SETTINGS_SOUND_BLOCK},
+    {"siteSettingsSensors", IDS_SETTINGS_SITE_SETTINGS_SENSORS},
+    {"siteSettingsSensorsAllow", IDS_SETTINGS_SITE_SETTINGS_SENSORS_ALLOW},
+    {"siteSettingsSensorsBlock", IDS_SETTINGS_SITE_SETTINGS_SENSORS_BLOCK},
     {"siteSettingsFlash", IDS_SETTINGS_SITE_SETTINGS_FLASH},
     {"siteSettingsPdfDocuments", IDS_SETTINGS_SITE_SETTINGS_PDF_DOCUMENTS},
     {"siteSettingsPdfDownloadPdfs",
@@ -2109,6 +2113,10 @@
       "enableClipboardContentSetting",
       base::FeatureList::IsEnabled(features::kClipboardContentSetting));
 
+  html_source->AddBoolean(
+      "enableSensorsContentSetting",
+      base::FeatureList::IsEnabled(features::kGenericSensorExtraClasses));
+
   if (PluginUtils::ShouldPreferHtmlOverPlugins(
           HostContentSettingsMapFactory::GetForProfile(profile))) {
     LocalizedString flash_strings[] = {
diff --git a/chrome/browser/ui/webui/site_settings_helper.cc b/chrome/browser/ui/webui/site_settings_helper.cc
index 4f4d73d1..bf59df31 100644
--- a/chrome/browser/ui/webui/site_settings_helper.cc
+++ b/chrome/browser/ui/webui/site_settings_helper.cc
@@ -74,6 +74,7 @@
     {CONTENT_SETTINGS_TYPE_ADS, "ads"},
     {CONTENT_SETTINGS_TYPE_SOUND, "sound"},
     {CONTENT_SETTINGS_TYPE_CLIPBOARD_READ, "clipboard"},
+    {CONTENT_SETTINGS_TYPE_SENSORS, "sensors"},
 
     // Add new content settings here if a corresponding Javascript string
     // representation for it is not required. Note some exceptions, such as
@@ -96,7 +97,6 @@
     {CONTENT_SETTINGS_TYPE_PASSWORD_PROTECTION, nullptr},
     {CONTENT_SETTINGS_TYPE_MEDIA_ENGAGEMENT, nullptr},
     {CONTENT_SETTINGS_TYPE_CLIENT_HINTS, nullptr},
-    {CONTENT_SETTINGS_TYPE_SENSORS, nullptr},
     {CONTENT_SETTINGS_TYPE_ACCESSIBILITY_EVENTS, nullptr},
     {CONTENT_SETTINGS_TYPE_CLIPBOARD_WRITE, nullptr},
 };
diff --git a/chrome/common/chrome_features.cc b/chrome/common/chrome_features.cc
index 8b631b9..251e0d55 100644
--- a/chrome/common/chrome_features.cc
+++ b/chrome/common/chrome_features.cc
@@ -546,8 +546,8 @@
 #if defined(OS_CHROMEOS)
 // Enables or disables user activity event logging for power management on
 // Chrome OS.
-const base::Feature kUserActivityEventLogging{
-    "UserActivityEventLogging", base::FEATURE_DISABLED_BY_DEFAULT};
+const base::Feature kUserActivityEventLogging{"UserActivityEventLogging",
+                                              base::FEATURE_ENABLED_BY_DEFAULT};
 #endif
 
 #if !defined(OS_ANDROID)
diff --git a/chrome/common/url_constants.cc b/chrome/common/url_constants.cc
index c33d558..b846a8ec 100644
--- a/chrome/common/url_constants.cc
+++ b/chrome/common/url_constants.cc
@@ -236,6 +236,19 @@
     "https://support.google.com/chrome/?p=settings_cloud_print";
 #endif
 
+const char kCloudPrintCertificateErrorLearnMoreURL[] =
+#if defined(OS_CHROMEOS)
+    "https://support.google.com/chromebook?p=cloudprint_error_troubleshoot";
+#elif defined(OS_MACOSX)
+    "https://support.google.com/cloudprint?p=cloudprint_error_offline_mac";
+#elif defined(OS_WIN)
+        "https://support.google.com/"
+        "cloudprint?p=cloudprint_error_offline_windows";
+#else
+        "https://support.google.com/"
+        "cloudprint?p=cloudprint_error_offline_linux";
+#endif
+
 const char kCloudPrintNoDestinationsLearnMoreURL[] =
     "https://www.google.com/cloudprint/learn/";
 
diff --git a/chrome/common/url_constants.h b/chrome/common/url_constants.h
index b0002a10..538ae89e 100644
--- a/chrome/common/url_constants.h
+++ b/chrome/common/url_constants.h
@@ -250,6 +250,9 @@
 // "Learn more" URL for the Cloud Print Preview No Destinations Promotion.
 extern const char kCloudPrintNoDestinationsLearnMoreURL[];
 
+// "Learn more" URL for the Cloud Print Preview certificate error.
+extern const char kCloudPrintCertificateErrorLearnMoreURL[];
+
 // The URL for the "Learn more" link the the Easy Unlock settings.
 extern const char kEasyUnlockLearnMoreUrl[];
 
diff --git a/chrome/installer/setup/install_worker_unittest.cc b/chrome/installer/setup/install_worker_unittest.cc
index e746e204..1ab277e2 100644
--- a/chrome/installer/setup/install_worker_unittest.cc
+++ b/chrome/installer/setup/install_worker_unittest.cc
@@ -7,7 +7,6 @@
 #include <memory>
 #include <string>
 
-#include "base/memory/ptr_util.h"
 #include "base/version.h"
 #include "base/win/registry.h"
 #include "chrome/common/chrome_constants.h"
@@ -243,7 +242,7 @@
       installer_state->AddProductFromState(*chrome);
     } else {
       BrowserDistribution* dist = BrowserDistribution::GetDistribution();
-      installer_state->AddProduct(base::MakeUnique<Product>(dist));
+      installer_state->AddProduct(std::make_unique<Product>(dist));
     }
   }
 
diff --git a/chrome/installer/setup/setup_install_details.cc b/chrome/installer/setup/setup_install_details.cc
index ab63ddc..92f10c12 100644
--- a/chrome/installer/setup/setup_install_details.cc
+++ b/chrome/installer/setup/setup_install_details.cc
@@ -5,7 +5,6 @@
 #include "chrome/installer/setup/setup_install_details.h"
 
 #include "base/command_line.h"
-#include "base/memory/ptr_util.h"
 #include "base/strings/string16.h"
 #include "base/win/registry.h"
 #include "chrome/install_static/install_constants.h"
@@ -66,7 +65,7 @@
     const base::CommandLine& command_line,
     const installer::MasterPreferences& master_preferences) {
   std::unique_ptr<install_static::PrimaryInstallDetails> details(
-      base::MakeUnique<install_static::PrimaryInstallDetails>());
+      std::make_unique<install_static::PrimaryInstallDetails>());
 
   // The mode is determined by brand-specific command line switches.
   const install_static::InstallConstants* const mode =
diff --git a/chrome/installer/setup/setup_install_details_unittest.cc b/chrome/installer/setup/setup_install_details_unittest.cc
index 76bf3e47..8e5f8d8 100644
--- a/chrome/installer/setup/setup_install_details_unittest.cc
+++ b/chrome/installer/setup/setup_install_details_unittest.cc
@@ -8,7 +8,6 @@
 
 #include "base/command_line.h"
 #include "base/macros.h"
-#include "base/memory/ptr_util.h"
 #include "base/test/test_reg_util_win.h"
 #include "chrome/install_static/install_details.h"
 #include "chrome/install_static/install_modes.h"
@@ -261,7 +260,7 @@
     // Prepare the inputs from the process command line.
     command_line_.ParseFromString(test_data_.command_line);
     master_preferences_ =
-        base::MakeUnique<installer::MasterPreferences>(command_line_);
+        std::make_unique<installer::MasterPreferences>(command_line_);
   }
 
   void SetUp() override {
diff --git a/chrome/installer/setup/setup_util.cc b/chrome/installer/setup/setup_util.cc
index 6938c84..b79db63c 100644
--- a/chrome/installer/setup/setup_util.cc
+++ b/chrome/installer/setup/setup_util.cc
@@ -29,7 +29,6 @@
 #include "base/files/file_util.h"
 #include "base/logging.h"
 #include "base/macros.h"
-#include "base/memory/ptr_util.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/numerics/safe_conversions.h"
 #include "base/strings/string_util.h"
@@ -781,10 +780,10 @@
 
 std::unique_ptr<AppRegistrationData> MakeBinariesRegistrationData() {
   if (install_static::kUseGoogleUpdateIntegration) {
-    return base::MakeUnique<UpdatingAppRegistrationData>(
+    return std::make_unique<UpdatingAppRegistrationData>(
         install_static::kBinariesAppGuid);
   }
-  return base::MakeUnique<NonUpdatingAppRegistrationData>(
+  return std::make_unique<NonUpdatingAppRegistrationData>(
       base::string16(L"Software\\").append(install_static::kBinariesPathName));
 }
 
diff --git a/chrome/installer/setup/setup_util_unittest.cc b/chrome/installer/setup/setup_util_unittest.cc
index 216ffb8..22e3439 100644
--- a/chrome/installer/setup/setup_util_unittest.cc
+++ b/chrome/installer/setup/setup_util_unittest.cc
@@ -14,7 +14,6 @@
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
 #include "base/macros.h"
-#include "base/memory/ptr_util.h"
 #include "base/process/kill.h"
 #include "base/process/launch.h"
 #include "base/process/process_handle.h"
@@ -575,7 +574,7 @@
     ASSERT_NO_FATAL_FAILURE(
         registry_override_manager_.OverrideRegistry(HKEY_CURRENT_USER));
     installer_state_ =
-        base::MakeUnique<FakeInstallerState>(temp_dir_.GetPath());
+        std::make_unique<FakeInstallerState>(temp_dir_.GetPath());
     // Create the state to be cleared.
     ASSERT_TRUE(base::win::RegKey(HKEY_CURRENT_USER, kBinariesClientsKeyPath,
                                   KEY_WRITE | KEY_WOW64_32KEY)
@@ -646,7 +645,7 @@
       operation_ = InstallerState::SINGLE_INSTALL_OR_UPDATE;
       target_path_ = target_path;
       state_key_ = dist->GetStateKey();
-      product_ = base::MakeUnique<Product>(dist);
+      product_ = std::make_unique<Product>(dist);
       level_ = InstallerState::USER_LEVEL;
       root_key_ = HKEY_CURRENT_USER;
     }
diff --git a/chrome/installer/util/beacons.cc b/chrome/installer/util/beacons.cc
index ac759ed..d85934a 100644
--- a/chrome/installer/util/beacons.cc
+++ b/chrome/installer/util/beacons.cc
@@ -6,7 +6,6 @@
 
 #include <stdint.h>
 
-#include "base/memory/ptr_util.h"
 #include "base/win/registry.h"
 #include "base/win/win_util.h"
 #include "chrome/install_static/install_details.h"
@@ -41,17 +40,17 @@
 namespace installer_util {
 
 std::unique_ptr<Beacon> MakeLastOsUpgradeBeacon() {
-  return base::MakeUnique<Beacon>(L"LastOsUpgrade", Beacon::BeaconType::LAST,
+  return std::make_unique<Beacon>(L"LastOsUpgrade", Beacon::BeaconType::LAST,
                                   Beacon::BeaconScope::PER_INSTALL);
 }
 
 std::unique_ptr<Beacon> MakeLastWasDefaultBeacon() {
-  return base::MakeUnique<Beacon>(L"LastWasDefault", Beacon::BeaconType::LAST,
+  return std::make_unique<Beacon>(L"LastWasDefault", Beacon::BeaconType::LAST,
                                   Beacon::BeaconScope::PER_USER);
 }
 
 std::unique_ptr<Beacon> MakeFirstNotDefaultBeacon() {
-  return base::MakeUnique<Beacon>(L"FirstNotDefault", Beacon::BeaconType::FIRST,
+  return std::make_unique<Beacon>(L"FirstNotDefault", Beacon::BeaconType::FIRST,
                                   Beacon::BeaconScope::PER_USER);
 }
 
diff --git a/chrome/installer/util/beacons_unittest.cc b/chrome/installer/util/beacons_unittest.cc
index 6e4ad1b4..7953e79 100644
--- a/chrome/installer/util/beacons_unittest.cc
+++ b/chrome/installer/util/beacons_unittest.cc
@@ -7,7 +7,6 @@
 #include <memory>
 #include <tuple>
 
-#include "base/memory/ptr_util.h"
 #include "base/test/test_reg_util_win.h"
 #include "base/test/test_timeouts.h"
 #include "base/threading/platform_thread.h"
@@ -173,7 +172,7 @@
 
     // Configure InstallDetails for the test.
     scoped_install_details_ =
-        base::MakeUnique<install_static::ScopedInstallDetails>(system_install_,
+        std::make_unique<install_static::ScopedInstallDetails>(system_install_,
                                                                mode_index);
     // Override the registry so that tests can freely push state to it.
     ASSERT_NO_FATAL_FAILURE(
diff --git a/chrome/installer/util/browser_distribution.cc b/chrome/installer/util/browser_distribution.cc
index ac6a3e41..33c105c 100644
--- a/chrome/installer/util/browser_distribution.cc
+++ b/chrome/installer/util/browser_distribution.cc
@@ -13,7 +13,6 @@
 
 #include "base/atomicops.h"
 #include "base/logging.h"
-#include "base/memory/ptr_util.h"
 #include "chrome/installer/util/app_registration_data.h"
 #include "chrome/installer/util/google_chrome_distribution.h"
 #include "chrome/installer/util/installer_util_strings.h"
@@ -28,7 +27,7 @@
 }  // namespace
 
 BrowserDistribution::BrowserDistribution()
-    : app_reg_data_(base::MakeUnique<NonUpdatingAppRegistrationData>(
+    : app_reg_data_(std::make_unique<NonUpdatingAppRegistrationData>(
           L"Software\\Chromium")) {}
 
 BrowserDistribution::BrowserDistribution(
diff --git a/chrome/installer/util/firewall_manager_win.cc b/chrome/installer/util/firewall_manager_win.cc
index ef886e3..b57f9952 100644
--- a/chrome/installer/util/firewall_manager_win.cc
+++ b/chrome/installer/util/firewall_manager_win.cc
@@ -10,7 +10,6 @@
 
 #include "base/files/file_path.h"
 #include "base/macros.h"
-#include "base/memory/ptr_util.h"
 #include "base/strings/string16.h"
 #include "chrome/installer/util/advanced_firewall_manager_win.h"
 #include "chrome/installer/util/browser_distribution.h"
@@ -69,7 +68,7 @@
     BrowserDistribution* dist,
     const base::FilePath& chrome_path) {
   // Try to connect to "Windows Firewall with Advanced Security" (Vista+).
-  auto manager = base::MakeUnique<FirewallManagerAdvancedImpl>();
+  auto manager = std::make_unique<FirewallManagerAdvancedImpl>();
   if (manager->Init(dist->GetDisplayName(), chrome_path))
     return std::move(manager);
 
diff --git a/chrome/installer/util/google_chrome_distribution.cc b/chrome/installer/util/google_chrome_distribution.cc
index 6afb11b..0594174 100644
--- a/chrome/installer/util/google_chrome_distribution.cc
+++ b/chrome/installer/util/google_chrome_distribution.cc
@@ -11,10 +11,10 @@
 #include <msi.h>
 #include <shellapi.h>
 
+#include <memory>
 #include <utility>
 
 #include "base/files/file_path.h"
-#include "base/memory/ptr_util.h"
 #include "base/path_service.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
@@ -87,7 +87,7 @@
 }  // namespace
 
 GoogleChromeDistribution::GoogleChromeDistribution()
-    : BrowserDistribution(base::MakeUnique<UpdatingAppRegistrationData>(
+    : BrowserDistribution(std::make_unique<UpdatingAppRegistrationData>(
           install_static::GetAppGuid())) {}
 
 void GoogleChromeDistribution::DoPostUninstallOperations(
diff --git a/chrome/installer/util/google_update_settings_unittest.cc b/chrome/installer/util/google_update_settings_unittest.cc
index dcee5783..96e7b1b 100644
--- a/chrome/installer/util/google_update_settings_unittest.cc
+++ b/chrome/installer/util/google_update_settings_unittest.cc
@@ -12,7 +12,6 @@
 
 #include "base/base_paths.h"
 #include "base/macros.h"
-#include "base/memory/ptr_util.h"
 #include "base/path_service.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/scoped_path_override.h"
@@ -1066,7 +1065,7 @@
 
   const StatsState& stats_state = GetParam();
   scoped_install_details_ =
-      base::MakeUnique<install_static::ScopedInstallDetails>(
+      std::make_unique<install_static::ScopedInstallDetails>(
           stats_state.system_level(), 0 /* install_mode_index */);
   const HKEY root_key = stats_state.root_key();
   ASSERT_NO_FATAL_FAILURE(
diff --git a/chrome/installer/util/install_util_unittest.cc b/chrome/installer/util/install_util_unittest.cc
index 24f056e..29f108d0 100644
--- a/chrome/installer/util/install_util_unittest.cc
+++ b/chrome/installer/util/install_util_unittest.cc
@@ -16,7 +16,6 @@
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
 #include "base/macros.h"
-#include "base/memory/ptr_util.h"
 #include "base/path_service.h"
 #include "base/strings/string_util.h"
 #include "base/test/scoped_path_override.h"
@@ -104,7 +103,7 @@
 class TestBrowserDistribution : public BrowserDistribution {
  public:
   TestBrowserDistribution()
-      : BrowserDistribution(base::MakeUnique<TestAppRegistrationData>()) {}
+      : BrowserDistribution(std::make_unique<TestAppRegistrationData>()) {}
 };
 
 class InstallUtilTest : public testing::Test {
diff --git a/chrome/installer/util/lzma_file_allocator_unittest.cc b/chrome/installer/util/lzma_file_allocator_unittest.cc
index dcd5710..a1b593ba 100644
--- a/chrome/installer/util/lzma_file_allocator_unittest.cc
+++ b/chrome/installer/util/lzma_file_allocator_unittest.cc
@@ -11,7 +11,6 @@
 
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
-#include "base/memory/ptr_util.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 #include <windows.h>
@@ -66,7 +65,7 @@
 
 TEST_F(LzmaFileAllocatorTest, DeleteAfterCloseTest) {
   std::unique_ptr<LzmaFileAllocator> allocator =
-      base::MakeUnique<LzmaFileAllocator>(temp_dir_.GetPath());
+      std::make_unique<LzmaFileAllocator>(temp_dir_.GetPath());
   base::FilePath file_path = allocator->mapped_file_path_;
   ASSERT_TRUE(base::PathExists(file_path));
   allocator.reset();
diff --git a/chrome/installer/util/product.cc b/chrome/installer/util/product.cc
index 62c2a7c..66fc9b0a 100644
--- a/chrome/installer/util/product.cc
+++ b/chrome/installer/util/product.cc
@@ -8,7 +8,6 @@
 
 #include "base/command_line.h"
 #include "base/logging.h"
-#include "base/memory/ptr_util.h"
 #include "base/process/launch.h"
 #include "base/win/registry.h"
 #include "chrome/installer/util/browser_distribution.h"
@@ -23,7 +22,7 @@
 
 Product::Product(BrowserDistribution* distribution)
     : distribution_(distribution),
-      operations_(base::MakeUnique<ChromeBrowserOperations>()) {}
+      operations_(std::make_unique<ChromeBrowserOperations>()) {}
 
 Product::~Product() {
 }
diff --git a/chrome/installer/util/product_unittest.cc b/chrome/installer/util/product_unittest.cc
index 6e6a45d5..7d2fad0 100644
--- a/chrome/installer/util/product_unittest.cc
+++ b/chrome/installer/util/product_unittest.cc
@@ -8,7 +8,6 @@
 
 #include "base/files/file_path.h"
 #include "base/logging.h"
-#include "base/memory/ptr_util.h"
 #include "base/path_service.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/test_reg_util_win.h"
@@ -30,7 +29,7 @@
   machine_state.Initialize();
 
   std::unique_ptr<Product> product =
-      base::MakeUnique<Product>(BrowserDistribution::GetDistribution());
+      std::make_unique<Product>(BrowserDistribution::GetDistribution());
   BrowserDistribution* distribution = product->distribution();
 
   base::FilePath user_data_dir;
diff --git a/chrome/installer/util/scoped_user_protocol_entry.cc b/chrome/installer/util/scoped_user_protocol_entry.cc
index f806217b..ea1cf2515 100644
--- a/chrome/installer/util/scoped_user_protocol_entry.cc
+++ b/chrome/installer/util/scoped_user_protocol_entry.cc
@@ -5,14 +5,13 @@
 #include "chrome/installer/util/scoped_user_protocol_entry.h"
 
 #include "base/files/file_path.h"
-#include "base/memory/ptr_util.h"
 #include "base/strings/string16.h"
 #include "base/win/registry.h"
 #include "chrome/installer/util/registry_entry.h"
 #include "chrome/installer/util/shell_util.h"
 
 ScopedUserProtocolEntry::ScopedUserProtocolEntry(const wchar_t* protocol) {
-  entries_.push_back(base::MakeUnique<RegistryEntry>(
+  entries_.push_back(std::make_unique<RegistryEntry>(
       base::FilePath(ShellUtil::kRegClasses).Append(protocol).value(),
       ShellUtil::kRegUrlProtocol, base::string16()));
   if (!entries_.back()->KeyExistsInRegistry(RegistryEntry::LOOK_IN_HKCU) &&
diff --git a/chrome/installer/util/scoped_user_protocol_entry_unittest.cc b/chrome/installer/util/scoped_user_protocol_entry_unittest.cc
index 04380163..7f346bb 100644
--- a/chrome/installer/util/scoped_user_protocol_entry_unittest.cc
+++ b/chrome/installer/util/scoped_user_protocol_entry_unittest.cc
@@ -4,7 +4,6 @@
 
 #include "chrome/installer/util/scoped_user_protocol_entry.h"
 
-#include "base/memory/ptr_util.h"
 #include "base/strings/string16.h"
 #include "base/test/test_reg_util_win.h"
 #include "base/win/registry.h"
@@ -32,13 +31,13 @@
                               const base::string16& name,
                               const base::string16& value) {
     std::vector<std::unique_ptr<RegistryEntry>> entries;
-    entries.push_back(base::MakeUnique<RegistryEntry>(key_path, name, value));
+    entries.push_back(std::make_unique<RegistryEntry>(key_path, name, value));
     ASSERT_TRUE(ShellUtil::AddRegistryEntries(HKEY_CURRENT_USER, entries));
   }
 
   void CreateScopedUserProtocolEntryAndVerifyRegistryValue(
       const base::string16& expected_entry_value) {
-    entry_ = base::MakeUnique<ScopedUserProtocolEntry>(L"http");
+    entry_ = std::make_unique<ScopedUserProtocolEntry>(L"http");
     ASSERT_TRUE(RegistryEntry(kProtocolEntryKeyPath, kProtocolEntryName,
                               expected_entry_value)
                     .ExistsInRegistry(RegistryEntry::LOOK_IN_HKCU));
diff --git a/chrome/installer/util/shell_util.cc b/chrome/installer/util/shell_util.cc
index f2b7e25b..df7d626 100644
--- a/chrome/installer/util/shell_util.cc
+++ b/chrome/installer/util/shell_util.cc
@@ -32,7 +32,6 @@
 #include "base/logging.h"
 #include "base/macros.h"
 #include "base/md5.h"
-#include "base/memory/ptr_util.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/path_service.h"
 #include "base/strings/string16.h"
@@ -245,7 +244,7 @@
   app_id_shell_key.append(ShellUtil::kRegShellPath);
 
   // <root hkey>\Software\Classes\<app_id>\.exe\shell @=open
-  entries.push_back(base::MakeUnique<RegistryEntry>(app_id_shell_key,
+  entries.push_back(std::make_unique<RegistryEntry>(app_id_shell_key,
                                                     ShellUtil::kRegVerbOpen));
 
   // The command to execute when opening this application via the Metro UI.
@@ -277,9 +276,9 @@
       const base::string16 verb_name(
           installer::GetLocalizedString(verb_and_id.name_id));
       entries.push_back(
-          base::MakeUnique<RegistryEntry>(sub_path, verb_name.c_str()));
+          std::make_unique<RegistryEntry>(sub_path, verb_name.c_str()));
     }
-    entries.push_back(base::MakeUnique<RegistryEntry>(sub_path, L"CommandId",
+    entries.push_back(std::make_unique<RegistryEntry>(sub_path, L"CommandId",
                                                       L"Browser.Launch"));
 
     sub_path.push_back(base::FilePath::kSeparators[0]);
@@ -287,8 +286,8 @@
 
     // <root hkey>\Software\Classes\<app_id>\.exe\shell\<verb>\command
     entries.push_back(
-        base::MakeUnique<RegistryEntry>(sub_path, delegate_command));
-    entries.push_back(base::MakeUnique<RegistryEntry>(
+        std::make_unique<RegistryEntry>(sub_path, delegate_command));
+    entries.push_back(std::make_unique<RegistryEntry>(
         sub_path, ShellUtil::kRegDelegateExecute, app_info.delegate_clsid));
   }
 
@@ -308,15 +307,15 @@
   prog_id_path.push_back(base::FilePath::kSeparators[0]);
   prog_id_path.append(app_info.prog_id);
   entries->push_back(
-      base::MakeUnique<RegistryEntry>(prog_id_path, app_info.file_type_name));
-  entries->push_back(base::MakeUnique<RegistryEntry>(
+      std::make_unique<RegistryEntry>(prog_id_path, app_info.file_type_name));
+  entries->push_back(std::make_unique<RegistryEntry>(
       prog_id_path + ShellUtil::kRegDefaultIcon,
       ShellUtil::FormatIconLocation(app_info.file_type_icon_path,
                                     app_info.file_type_icon_index)));
-  entries->push_back(base::MakeUnique<RegistryEntry>(
+  entries->push_back(std::make_unique<RegistryEntry>(
       prog_id_path + ShellUtil::kRegShellOpen, app_info.command_line));
   if (!app_info.delegate_clsid.empty()) {
-    entries->push_back(base::MakeUnique<RegistryEntry>(
+    entries->push_back(std::make_unique<RegistryEntry>(
         prog_id_path + ShellUtil::kRegShellOpen, ShellUtil::kRegDelegateExecute,
         app_info.delegate_clsid));
     // TODO(scottmg): Simplify after Metro removal. https://crbug.com/558054.
@@ -327,34 +326,34 @@
   // depend on the DelegateExecute verb handler being set.
   if (base::win::GetVersion() >= base::win::VERSION_WIN8) {
     if (!app_info.app_id.empty()) {
-      entries->push_back(base::MakeUnique<RegistryEntry>(
+      entries->push_back(std::make_unique<RegistryEntry>(
           prog_id_path, ShellUtil::kRegAppUserModelId, app_info.app_id));
     }
 
     // Add \Software\Classes\<prog_id>\Application entries
     base::string16 application_path(prog_id_path + ShellUtil::kRegApplication);
     if (!app_info.app_id.empty()) {
-      entries->push_back(base::MakeUnique<RegistryEntry>(
+      entries->push_back(std::make_unique<RegistryEntry>(
           application_path, ShellUtil::kRegAppUserModelId, app_info.app_id));
     }
     if (!app_info.application_icon_path.empty()) {
-      entries->push_back(base::MakeUnique<RegistryEntry>(
+      entries->push_back(std::make_unique<RegistryEntry>(
           application_path, ShellUtil::kRegApplicationIcon,
           ShellUtil::FormatIconLocation(app_info.application_icon_path,
                                         app_info.application_icon_index)));
     }
     if (!app_info.application_name.empty()) {
-      entries->push_back(base::MakeUnique<RegistryEntry>(
+      entries->push_back(std::make_unique<RegistryEntry>(
           application_path, ShellUtil::kRegApplicationName,
           app_info.application_name));
     }
     if (!app_info.application_description.empty()) {
-      entries->push_back(base::MakeUnique<RegistryEntry>(
+      entries->push_back(std::make_unique<RegistryEntry>(
           application_path, ShellUtil::kRegApplicationDescription,
           app_info.application_description));
     }
     if (!app_info.publisher_name.empty()) {
-      entries->push_back(base::MakeUnique<RegistryEntry>(
+      entries->push_back(std::make_unique<RegistryEntry>(
           application_path, ShellUtil::kRegApplicationCompany,
           app_info.publisher_name));
     }
@@ -414,7 +413,7 @@
     const base::string16& suffix,
     const base::string16& protocol,
     std::vector<std::unique_ptr<RegistryEntry>>* entries) {
-  entries->push_back(base::MakeUnique<RegistryEntry>(
+  entries->push_back(std::make_unique<RegistryEntry>(
       GetCapabilitiesKey(suffix).append(L"\\URLAssociations"), protocol,
       GetBrowserProgId(suffix)));
 }
@@ -438,61 +437,61 @@
   // Register Chrome's display name.
   // TODO(grt): http://crbug.com/75152 Also set LocalizedString; see
   // http://msdn.microsoft.com/en-us/library/windows/desktop/cc144109(v=VS.85).aspx#registering_the_display_name
-  entries->push_back(base::MakeUnique<RegistryEntry>(start_menu_entry,
+  entries->push_back(std::make_unique<RegistryEntry>(start_menu_entry,
                                                      dist->GetDisplayName()));
   // Register the "open" verb for launching Chrome via the "Internet" link.
-  entries->push_back(base::MakeUnique<RegistryEntry>(
+  entries->push_back(std::make_unique<RegistryEntry>(
       start_menu_entry + ShellUtil::kRegShellOpen, quoted_exe_path));
   // Register Chrome's icon for the Start Menu "Internet" link.
-  entries->push_back(base::MakeUnique<RegistryEntry>(
+  entries->push_back(std::make_unique<RegistryEntry>(
       start_menu_entry + ShellUtil::kRegDefaultIcon, icon_path));
 
   // Register installation information.
   base::string16 install_info(start_menu_entry + L"\\InstallInfo");
   // Note: not using CommandLine since it has ambiguous rules for quoting
   // strings.
-  entries->push_back(base::MakeUnique<RegistryEntry>(
+  entries->push_back(std::make_unique<RegistryEntry>(
       install_info, kReinstallCommand,
       quoted_exe_path + L" --" +
           base::ASCIIToUTF16(switches::kMakeDefaultBrowser)));
-  entries->push_back(base::MakeUnique<RegistryEntry>(
+  entries->push_back(std::make_unique<RegistryEntry>(
       install_info, L"HideIconsCommand",
       quoted_exe_path + L" --" + base::ASCIIToUTF16(switches::kHideIcons)));
-  entries->push_back(base::MakeUnique<RegistryEntry>(
+  entries->push_back(std::make_unique<RegistryEntry>(
       install_info, L"ShowIconsCommand",
       quoted_exe_path + L" --" + base::ASCIIToUTF16(switches::kShowIcons)));
   entries->push_back(
-      base::MakeUnique<RegistryEntry>(install_info, L"IconsVisible", 1));
+      std::make_unique<RegistryEntry>(install_info, L"IconsVisible", 1));
 
   // Register with Default Programs.
   const base::string16 reg_app_name(
       install_static::GetBaseAppName().append(suffix));
   // Tell Windows where to find Chrome's Default Programs info.
   const base::string16 capabilities(GetCapabilitiesKey(suffix));
-  entries->push_back(base::MakeUnique<RegistryEntry>(
+  entries->push_back(std::make_unique<RegistryEntry>(
       ShellUtil::kRegRegisteredApplications, reg_app_name, capabilities));
   // Write out Chrome's Default Programs info.
   // TODO(grt): http://crbug.com/75152 Write a reference to a localized
   // resource rather than this.
-  entries->push_back(base::MakeUnique<RegistryEntry>(
+  entries->push_back(std::make_unique<RegistryEntry>(
       capabilities, ShellUtil::kRegApplicationDescription,
       dist->GetLongAppDescription()));
-  entries->push_back(base::MakeUnique<RegistryEntry>(
+  entries->push_back(std::make_unique<RegistryEntry>(
       capabilities, ShellUtil::kRegApplicationIcon, icon_path));
-  entries->push_back(base::MakeUnique<RegistryEntry>(
+  entries->push_back(std::make_unique<RegistryEntry>(
       capabilities, ShellUtil::kRegApplicationName, dist->GetDisplayName()));
 
-  entries->push_back(base::MakeUnique<RegistryEntry>(
+  entries->push_back(std::make_unique<RegistryEntry>(
       capabilities + L"\\Startmenu", L"StartMenuInternet", reg_app_name));
 
   const base::string16 html_prog_id(GetBrowserProgId(suffix));
   for (int i = 0; ShellUtil::kPotentialFileAssociations[i] != NULL; i++) {
-    entries->push_back(base::MakeUnique<RegistryEntry>(
+    entries->push_back(std::make_unique<RegistryEntry>(
         capabilities + L"\\FileAssociations",
         ShellUtil::kPotentialFileAssociations[i], html_prog_id));
   }
   for (int i = 0; ShellUtil::kPotentialProtocolAssociations[i] != NULL; i++) {
-    entries->push_back(base::MakeUnique<RegistryEntry>(
+    entries->push_back(std::make_unique<RegistryEntry>(
         capabilities + L"\\URLAssociations",
         ShellUtil::kPotentialProtocolAssociations[i], html_prog_id));
   }
@@ -513,7 +512,7 @@
   key_name.push_back(base::FilePath::kSeparators[0]);
   key_name.append(ShellUtil::kRegOpenWithProgids);
   entries->push_back(
-      base::MakeUnique<RegistryEntry>(key_name, prog_id, base::string16()));
+      std::make_unique<RegistryEntry>(key_name, prog_id, base::string16()));
 }
 
 // This method returns a list of the registry entries required for this
@@ -532,8 +531,8 @@
   app_path_key.push_back(base::FilePath::kSeparators[0]);
   app_path_key.append(chrome_exe.BaseName().value());
   entries->push_back(
-      base::MakeUnique<RegistryEntry>(app_path_key, chrome_exe.value()));
-  entries->push_back(base::MakeUnique<RegistryEntry>(
+      std::make_unique<RegistryEntry>(app_path_key, chrome_exe.value()));
+  entries->push_back(std::make_unique<RegistryEntry>(
       app_path_key, ShellUtil::kAppPathsRegistryPathName,
       chrome_exe.DirName().value()));
 
@@ -565,7 +564,7 @@
   base::string16 key_name(ShellUtil::kRegClasses);
   key_name.push_back(base::FilePath::kSeparators[0]);
   key_name.append(ext);
-  auto default_association = base::MakeUnique<RegistryEntry>(key_name, prog_id);
+  auto default_association = std::make_unique<RegistryEntry>(key_name, prog_id);
   if (overwrite_existing ||
       !default_association->KeyExistsInRegistry(RegistryEntry::LOOK_IN_HKCU)) {
     entries->push_back(std::move(default_association));
@@ -587,26 +586,26 @@
   // This registry value tells Windows that this 'class' is a URL scheme
   // so IE, explorer and other apps will route it to our handler.
   // <root hkey>\Software\Classes\<protocol>\URL Protocol
-  entries->push_back(base::MakeUnique<RegistryEntry>(
+  entries->push_back(std::make_unique<RegistryEntry>(
       url_key, ShellUtil::kRegUrlProtocol, base::string16()));
 
   // <root hkey>\Software\Classes\<protocol>\DefaultIcon
   base::string16 icon_key = url_key + ShellUtil::kRegDefaultIcon;
-  entries->push_back(base::MakeUnique<RegistryEntry>(icon_key, chrome_icon));
+  entries->push_back(std::make_unique<RegistryEntry>(icon_key, chrome_icon));
 
   // <root hkey>\Software\Classes\<protocol>\shell\open\command
   base::string16 shell_key = url_key + ShellUtil::kRegShellOpen;
-  entries->push_back(base::MakeUnique<RegistryEntry>(shell_key, chrome_open));
+  entries->push_back(std::make_unique<RegistryEntry>(shell_key, chrome_open));
 
   // <root hkey>\Software\Classes\<protocol>\shell\open\ddeexec
   base::string16 dde_key = url_key + L"\\shell\\open\\ddeexec";
   entries->push_back(
-      base::MakeUnique<RegistryEntry>(dde_key, base::string16()));
+      std::make_unique<RegistryEntry>(dde_key, base::string16()));
 
   // <root hkey>\Software\Classes\<protocol>\shell\@
   base::string16 protocol_shell_key = url_key + ShellUtil::kRegShellPath;
   entries->push_back(
-      base::MakeUnique<RegistryEntry>(protocol_shell_key, L"open"));
+      std::make_unique<RegistryEntry>(protocol_shell_key, L"open"));
 }
 
 // This method returns a list of all the user level registry entries that are
@@ -636,7 +635,7 @@
   // start->Internet shortcut.
   base::string16 start_menu(ShellUtil::kRegStartMenuInternet);
   base::string16 app_name = install_static::GetBaseAppName().append(suffix);
-  entries->push_back(base::MakeUnique<RegistryEntry>(start_menu, app_name));
+  entries->push_back(std::make_unique<RegistryEntry>(start_menu, app_name));
 }
 
 // Checks that all |entries| are present on this computer (or absent if their
diff --git a/chrome/installer/zucchini/disassembler_win32.cc b/chrome/installer/zucchini/disassembler_win32.cc
index c6b0fda..a126fb3 100644
--- a/chrome/installer/zucchini/disassembler_win32.cc
+++ b/chrome/installer/zucchini/disassembler_win32.cc
@@ -9,7 +9,6 @@
 #include <algorithm>
 
 #include "base/logging.h"
-#include "base/memory/ptr_util.h"
 #include "base/numerics/safe_conversions.h"
 #include "chrome/installer/zucchini/abs32_utils.h"
 #include "chrome/installer/zucchini/algorithm.h"
@@ -127,7 +126,7 @@
   CHECK_GE(image_.size(), Traits::kVAWidth);
   offset_t offset_bound =
       base::checked_cast<offset_t>(image_.size() - Traits::kVAWidth + 1);
-  return base::MakeUnique<RelocReaderWin32>(std::move(reloc_rva_reader),
+  return std::make_unique<RelocReaderWin32>(std::move(reloc_rva_reader),
                                             Traits::kRelocType, offset_bound,
                                             translator_);
 }
@@ -139,7 +138,7 @@
   ParseAndStoreAbs32();
   Abs32RvaExtractorWin32 abs_rva_extractor(
       image_, {Traits::kBitness, image_base_}, abs32_locations_, lo, hi);
-  return base::MakeUnique<Abs32ReaderWin32>(std::move(abs_rva_extractor),
+  return std::make_unique<Abs32ReaderWin32>(std::move(abs_rva_extractor),
                                             translator_);
 }
 
@@ -148,7 +147,7 @@
     offset_t lo,
     offset_t hi) {
   ParseAndStoreRel32();
-  return base::MakeUnique<Rel32ReaderX86>(image_, lo, hi, &rel32_locations_,
+  return std::make_unique<Rel32ReaderX86>(image_, lo, hi, &rel32_locations_,
                                           translator_);
 }
 
@@ -156,7 +155,7 @@
 std::unique_ptr<ReferenceWriter> DisassemblerWin32<Traits>::MakeWriteRelocs(
     MutableBufferView image) {
   ParseAndStoreRelocBlocks();
-  return base::MakeUnique<RelocWriterWin32>(Traits::kRelocType, image,
+  return std::make_unique<RelocWriterWin32>(Traits::kRelocType, image,
                                             reloc_region_, reloc_block_offsets_,
                                             translator_);
 }
@@ -164,14 +163,14 @@
 template <class Traits>
 std::unique_ptr<ReferenceWriter> DisassemblerWin32<Traits>::MakeWriteAbs32(
     MutableBufferView image) {
-  return base::MakeUnique<Abs32WriterWin32>(
+  return std::make_unique<Abs32WriterWin32>(
       image, AbsoluteAddress(Traits::kBitness, image_base_), translator_);
 }
 
 template <class Traits>
 std::unique_ptr<ReferenceWriter> DisassemblerWin32<Traits>::MakeWriteRel32(
     MutableBufferView image) {
-  return base::MakeUnique<Rel32WriterX86>(image, translator_);
+  return std::make_unique<Rel32WriterX86>(image, translator_);
 }
 
 template <class Traits>
diff --git a/chrome/installer/zucchini/reloc_utils_unittest.cc b/chrome/installer/zucchini/reloc_utils_unittest.cc
index 26af68c..09961c85 100644
--- a/chrome/installer/zucchini/reloc_utils_unittest.cc
+++ b/chrome/installer/zucchini/reloc_utils_unittest.cc
@@ -7,12 +7,12 @@
 #include <stdint.h>
 
 #include <algorithm>
+#include <memory>
 #include <string>
 #include <utility>
 #include <vector>
 
 #include "base/logging.h"
-#include "base/memory/ptr_util.h"
 #include "base/numerics/safe_conversions.h"
 #include "base/test/gtest_util.h"
 #include "chrome/installer/zucchini/address_translator.h"
@@ -234,7 +234,7 @@
   offset_t offset_bound = image_size - kVAWidthX86 + 1;
 
   // Make RelocReaderWin32 that wraps |reloc_rva_reader|.
-  auto reader = base::MakeUnique<RelocReaderWin32>(
+  auto reader = std::make_unique<RelocReaderWin32>(
       std::move(reloc_rva_reader), kRelocTypeX86, offset_bound, translator);
 
   // Read all references and check.
@@ -249,7 +249,7 @@
 
   // Write reference, extract bytes and check.
   MutableBufferView mutable_image(&image_data[0], image_data.size());
-  auto writer = base::MakeUnique<RelocWriterWin32>(
+  auto writer = std::make_unique<RelocWriterWin32>(
       kRelocTypeX86, mutable_image, reloc_region_, reloc_block_offsets_,
       translator);
 
diff --git a/chrome/installer/zucchini/test_disassembler.cc b/chrome/installer/zucchini/test_disassembler.cc
index bfd30b0c..25f10f5 100644
--- a/chrome/installer/zucchini/test_disassembler.cc
+++ b/chrome/installer/zucchini/test_disassembler.cc
@@ -4,7 +4,6 @@
 
 #include "chrome/installer/zucchini/test_disassembler.h"
 
-#include "base/memory/ptr_util.h"
 #include "chrome/installer/zucchini/test_reference_reader.h"
 
 namespace zucchini {
@@ -43,7 +42,7 @@
 }
 
 std::unique_ptr<ReferenceReader> TestDisassembler::MakeReadRefs(int type) {
-  return base::MakeUnique<TestReferenceReader>(refs_[type]);
+  return std::make_unique<TestReferenceReader>(refs_[type]);
 }
 
 std::unique_ptr<ReferenceWriter> TestDisassembler::MakeWriteRefs(
@@ -53,7 +52,7 @@
     // ReferenceWriter:
     void PutNext(Reference) override {}
   };
-  return base::MakeUnique<NoOpWriter>();
+  return std::make_unique<NoOpWriter>();
 }
 
 }  // namespace zucchini
diff --git a/chrome/renderer/extensions/custom_types_unittest.cc b/chrome/renderer/extensions/custom_types_unittest.cc
new file mode 100644
index 0000000..9af7494
--- /dev/null
+++ b/chrome/renderer/extensions/custom_types_unittest.cc
@@ -0,0 +1,114 @@
+// 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 "extensions/renderer/storage_area.h"
+
+#include "base/command_line.h"
+#include "components/crx_file/id_util.h"
+#include "extensions/common/extension_builder.h"
+#include "extensions/common/switches.h"
+#include "extensions/renderer/bindings/api_binding_test_util.h"
+#include "extensions/renderer/bindings/api_binding_util.h"
+#include "extensions/renderer/native_extension_bindings_system.h"
+#include "extensions/renderer/native_extension_bindings_system_test_base.h"
+#include "extensions/renderer/script_context.h"
+
+namespace extensions {
+
+class CustomTypesTest : public NativeExtensionBindingsSystemUnittest {
+ public:
+  CustomTypesTest() = default;
+  ~CustomTypesTest() override = default;
+
+  void SetUp() override {
+    extension_id_ = crx_file::id_util::GenerateId("id");
+    // Whitelist an extension id so that we have access to privileged APIs (like
+    // preferencesPrivate).
+    base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
+        switches::kWhitelistedExtensionID, extension_id_);
+    NativeExtensionBindingsSystemUnittest::SetUp();
+  }
+
+  // Checks behavior of script after the main context is invalidated.
+  // Creates an extension with the given |permission|, and then runs
+  // |use_api_script| as a function with a single argument, the result of
+  // |api_script|. This expects the function to succeed while the function is
+  // valid, and then fail when the function is invalidated with the expected
+  // error.
+  // Note that no other validations are made (e.g., around the correctness of
+  // the call made to the API).
+  void RunContextInvalidationTest(const char* permission,
+                                  const char* api_script,
+                                  const char* use_api_script) {
+    scoped_refptr<Extension> extension = ExtensionBuilder("foo")
+                                             .AddPermission(permission)
+                                             .SetID(extension_id_)
+                                             .Build();
+    RegisterExtension(extension);
+
+    v8::HandleScope handle_scope(isolate());
+    v8::Local<v8::Context> context = MainContext();
+
+    ScriptContext* script_context = CreateScriptContext(
+        context, extension.get(), Feature::BLESSED_EXTENSION_CONTEXT);
+    script_context->set_url(extension->url());
+
+    bindings_system()->UpdateBindingsForContext(script_context);
+
+    v8::Local<v8::Value> api_object =
+        V8ValueFromScriptSource(context, api_script);
+    ASSERT_TRUE(api_object->IsObject());
+
+    v8::Local<v8::Function> use_api =
+        FunctionFromString(context, use_api_script);
+    v8::Local<v8::Value> args[] = {api_object};
+    RunFunction(use_api, context, arraysize(args), args);
+
+    DisposeContext(context);
+
+    EXPECT_FALSE(binding::IsContextValid(context));
+    RunFunctionAndExpectError(use_api, context, arraysize(args), args,
+                              "Uncaught Error: Extension context invalidated.");
+  }
+
+ private:
+  std::string extension_id_;
+
+  DISALLOW_COPY_AND_ASSIGN(CustomTypesTest);
+};
+
+TEST_F(CustomTypesTest, ContentSettingsUseAfterInvalidation) {
+  RunContextInvalidationTest("contentSettings",
+                             "chrome.contentSettings.javascript",
+                             R"((function(setting) {
+                                setting.set({
+                                  primaryPattern: '<all_urls>',
+                                  setting: 'block' });
+                                });)");
+}
+
+TEST_F(CustomTypesTest, ChromeSettingsAPIUseAfterInvalidation) {
+  RunContextInvalidationTest(
+      "privacy", "chrome.privacy.websites.doNotTrackEnabled",
+      R"((function(setting) { setting.set({value: true}); }))");
+}
+
+TEST_F(CustomTypesTest, ChromeSettingsEventUseAfterInvalidation) {
+  RunContextInvalidationTest("privacy",
+                             "chrome.privacy.websites.doNotTrackEnabled",
+                             R"((function(setting) {
+                                  setting.onChange.addListener(function() {});
+                                });)");
+}
+
+TEST_F(CustomTypesTest, EasyUnlockProximityRequiredUseAfterInvalidation) {
+  RunContextInvalidationTest(
+      "preferencesPrivate",
+      "chrome.preferencesPrivate.easyUnlockProximityRequired",
+      R"((function(setting) {
+           setting.onChange.addListener(function() {});
+         });)");
+}
+
+}  // namespace extensions
diff --git a/chrome/renderer/printing/chrome_print_render_frame_helper_delegate.cc b/chrome/renderer/printing/chrome_print_render_frame_helper_delegate.cc
index 01b6532..461eaa9 100644
--- a/chrome/renderer/printing/chrome_print_render_frame_helper_delegate.cc
+++ b/chrome/renderer/printing/chrome_print_render_frame_helper_delegate.cc
@@ -25,7 +25,11 @@
 #include "extensions/renderer/guest_view/mime_handler_view/mime_handler_view_container.h"
 #endif  // BUILDFLAG(ENABLE_EXTENSIONS)
 
-ChromePrintRenderFrameHelperDelegate::~ChromePrintRenderFrameHelperDelegate() {}
+ChromePrintRenderFrameHelperDelegate::ChromePrintRenderFrameHelperDelegate() =
+    default;
+
+ChromePrintRenderFrameHelperDelegate::~ChromePrintRenderFrameHelperDelegate() =
+    default;
 
 bool ChromePrintRenderFrameHelperDelegate::CancelPrerender(
     content::RenderFrame* render_frame) {
diff --git a/chrome/renderer/printing/chrome_print_render_frame_helper_delegate.h b/chrome/renderer/printing/chrome_print_render_frame_helper_delegate.h
index d3d5ad0..581d9f5 100644
--- a/chrome/renderer/printing/chrome_print_render_frame_helper_delegate.h
+++ b/chrome/renderer/printing/chrome_print_render_frame_helper_delegate.h
@@ -5,20 +5,23 @@
 #ifndef CHROME_RENDERER_PRINTING_CHROME_PRINT_RENDER_FRAME_HELPER_DELEGATE_H_
 #define CHROME_RENDERER_PRINTING_CHROME_PRINT_RENDER_FRAME_HELPER_DELEGATE_H_
 
+#include "base/macros.h"
 #include "components/printing/renderer/print_render_frame_helper.h"
 
 class ChromePrintRenderFrameHelperDelegate
     : public printing::PrintRenderFrameHelper::Delegate {
  public:
+  ChromePrintRenderFrameHelperDelegate();
   ~ChromePrintRenderFrameHelperDelegate() override;
 
+ private:
+  // printing::PrintRenderFrameHelper::Delegate:
   bool CancelPrerender(content::RenderFrame* render_frame) override;
-
   blink::WebElement GetPdfElement(blink::WebLocalFrame* frame) override;
-
   bool IsPrintPreviewEnabled() override;
-
   bool OverridePrint(blink::WebLocalFrame* frame) override;
-};  // class ChromePrintRenderFrameHelperDelegate
+
+  DISALLOW_COPY_AND_ASSIGN(ChromePrintRenderFrameHelperDelegate);
+};
 
 #endif  // CHROME_RENDERER_PRINTING_CHROME_PRINT_RENDER_FRAME_HELPER_DELEGATE_H_
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 2bbb110..84f478e 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -784,7 +784,7 @@
       "../browser/ui/search/local_ntp_test_utils.cc",
       "../browser/ui/search/local_ntp_test_utils.h",
       "../browser/ui/search/local_ntp_voice_search_browsertest.cc",
-      "../browser/ui/search/new_tab_page_interceptor_browsertest.cc",
+      "../browser/ui/search/new_tab_page_navigation_throttle_browsertest.cc",
       "../browser/ui/search_engines/search_engine_tab_helper_browsertest.cc",
       "../browser/ui/settings_window_manager_browsertest_chromeos.cc",
       "../browser/ui/startup/startup_browser_creator_browsertest.cc",
@@ -1159,6 +1159,8 @@
         "../browser/extensions/api/passwords_private/passwords_private_apitest.cc",
         "../browser/extensions/api/permissions/permissions_apitest.cc",
         "../browser/extensions/api/platform_keys/platform_keys_apitest_nss.cc",
+        "../browser/extensions/api/platform_keys/platform_keys_test_base.cc",
+        "../browser/extensions/api/platform_keys/platform_keys_test_base.h",
         "../browser/extensions/api/preference/preference_apitest.cc",
         "../browser/extensions/api/preference/preferences_private_apitest.cc",
         "../browser/extensions/api/processes/processes_apitest.cc",
@@ -1697,6 +1699,8 @@
           "../browser/extensions/api/enterprise_device_attributes/enterprise_device_attributes_apitest.cc",
           "../browser/extensions/api/enterprise_platform_keys/enterprise_platform_keys_apitest_nss.cc",
           "../browser/extensions/api/platform_keys/platform_keys_apitest_nss.cc",
+          "../browser/extensions/api/platform_keys/platform_keys_test_base.cc",
+          "../browser/extensions/api/platform_keys/platform_keys_test_base.h",
           "../browser/extensions/api/terminal/terminal_private_apitest.cc",
         ]
       }
@@ -3460,6 +3464,7 @@
       "../common/extensions/permissions/settings_override_permission_unittest.cc",
       "../common/extensions/sync_type_unittest.cc",
       "../renderer/extensions/chrome_native_extension_bindings_system_unittest.cc",
+      "../renderer/extensions/custom_types_unittest.cc",
       "../renderer/extensions/extension_hooks_delegate_unittest.cc",
       "../renderer/extensions/extension_localization_peer_unittest.cc",
       "../renderer/extensions/extension_process_policy_unittest.cc",
@@ -4226,7 +4231,6 @@
       "../browser/ui/app_list/search/mixer_unittest.cc",
       "../browser/ui/app_list/search/omnibox_result_unittest.cc",
       "../browser/ui/app_list/search/suggestions/suggestions_search_provider_unittest.cc",
-      "../browser/ui/app_list/speech_auth_helper_unittest.cc",
       "../browser/ui/app_list/test/fake_app_list_model_updater.cc",
       "../browser/ui/app_list/test/fake_app_list_model_updater.h",
       "../browser/ui/app_list/test/fake_profile.cc",
diff --git a/chrome/test/data/extensions/api_test/enterprise_platform_keys.crx b/chrome/test/data/extensions/api_test/enterprise_platform_keys.crx
index 0e39c5f1..3e4b41fc 100644
--- a/chrome/test/data/extensions/api_test/enterprise_platform_keys.crx
+++ b/chrome/test/data/extensions/api_test/enterprise_platform_keys.crx
Binary files differ
diff --git a/chrome/test/data/extensions/api_test/enterprise_platform_keys/basic.js b/chrome/test/data/extensions/api_test/enterprise_platform_keys/basic.js
index 6684d9f..4773a3a 100644
--- a/chrome/test/data/extensions/api_test/enterprise_platform_keys/basic.js
+++ b/chrome/test/data/extensions/api_test/enterprise_platform_keys/basic.js
@@ -607,7 +607,7 @@
   var testsIndependentOfKeys =
       bindTestsToToken(testsIndependentOfKeysWithTokenParameter, userToken);
   if (systemToken) {
-    testsIndependentOfKeys.concat(bindTestsToToken(
+    testsIndependentOfKeys = testsIndependentOfKeys.concat(bindTestsToToken(
         testsIndependentOfKeysWithTokenParameter, systemToken));
   }
 
diff --git a/chrome/test/data/extensions/api_test/platform_keys/basic.js b/chrome/test/data/extensions/api_test/platform_keys/basic.js
index ee4516d3..afe3316 100644
--- a/chrome/test/data/extensions/api_test/platform_keys/basic.js
+++ b/chrome/test/data/extensions/api_test/platform_keys/basic.js
@@ -64,7 +64,12 @@
   // A signature of raw_data using RSASSA-PKCS1-v1_5 with client_1, using SHA-1
   // as the hash function.
   // Generated by create_net_cert_data.sh .
-  signature_sha1_pkcs: 'signature_sha1_pkcs',
+  signature_client1_sha1_pkcs: 'signature_client1_sha1_pkcs',
+
+  // A signature of raw_data using RSASSA-PKCS1-v1_5 with client_2, using SHA-1
+  // as the hash function.
+  // Generated by create_net_cert_data.sh .
+  signature_client2_sha1_pkcs: 'signature_client2_sha1_pkcs',
 };
 
 // Reads the binary file at |path| and passes it as a Uint8Array to |callback|.
@@ -421,14 +426,48 @@
             .then(callbackPass(function(signature) {
               var actualSignature = new Uint8Array(signature);
               assertTrue(
-                  compareArrays(data.signature_sha1_pkcs, actualSignature) == 0,
+                  compareArrays(
+                      data.signature_client1_sha1_pkcs, actualSignature) == 0,
                   'Incorrect signature');
             }));
       }));
 }
 
-// TODO(pneubeck): Test this by verifying that no private key is returned, once
-// that's implemented.
+function testSignSha1Client2() {
+  var keyParams = {
+    name: 'RSASSA-PKCS1-v1_5',
+    // Algorithm names are case-insensitive.
+    hash: {name: 'Sha-1'}
+  };
+  var signParams = {
+    // Algorithm names are case-insensitive.
+    name: 'RSASSA-Pkcs1-v1_5'
+  };
+  chrome.platformKeys.getKeyPair(
+      data.client_2.buffer, keyParams,
+      callbackPass(function(publicKey, privateKey) {
+        chrome.platformKeys.subtleCrypto()
+            .sign(signParams, privateKey, data.raw_data)
+            .then(callbackPass(function(signature) {
+              var actualSignature = new Uint8Array(signature);
+              assertTrue(
+                  compareArrays(
+                      data.signature_client2_sha1_pkcs, actualSignature) == 0,
+                  'Incorrect signature');
+            }));
+      }));
+}
+
+function testSignSha1Client2OnSystemTokenOnly() {
+  if (systemTokenEnabled) {
+    testSignSha1Client2();
+  } else {
+    testSignClient2Fails();
+  }
+}
+
+// TODO(pmarko,emaxx): Test this by verifying that no private key is returned,
+// once that's implemented, see crbug.com/799410.
 function testSignFails(cert) {
   var keyParams = {
     name: 'RSASSA-PKCS1-v1_5',
@@ -547,6 +586,7 @@
     var tests = [
       testStaticMethods,
 
+      testSignSha1Client2OnSystemTokenOnly,
       // Interactively select client_1 and client_2 to grant permissions for
       // these certificates.
       testInteractiveSelectClient1,
@@ -623,6 +663,10 @@
 
       // Interactively selecting must not show any cert to the user.
       testInteractiveSelectNoCerts,
+
+      // client_2 is on the system token and is thus implicitly a corporate key.
+      // The extension has no access to it.
+      testSignClient2Fails,
     ];
     chrome.test.runTests(tests);
   },
@@ -635,6 +679,10 @@
 
       // Interactively selecting for client_1 will work as well.
       testInteractiveSelectClient1,
+
+      // client_2 is on the system token and is thus implicitly a corporate key.
+      // The extension has access to it.
+      testSignSha1Client2OnSystemTokenOnly,
     ];
     chrome.test.runTests(tests);
   },
diff --git a/chrome/test/data/extensions/api_test/platform_keys/create_net_cert_data.sh b/chrome/test/data/extensions/api_test/platform_keys/create_net_cert_data.sh
index 45e87b6..cfb65a1 100755
--- a/chrome/test/data/extensions/api_test/platform_keys/create_net_cert_data.sh
+++ b/chrome/test/data/extensions/api_test/platform_keys/create_net_cert_data.sh
@@ -27,4 +27,6 @@
 try openssl rsautl -inkey "${net_certs_dir}/client_1.key" -sign -in \
    data -pkcs -out signature_nohash_pkcs
 try openssl dgst -sha1 -sign "${net_certs_dir}/client_1.key" -out \
-   signature_sha1_pkcs data
+   signature_client1_sha1_pkcs data
+try openssl dgst -sha1 -sign "${net_certs_dir}/client_2.key" -out \
+   signature_client2_sha1_pkcs data
diff --git a/chrome/test/data/extensions/api_test/platform_keys/signature_sha1_pkcs b/chrome/test/data/extensions/api_test/platform_keys/signature_client1_sha1_pkcs
similarity index 100%
rename from chrome/test/data/extensions/api_test/platform_keys/signature_sha1_pkcs
rename to chrome/test/data/extensions/api_test/platform_keys/signature_client1_sha1_pkcs
diff --git a/chrome/test/data/extensions/api_test/platform_keys/signature_client2_sha1_pkcs b/chrome/test/data/extensions/api_test/platform_keys/signature_client2_sha1_pkcs
new file mode 100644
index 0000000..56fcfe3
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/platform_keys/signature_client2_sha1_pkcs
Binary files differ
diff --git a/chrome/test/data/extensions/api_test/webstore_private/incorrect_manifest1.js b/chrome/test/data/extensions/api_test/webstore_private/incorrect_manifest1.js
index 9d485b49..310af90 100644
--- a/chrome/test/data/extensions/api_test/webstore_private/incorrect_manifest1.js
+++ b/chrome/test/data/extensions/api_test/webstore_private/incorrect_manifest1.js
@@ -18,7 +18,6 @@
   assertNoLastError();
   assertEq("", result);
 
-  var expectedError = "Manifest file is invalid.";
   chrome.webstorePrivate.completeInstall(extensionId,
                                          callbackPass());
 });
diff --git a/chrome/test/data/extensions/api_test/webstore_private/incorrect_manifest2.js b/chrome/test/data/extensions/api_test/webstore_private/incorrect_manifest2.js
index 7ded818..88d0394 100644
--- a/chrome/test/data/extensions/api_test/webstore_private/incorrect_manifest2.js
+++ b/chrome/test/data/extensions/api_test/webstore_private/incorrect_manifest2.js
@@ -17,7 +17,7 @@
   assertNoLastError();
   assertEq("", result);
 
-  var expectedError = "Manifest file is invalid.";
+  var expectedError = "Manifest file is invalid";
   chrome.webstorePrivate.completeInstall(extensionId,
                                          callbackFail(expectedError));
 });
diff --git a/chrome/test/data/webui/settings/all_sites_tests.js b/chrome/test/data/webui/settings/all_sites_tests.js
index 6a97a48..9b134be 100644
--- a/chrome/test/data/webui/settings/all_sites_tests.js
+++ b/chrome/test/data/webui/settings/all_sites_tests.js
@@ -70,6 +70,7 @@
     sound: [],
     unsandboxed_plugins: [],
     clipboard: [],
+    sensors: [],
   }
 };
 
@@ -134,6 +135,7 @@
     sound: [],
     unsandboxed_plugins: [],
     clipboard: [],
+    sensors: [],
   }
 };
 
diff --git a/chrome/test/data/webui/settings/site_details_tests.js b/chrome/test/data/webui/settings/site_details_tests.js
index d99cfb56..251e21e 100644
--- a/chrome/test/data/webui/settings/site_details_tests.js
+++ b/chrome/test/data/webui/settings/site_details_tests.js
@@ -80,6 +80,9 @@
         clipboard: {
           setting: settings.ContentSetting.ALLOW,
         },
+        sensors: {
+          setting: settings.ContentSetting.ALLOW,
+        },
       },
       exceptions: {
         ads: [createExceptionForTest()],
@@ -108,6 +111,7 @@
         unsandboxed_plugins: [createExceptionForTest()],
         protectedContent: [createExceptionForTest()],
         clipboard: [createExceptionForTest()],
+        sensors: [createExceptionForTest()],
       }
     };
 
@@ -149,6 +153,9 @@
     optionalSiteDetailsContentSettingsTypes[settings.ContentSettingsTypes.ADS] =
         'enableSafeBrowsingSubresourceFilter';
 
+    optionalSiteDetailsContentSettingsTypes[settings.ContentSettingsTypes
+                                                .SENSORS] =
+        'enableSensorsContentSetting';
     browserProxy.setPrefs(prefs);
 
     // First, explicitly set all the optional settings to false.
@@ -217,6 +224,7 @@
     loadTimeData.overrideValues({enableSoundContentSetting: true});
     loadTimeData.overrideValues({enableSafeBrowsingSubresourceFilter: true});
     loadTimeData.overrideValues({enableClipboardContentSetting: true});
+    loadTimeData.overrideValues({enableSensorsContentSetting: true});
     testElement = createSiteDetails('https://foo.com:443');
 
     return browserProxy.whenCalled('isOriginValid')
diff --git a/chrome/test/data/webui/settings/site_list_tests.js b/chrome/test/data/webui/settings/site_list_tests.js
index e11ddb1..ae91172 100644
--- a/chrome/test/data/webui/settings/site_list_tests.js
+++ b/chrome/test/data/webui/settings/site_list_tests.js
@@ -54,6 +54,7 @@
     sound: [],
     unsandboxed_plugins: [],
     clipboard: [],
+    sensors: [],
   }
 };
 
diff --git a/chrome/test/data/webui/settings/test_site_settings_prefs_browser_proxy.js b/chrome/test/data/webui/settings/test_site_settings_prefs_browser_proxy.js
index 1b2e7f5..1a5f28b 100644
--- a/chrome/test/data/webui/settings/test_site_settings_prefs_browser_proxy.js
+++ b/chrome/test/data/webui/settings/test_site_settings_prefs_browser_proxy.js
@@ -36,6 +36,7 @@
     sound: {},
     unsandboxed_plugins: {},
     clipboard: {},
+    sensors: {},
   },
   exceptions: {
     ads: [],
@@ -55,6 +56,7 @@
     sound: [],
     unsandboxed_plugins: [],
     clipboard: [],
+    sensors: [],
   },
 };
 
@@ -271,6 +273,8 @@
       pref = this.prefs_.defaults.protectedContent;
     } else if (contentType == settings.ContentSettingsTypes.CLIPBOARD) {
       pref = this.prefs_.defaults.clipboard;
+    } else if (contentType == settings.ContentSettingsTypes.SENSORS) {
+      pref = this.prefs_.defaults.sensors;
     } else {
       console.log('getDefault received unknown category: ' + contentType);
     }
@@ -320,6 +324,8 @@
       pref = this.prefs_.exceptions.unsandboxed_plugins;
     else if (contentType == settings.ContentSettingsTypes.CLIPBOARD)
       pref = this.prefs_.exceptions.clipboard;
+    else if (contentType == settings.ContentSettingsTypes.SENSORS)
+      pref = this.prefs_.exceptions.sensors;
     else
       console.log('getExceptionList received unknown category: ' + contentType);
 
diff --git a/chromecast/browser/DEPS b/chromecast/browser/DEPS
index 6980cde..511a65d 100644
--- a/chromecast/browser/DEPS
+++ b/chromecast/browser/DEPS
@@ -33,6 +33,7 @@
   "+media/mojo",
   "+mojo/public",
   "+net",
+  "+services/network/public/cpp",
   "+services/service_manager/public",
   "+ui/aura",
   "+ui/base",
diff --git a/chromecast/browser/cast_net_log.cc b/chromecast/browser/cast_net_log.cc
index 123f112..26c33032 100644
--- a/chromecast/browser/cast_net_log.cc
+++ b/chromecast/browser/cast_net_log.cc
@@ -16,6 +16,7 @@
 #include "content/public/common/content_switches.h"
 #include "net/log/file_net_log_observer.h"
 #include "net/log/net_log_util.h"
+#include "services/network/public/cpp/network_switches.h"
 
 namespace chromecast {
 
@@ -44,9 +45,9 @@
   const base::CommandLine* command_line =
       base::CommandLine::ForCurrentProcess();
 
-  if (command_line->HasSwitch(switches::kLogNetLog)) {
+  if (command_line->HasSwitch(network::switches::kLogNetLog)) {
     base::FilePath log_path =
-        command_line->GetSwitchValuePath(switches::kLogNetLog);
+        command_line->GetSwitchValuePath(network::switches::kLogNetLog);
     net::NetLogCaptureMode capture_mode = net::NetLogCaptureMode::Default();
 
     file_net_log_observer_ =
diff --git a/chromeos/BUILD.gn b/chromeos/BUILD.gn
index 0659b2e..88bbc4bc6 100644
--- a/chromeos/BUILD.gn
+++ b/chromeos/BUILD.gn
@@ -463,6 +463,8 @@
     "printing/printer_configuration.h",
     "printing/printer_translator.cc",
     "printing/printer_translator.h",
+    "printing/uri_components.cc",
+    "printing/uri_components.h",
     "process_proxy/process_output_watcher.cc",
     "process_proxy/process_output_watcher.h",
     "process_proxy/process_proxy.cc",
diff --git a/chromeos/chromeos_switches.cc b/chromeos/chromeos_switches.cc
index 8686791..eeb0dab9 100644
--- a/chromeos/chromeos_switches.cc
+++ b/chromeos/chromeos_switches.cc
@@ -662,9 +662,9 @@
 }
 
 bool IsZipArchiverPackerEnabled() {
-  // Enabled by default.
-  return !base::CommandLine::ForCurrentProcess()->HasSwitch(
-      kDisableZipArchiverPacker);
+  // Disabled by default.
+  return base::CommandLine::ForCurrentProcess()->HasSwitch(
+      kEnableZipArchiverPacker);
 }
 
 bool IsSigninFrameClientCertsEnabled() {
diff --git a/chromeos/cryptohome/cryptohome_util.cc b/chromeos/cryptohome/cryptohome_util.cc
index 46f0797..846326a 100644
--- a/chromeos/cryptohome/cryptohome_util.cc
+++ b/chromeos/cryptohome/cryptohome_util.cc
@@ -17,23 +17,37 @@
 
 namespace cryptohome {
 
-MountError BaseReplyToMountError(const base::Optional<BaseReply>& reply) {
+namespace {
+
+bool IsEmpty(const base::Optional<BaseReply>& reply) {
   if (!reply.has_value()) {
-    LOGIN_LOG(ERROR) << "MountEx failed with no reply.";
-    return MOUNT_ERROR_FATAL;
+    LOGIN_LOG(ERROR) << "Cryptohome call failed with empty reply.";
+    return true;
   }
+  return false;
+}
+
+}  // namespace
+
+MountError MountExReplyToMountError(const base::Optional<BaseReply>& reply) {
+  if (IsEmpty(reply))
+    return MOUNT_ERROR_FATAL;
+
   if (!reply->HasExtension(MountReply::reply)) {
     LOGIN_LOG(ERROR) << "MountEx failed with no MountReply extension in reply.";
     return MOUNT_ERROR_FATAL;
   }
-  if (reply->has_error() && reply->error() != CRYPTOHOME_ERROR_NOT_SET) {
-    LOGIN_LOG(ERROR) << "MountEx failed (CryptohomeErrorCode): "
-                     << reply->error();
-  }
   return CryptohomeErrorToMountError(reply->error());
 }
 
-const std::string& BaseReplyToMountHash(const BaseReply& reply) {
+MountError BaseReplyToMountError(const base::Optional<BaseReply>& reply) {
+  if (IsEmpty(reply))
+    return MOUNT_ERROR_FATAL;
+
+  return CryptohomeErrorToMountError(reply->error());
+}
+
+const std::string& MountExReplyToMountHash(const BaseReply& reply) {
   return reply.GetExtension(MountReply::reply).sanitized_username();
 }
 
diff --git a/chromeos/cryptohome/cryptohome_util.h b/chromeos/cryptohome/cryptohome_util.h
index dba8e7d..2a59321a 100644
--- a/chromeos/cryptohome/cryptohome_util.h
+++ b/chromeos/cryptohome/cryptohome_util.h
@@ -21,11 +21,17 @@
 CHROMEOS_EXPORT MountError
 BaseReplyToMountError(const base::Optional<BaseReply>& reply);
 
+// Returns a MountError code from the MountEx |reply| returning
+// MOUNT_ERROR_NONE if the reply is well-formed and there is no error.
+CHROMEOS_EXPORT MountError
+MountExReplyToMountError(const base::Optional<BaseReply>& reply);
+
 // Extracts the mount hash from |reply|.
 // This method assumes |reply| is well-formed. To check if a reply
 // is well-formed, callers can check if BaseReplyToMountError returns
 // MOUNT_ERROR_NONE.
-CHROMEOS_EXPORT const std::string& BaseReplyToMountHash(const BaseReply& reply);
+CHROMEOS_EXPORT const std::string& MountExReplyToMountHash(
+    const BaseReply& reply);
 
 // Creates an AuthorizationRequest from the given secret and label.
 CHROMEOS_EXPORT AuthorizationRequest
diff --git a/chromeos/cryptohome/homedir_methods.cc b/chromeos/cryptohome/homedir_methods.cc
index 1fa80faf..8c79fe92 100644
--- a/chromeos/cryptohome/homedir_methods.cc
+++ b/chromeos/cryptohome/homedir_methods.cc
@@ -82,15 +82,6 @@
                        weak_ptr_factory_.GetWeakPtr(), callback));
   }
 
-  void RenameCryptohome(const Identification& id_from,
-                        const Identification& id_to,
-                        const Callback& callback) override {
-    DBusThreadManager::Get()->GetCryptohomeClient()->RenameCryptohome(
-        id_from, id_to,
-        base::BindOnce(&HomedirMethodsImpl::OnBaseReplyCallback,
-                       weak_ptr_factory_.GetWeakPtr(), callback));
-  }
-
   void GetAccountDiskUsage(
       const Identification& id,
       const GetAccountDiskUsageCallback& callback) override {
diff --git a/chromeos/cryptohome/homedir_methods.h b/chromeos/cryptohome/homedir_methods.h
index 2af3f4d..1cefa325 100644
--- a/chromeos/cryptohome/homedir_methods.h
+++ b/chromeos/cryptohome/homedir_methods.h
@@ -77,12 +77,6 @@
                            const RemoveKeyRequest& request,
                            const Callback& callback) = 0;
 
-  // Asks cryptohomed to change cryptohome identification |id_from| to |id_to|,
-  // which results in cryptohome directory renaming.
-  virtual void RenameCryptohome(const Identification& id_from,
-                                const Identification& id_to,
-                                const Callback& callback) = 0;
-
   // Asks cryptohomed to compute the size of cryptohome for user identified by
   // |id|.
   virtual void GetAccountDiskUsage(
diff --git a/chromeos/cryptohome/mock_homedir_methods.h b/chromeos/cryptohome/mock_homedir_methods.h
index e7c4aa1..ddc4371ad 100644
--- a/chromeos/cryptohome/mock_homedir_methods.h
+++ b/chromeos/cryptohome/mock_homedir_methods.h
@@ -47,10 +47,6 @@
                     const AuthorizationRequest& auth,
                     const UpdateKeyRequest& request,
                     const Callback& callback));
-  MOCK_METHOD3(RenameCryptohome,
-               void(const Identification& id_from,
-                    const Identification& id_to,
-                    const Callback& callback));
   MOCK_METHOD2(GetAccountDiskUsage,
                void(const Identification& id,
                     const GetAccountDiskUsageCallback& callback));
diff --git a/chromeos/dbus/fake_smb_provider_client.cc b/chromeos/dbus/fake_smb_provider_client.cc
index b9bbe715..c59a2f6 100644
--- a/chromeos/dbus/fake_smb_provider_client.cc
+++ b/chromeos/dbus/fake_smb_provider_client.cc
@@ -62,4 +62,15 @@
       FROM_HERE, base::BindOnce(std::move(callback), smbprovider::ERROR_OK));
 }
 
+void FakeSmbProviderClient::ReadFile(int32_t mount_id,
+                                     int32_t file_id,
+                                     int64_t offset,
+                                     int32_t length,
+                                     ReadFileCallback callback) {
+  base::ScopedFD fd;
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::BindOnce(std::move(callback), smbprovider::ERROR_OK,
+                                std::move(fd)));
+}
+
 }  // namespace chromeos
diff --git a/chromeos/dbus/fake_smb_provider_client.h b/chromeos/dbus/fake_smb_provider_client.h
index 976f6604..6d64a1fa4 100644
--- a/chromeos/dbus/fake_smb_provider_client.h
+++ b/chromeos/dbus/fake_smb_provider_client.h
@@ -34,6 +34,11 @@
   void CloseFile(int32_t mount_id,
                  int32_t file_id,
                  StatusCallback callback) override;
+  void ReadFile(int32_t mount_id,
+                int32_t file_id,
+                int64_t offset,
+                int32_t length,
+                ReadFileCallback callback) override;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(FakeSmbProviderClient);
diff --git a/chromeos/dbus/smb_provider_client.cc b/chromeos/dbus/smb_provider_client.cc
index e81de412..21f4839 100644
--- a/chromeos/dbus/smb_provider_client.cc
+++ b/chromeos/dbus/smb_provider_client.cc
@@ -112,6 +112,20 @@
                &SmbProviderClientImpl::HandleCloseFileCallback, &callback);
   }
 
+  void ReadFile(int32_t mount_id,
+                int32_t file_id,
+                int64_t offset,
+                int32_t length,
+                ReadFileCallback callback) override {
+    smbprovider::ReadFileOptions options;
+    options.set_mount_id(mount_id);
+    options.set_file_id(file_id);
+    options.set_offset(offset);
+    options.set_length(length);
+    CallMethod(smbprovider::kReadFileMethod, options,
+               &SmbProviderClientImpl::HandleReadFileCallback, &callback);
+  }
+
  protected:
   // DBusClient override.
   void Init(dbus::Bus* bus) override {
@@ -200,11 +214,35 @@
     if (!response) {
       DLOG(ERROR) << "CloseFile: failed to call smbprovider";
       std::move(callback).Run(smbprovider::ERROR_DBUS_PARSE_FAILED);
+      return;
     }
     dbus::MessageReader reader(response);
     std::move(callback).Run(GetErrorFromReader(&reader));
   }
 
+  // Handles D-Bus callback for ReadFile.
+  void HandleReadFileCallback(ReadFileCallback callback,
+                              dbus::Response* response) {
+    base::ScopedFD fd;
+    if (!response) {
+      LOG(ERROR) << "ReadFile: failed to call smbprovider";
+      std::move(callback).Run(smbprovider::ERROR_DBUS_PARSE_FAILED, fd);
+      return;
+    }
+    dbus::MessageReader reader(response);
+    smbprovider::ErrorType error = GetErrorFromReader(&reader);
+    if (error != smbprovider::ERROR_OK) {
+      std::move(callback).Run(error, fd);
+      return;
+    }
+    if (!reader.PopFileDescriptor(&fd)) {
+      LOG(ERROR) << "ReadFile: failed to parse file descriptor";
+      std::move(callback).Run(smbprovider::ERROR_DBUS_PARSE_FAILED, fd);
+      return;
+    }
+    std::move(callback).Run(smbprovider::ERROR_OK, fd);
+  }
+
   // Handles D-Bus responses for methods that return an error and a protobuf
   // object.
   template <class T>
diff --git a/chromeos/dbus/smb_provider_client.h b/chromeos/dbus/smb_provider_client.h
index 1a54f5b..aa0c1c8 100644
--- a/chromeos/dbus/smb_provider_client.h
+++ b/chromeos/dbus/smb_provider_client.h
@@ -7,6 +7,7 @@
 
 #include "base/callback.h"
 #include "base/files/file_path.h"
+#include "base/files/scoped_file.h"
 #include "chromeos/chromeos_export.h"
 #include "chromeos/dbus/dbus_client.h"
 #include "chromeos/dbus/smbprovider/directory_entry.pb.h"
@@ -31,6 +32,8 @@
       base::OnceCallback<void(smbprovider::ErrorType error,
                               const smbprovider::DirectoryEntryList& entries)>;
   using StatusCallback = base::OnceCallback<void(smbprovider::ErrorType error)>;
+  using ReadFileCallback = base::OnceCallback<void(smbprovider::ErrorType error,
+                                                   const base::ScopedFD& fd)>;
 
   ~SmbProviderClient() override;
 
@@ -76,6 +79,16 @@
                          int32_t file_id,
                          StatusCallback callback) = 0;
 
+  // Calls ReadFile. Using the corresponding mount |mount_id|, this reads the
+  // file with handle |file_id| from |offset| and reads up to |length| in bytes.
+  // The data read is saved to a temporary file and is returned as a file
+  // descriptor in the supplied ReadFileCallback.
+  virtual void ReadFile(int32_t mount_id,
+                        int32_t file_id,
+                        int64_t offset,
+                        int32_t length,
+                        ReadFileCallback callback) = 0;
+
  protected:
   // Create() should be used instead.
   SmbProviderClient();
diff --git a/chromeos/login/auth/cryptohome_authenticator.cc b/chromeos/login/auth/cryptohome_authenticator.cc
index e05f7b2..8c7abfa 100644
--- a/chromeos/login/auth/cryptohome_authenticator.cc
+++ b/chromeos/login/auth/cryptohome_authenticator.cc
@@ -141,11 +141,13 @@
   chromeos::LoginEventRecorder::Get()->AddLoginTimeMarker(
       public_mount ? "CryptohomeMountPublic-End" : "CryptohomeMount-End",
       false);
-  attempt->RecordCryptohomeStatus(BaseReplyToMountError(reply));
-  if (attempt->cryptohome_code() == cryptohome::MOUNT_ERROR_NONE)
-    attempt->RecordUsernameHash(BaseReplyToMountHash(reply.value()));
-  else
+  attempt->RecordCryptohomeStatus(MountExReplyToMountError(reply));
+  if (attempt->cryptohome_code() == cryptohome::MOUNT_ERROR_NONE) {
+    attempt->RecordUsernameHash(MountExReplyToMountHash(reply.value()));
+  } else {
+    LOGIN_LOG(ERROR) << "MountEx failed. Error: " << attempt->cryptohome_code();
     attempt->RecordUsernameHashFailed();
+  }
   resolver->Resolve();
 }
 
@@ -187,7 +189,7 @@
   auth_key->set_secret(key->GetSecret());
   DBusThreadManager::Get()->GetCryptohomeClient()->MountEx(
       cryptohome::Identification(attempt->user_context.GetAccountId()), auth,
-      mount, base::Bind(&OnMount, attempt, resolver));
+      mount, base::BindOnce(&OnMount, attempt, resolver));
 }
 
 // Handle cryptohome migration status.
@@ -195,12 +197,12 @@
                          scoped_refptr<CryptohomeAuthenticator> resolver,
                          bool ephemeral,
                          bool create_if_nonexistent,
-                         bool success,
-                         cryptohome::MountError return_code) {
+                         base::Optional<cryptohome::BaseReply> reply) {
+  cryptohome::MountError return_code = cryptohome::BaseReplyToMountError(reply);
   chromeos::LoginEventRecorder::Get()->AddLoginTimeMarker(
       "CryptohomeRename-End", false);
   const AccountId account_id = attempt->user_context.GetAccountId();
-  if (success) {
+  if (return_code == cryptohome::MOUNT_ERROR_NONE) {
     cryptohome::SetGaiaIdMigrationStatusDone(account_id);
     UMACryptohomeMigrationToGaiaId(CryptohomeMigrationToGaiaId::SUCCESS);
   } else {
@@ -255,11 +257,11 @@
     const std::string cryptohome_id_to =
         attempt->user_context.GetAccountId().GetAccountIdKey();
 
-    cryptohome::HomedirMethods::GetInstance()->RenameCryptohome(
+    DBusThreadManager::Get()->GetCryptohomeClient()->RenameCryptohome(
         cryptohome::Identification::FromString(cryptohome_id_from),
         cryptohome::Identification::FromString(cryptohome_id_to),
-        base::Bind(&OnCryptohomeRenamed, attempt, resolver, ephemeral,
-                   create_if_nonexistent));
+        base::BindOnce(&OnCryptohomeRenamed, attempt, resolver, ephemeral,
+                       create_if_nonexistent));
     return;
   }
   if (!already_migrated && has_account_key) {
@@ -434,7 +436,7 @@
   DBusThreadManager::Get()->GetCryptohomeClient()->MountEx(
       cryptohome::Identification(attempt->user_context.GetAccountId()),
       cryptohome::AuthorizationRequest(), mount,
-      base::Bind(&OnMount, attempt, resolver));
+      base::BindOnce(&OnMount, attempt, resolver));
 }
 
 // Calls cryptohome's key migration method.
diff --git a/chromeos/login/auth/extended_authenticator_impl.cc b/chromeos/login/auth/extended_authenticator_impl.cc
index dd9b490..7ffef93e 100644
--- a/chromeos/login/auth/extended_authenticator_impl.cc
+++ b/chromeos/login/auth/extended_authenticator_impl.cc
@@ -266,11 +266,12 @@
     const UserContext& user_context,
     const ResultCallback& success_callback,
     base::Optional<cryptohome::BaseReply> reply) {
-  cryptohome::MountError return_code = cryptohome::BaseReplyToMountError(reply);
+  cryptohome::MountError return_code =
+      cryptohome::MountExReplyToMountError(reply);
   RecordEndMarker(time_marker);
   if (return_code == cryptohome::MOUNT_ERROR_NONE) {
     const std::string& mount_hash =
-        cryptohome::BaseReplyToMountHash(reply.value());
+        cryptohome::MountExReplyToMountHash(reply.value());
     if (!success_callback.is_null())
       success_callback.Run(mount_hash);
     if (old_consumer_) {
@@ -280,6 +281,7 @@
     }
     return;
   }
+  LOG(ERROR) << "MountEx failed. Error: " << return_code;
   AuthState state = FAILED_MOUNT;
   if (return_code == cryptohome::MOUNT_ERROR_TPM_COMM_ERROR ||
       return_code == cryptohome::MOUNT_ERROR_TPM_DEFEND_LOCK ||
diff --git a/chromeos/printing/printer_configuration.cc b/chromeos/printing/printer_configuration.cc
index fb618e45..34678a43 100644
--- a/chromeos/printing/printer_configuration.cc
+++ b/chromeos/printing/printer_configuration.cc
@@ -7,13 +7,46 @@
 #include <string>
 
 #include "base/guid.h"
+#include "base/optional.h"
 #include "base/strings/string_piece.h"
 #include "base/strings/string_util.h"
 #include "net/base/ip_endpoint.h"
+#include "url/third_party/mozilla/url_parse.h"
 #include "url/url_constants.h"
 
+#include "chromeos/printing/printing_constants.h"
+
 namespace chromeos {
 
+base::Optional<UriComponents> ParseUri(const std::string& printer_uri) {
+  const char* uri_ptr = printer_uri.c_str();
+  url::Parsed parsed;
+  url::ParseStandardURL(uri_ptr, printer_uri.length(), &parsed);
+  if (!parsed.scheme.is_valid() || !parsed.host.is_valid() ||
+      !parsed.path.is_valid()) {
+    return {};
+  }
+  base::StringPiece scheme(&uri_ptr[parsed.scheme.begin], parsed.scheme.len);
+  base::StringPiece host(&uri_ptr[parsed.host.begin], parsed.host.len);
+  base::StringPiece path(&uri_ptr[parsed.path.begin], parsed.path.len);
+
+  bool encrypted = scheme != kIppScheme;
+  int port = ParsePort(uri_ptr, parsed.port);
+  // Port not specified.
+  if (port == url::SpecialPort::PORT_UNSPECIFIED ||
+      port == url::SpecialPort::PORT_INVALID) {
+    if (scheme == kIppScheme) {
+      port = kIppPort;
+    } else if (scheme == kIppsScheme) {
+      port = kIppsPort;
+    }
+  }
+
+  return base::Optional<UriComponents>(base::in_place, encrypted,
+                                       scheme.as_string(), host.as_string(),
+                                       port, path.as_string());
+}
+
 namespace {
 
 // Returns the index of the first character representing the hostname in |uri|.
@@ -121,6 +154,18 @@
   return PrinterProtocol::kUnknown;
 }
 
+std::string Printer::UriForCups() const {
+  if (!effective_uri_.empty()) {
+    return effective_uri_;
+  } else {
+    return uri_;
+  }
+}
+
+base::Optional<UriComponents> Printer::GetUriComponents() const {
+  return chromeos::ParseUri(uri_);
+}
+
 bool Printer::PpdReference::operator==(
     const Printer::PpdReference& other) const {
   return user_supplied_ppd_url == other.user_supplied_ppd_url &&
diff --git a/chromeos/printing/printer_configuration.h b/chromeos/printing/printer_configuration.h
index 7d26aca3..2332d12 100644
--- a/chromeos/printing/printer_configuration.h
+++ b/chromeos/printing/printer_configuration.h
@@ -9,9 +9,13 @@
 #include <string>
 
 #include "base/macros.h"
+#include "base/optional.h"
 #include "base/time/time.h"
 #include "chromeos/chromeos_export.h"
 #include "net/base/host_port_pair.h"
+#include "url/third_party/mozilla/url_parse.h"
+
+#include "chromeos/printing/uri_components.h"
 
 namespace net {
 class IPEndPoint;
@@ -19,6 +23,12 @@
 
 namespace chromeos {
 
+// Parses |printer_uri| into its components and returns an optional
+// UriComponents depending on whether or not |printer_uri| was parsed
+// successfully.
+CHROMEOS_EXPORT base::Optional<UriComponents> ParseUri(
+    const std::string& printer_uri);
+
 class CHROMEOS_EXPORT Printer {
  public:
   // Information needed to find the PPD file for this printer.
@@ -149,6 +159,14 @@
   Source source() const { return source_; }
   void set_source(const Source source) { source_ = source; }
 
+  // Get the URI that we want for talking to cups.
+  std::string UriForCups() const;
+
+  // Parses the printers's uri into its components and returns an optional
+  // containing a UriComponents object depending on whether or not the uri was
+  // successfully parsed.
+  base::Optional<UriComponents> GetUriComponents() const;
+
  private:
   // Globally unique identifier. Empty indicates a new printer.
   std::string id_;
diff --git a/chromeos/printing/printing_constants.h b/chromeos/printing/printing_constants.h
index 1ea5716..08ee41fa 100644
--- a/chromeos/printing/printing_constants.h
+++ b/chromeos/printing/printing_constants.h
@@ -12,6 +12,20 @@
 // arbitrary, we just don't want to try to handle ridiculously huge files.
 constexpr size_t kMaxPpdSizeBytes = 250 * 1024;
 
+// Printing protocol schemes.
+constexpr char kIppScheme[] = "ipp";
+constexpr char kIppsScheme[] = "ipps";
+constexpr char kUsbScheme[] = "usb";
+constexpr char kHttpScheme[] = "http";
+constexpr char kHttpsScheme[] = "https";
+constexpr char kSocketScheme[] = "socket";
+constexpr char kLpdScheme[] = "lpd";
+
+constexpr int kIppPort = 631;
+// IPPS commonly uses the HTTPS port despite the spec saying it should use the
+// IPP port.
+constexpr int kIppsPort = 443;
+
 }  // namespace chromeos
 
 #endif  // CHROMEOS_PRINTING_PRINTING_CONSTANTS_H_
diff --git a/chromeos/printing/uri_components.cc b/chromeos/printing/uri_components.cc
new file mode 100644
index 0000000..fe22f2e
--- /dev/null
+++ b/chromeos/printing/uri_components.cc
@@ -0,0 +1,24 @@
+// 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.
+
+#include "chromeos/printing/uri_components.h"
+
+#include "url/third_party/mozilla/url_parse.h"
+
+namespace chromeos {
+
+UriComponents::UriComponents(bool encrypted,
+                             const std::string& scheme,
+                             const std::string& host,
+                             int port,
+                             const std::string& path)
+    : encrypted_(encrypted),
+      scheme_(scheme),
+      host_(host),
+      port_(port),
+      path_(path) {}
+
+UriComponents::UriComponents(const UriComponents&) = default;
+
+}  // namespace chromeos
diff --git a/chromeos/printing/uri_components.h b/chromeos/printing/uri_components.h
new file mode 100644
index 0000000..96a351f
--- /dev/null
+++ b/chromeos/printing/uri_components.h
@@ -0,0 +1,41 @@
+// 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.
+
+#ifndef CHROMEOS_PRINTING_URI_COMPONENTS_H_
+#define CHROMEOS_PRINTING_URI_COMPONENTS_H_
+
+#include <string>
+
+#include "chromeos/chromeos_export.h"
+#include "url/third_party/mozilla/url_parse.h"
+
+namespace chromeos {
+
+class CHROMEOS_EXPORT UriComponents {
+ public:
+  UriComponents(bool encrypted,
+                const std::string& scheme,
+                const std::string& host,
+                int port,
+                const std::string& path);
+
+  UriComponents(const UriComponents&);
+
+  bool encrypted() const { return encrypted_; }
+  std::string scheme() const { return scheme_; }
+  std::string host() const { return host_; }
+  int port() const { return port_; }
+  std::string path() const { return path_; }
+
+ private:
+  const bool encrypted_;
+  const std::string scheme_;
+  const std::string host_;
+  const int port_;
+  const std::string path_;
+};
+
+}  // namespace chromeos
+
+#endif  // CHROMEOS_PRINTING_URI_COMPONENTS_H_
diff --git a/components/autofill/content/renderer/password_autofill_agent.cc b/components/autofill/content/renderer/password_autofill_agent.cc
index b8f64d41..c7e49cd6 100644
--- a/components/autofill/content/renderer/password_autofill_agent.cc
+++ b/components/autofill/content/renderer/password_autofill_agent.cc
@@ -1717,7 +1717,7 @@
   provisionally_saved_form_.Set(std::move(password_form), form, element);
 
   if (base::FeatureList::IsEnabled(
-          password_manager::features::kEnableManualSaving)) {
+          password_manager::features::kManualSaving)) {
     if (has_password) {
       GetPasswordManagerDriver()->ShowManualFallbackForSaving(
           provisionally_saved_form_.password_form());
diff --git a/components/cast_channel/cast_socket.cc b/components/cast_channel/cast_socket.cc
index 9399587..eacc596 100644
--- a/components/cast_channel/cast_socket.cc
+++ b/components/cast_channel/cast_socket.cc
@@ -47,6 +47,7 @@
 #include "net/socket/tcp_client_socket.h"
 #include "net/ssl/ssl_config_service.h"
 #include "net/ssl/ssl_info.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
 
 // Helper for logging data with remote host IP and authentication state.
 // Assumes |ip_endpoint_| of type net::IPEndPoint and |channel_auth_| of enum
@@ -455,9 +456,33 @@
                           << CastMessageToString(challenge_message);
 
   ResetConnectLoopCallback();
-  // TODO(https://crbug.com/656607): Add proper annotation.
+
+  net::NetworkTrafficAnnotationTag traffic_annotation =
+      net::DefineNetworkTrafficAnnotation("cast_socket", R"(
+        semantics {
+          sender: "Cast Socket"
+          description:
+            "An auth challenge request sent to a Cast device as a part of "
+            "establishing a connection to it."
+          trigger:
+            "A new Cast device has been discovered via mDNS in the local "
+            "network."
+          data:
+            "A serialized protobuf message containing the nonce challenge. No "
+            "user data."
+          destination: OTHER
+          destination_other:
+            "Data will be sent to a Cast device in local network."
+        }
+        policy {
+          cookies_allowed: NO
+          setting:
+            "This request cannot be disabled, but it would not be sent if user "
+            "does not connect a Cast device to the local network."
+          policy_exception_justification: "Not implemented."
+        })");
   transport_->SendMessage(challenge_message, connect_loop_callback_.callback(),
-                          NO_TRAFFIC_ANNOTATION_BUG_656607);
+                          traffic_annotation);
 
   // Always return IO_PENDING since the result is always asynchronous.
   return net::ERR_IO_PENDING;
diff --git a/components/cast_channel/keep_alive_delegate.cc b/components/cast_channel/keep_alive_delegate.cc
index cce0304..082ecc83 100644
--- a/components/cast_channel/keep_alive_delegate.cc
+++ b/components/cast_channel/keep_alive_delegate.cc
@@ -12,6 +12,7 @@
 #include "components/cast_channel/logger.h"
 #include "components/cast_channel/proto/cast_channel.pb.h"
 #include "net/base/net_errors.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
 
 namespace cast_channel {
 
@@ -85,12 +86,34 @@
                                              CastMessageType message_type) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   DVLOG(2) << "Sending " << CastMessageTypeToString(message_type);
-  // TODO(https://crbug.com/656607): Add proper annotation.
+
+  net::NetworkTrafficAnnotationTag traffic_annotation =
+      net::DefineNetworkTrafficAnnotation("cast_keep_alive_delegate", R"(
+        semantics {
+          sender: "Cast Socket Keep Alive Delegate"
+          description:
+            "A ping/pong message sent periodically to a Cast device to keep "
+            "the connection alive."
+          trigger:
+            "Periodically while a connection to a Cast device is established."
+          data:
+            "A protobuf message representing a ping/pong message. No user data."
+          destination: OTHER
+          destination_other:
+            "Data will be sent to a Cast device in local network."
+        }
+        policy {
+          cookies_allowed: NO
+          setting:
+            "This request cannot be disabled, but it would not be sent if user "
+            "does not connect to a Cast device."
+          policy_exception_justification: "Not implemented."
+        })");
   socket_->transport()->SendMessage(
       message,
       base::Bind(&KeepAliveDelegate::SendKeepAliveMessageComplete,
                  base::Unretained(this), message_type),
-      NO_TRAFFIC_ANNOTATION_BUG_656607);
+      traffic_annotation);
 }
 
 void KeepAliveDelegate::SendKeepAliveMessageComplete(
diff --git a/components/crash/content/app/breakpad_win.cc b/components/crash/content/app/breakpad_win.cc
index dd3cab6..47cce0d4 100644
--- a/components/crash/content/app/breakpad_win.cc
+++ b/components/crash/content/app/breakpad_win.cc
@@ -4,12 +4,13 @@
 
 #include "components/crash/content/app/breakpad_win.h"
 
-#include <windows.h>
+#include <crtdbg.h>
 #include <intrin.h>
 #include <shellapi.h>
 #include <stddef.h>
 #include <tchar.h>
 #include <userenv.h>
+#include <windows.h>
 #include <winnt.h>
 
 #include <algorithm>
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data.cc
index 665eb61..be824254 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data.cc
@@ -419,6 +419,11 @@
   DCHECK(data_use_ascriber);
   data_use_observer_.reset(
       new DataReductionProxyDataUseObserver(this, data_use_ascriber));
+
+  // Disable data use ascriber when data saver is not enabled.
+  if (!IsEnabled()) {
+    data_use_ascriber->DisableAscriber();
+  }
 }
 
 void DataReductionProxyIOData::SetPreviewsDecider(
diff --git a/components/data_use_measurement/core/data_use_ascriber.cc b/components/data_use_measurement/core/data_use_ascriber.cc
index 4c549c0..f508dd86 100644
--- a/components/data_use_measurement/core/data_use_ascriber.cc
+++ b/components/data_use_measurement/core/data_use_ascriber.cc
@@ -66,4 +66,6 @@
   recorder->OnUrlRequestDestroyed(request);
 }
 
+void DataUseAscriber::DisableAscriber() {}
+
 }  // namespace data_use_measurement
diff --git a/components/data_use_measurement/core/data_use_ascriber.h b/components/data_use_measurement/core/data_use_ascriber.h
index d271883..9d903aea 100644
--- a/components/data_use_measurement/core/data_use_ascriber.h
+++ b/components/data_use_measurement/core/data_use_ascriber.h
@@ -109,6 +109,9 @@
   virtual void OnUrlRequestCompleted(net::URLRequest* request, bool started);
   virtual void OnUrlRequestDestroyed(net::URLRequest* request);
 
+  // Disables data use ascriber.
+  virtual void DisableAscriber();
+
  protected:
   base::ObserverList<PageLoadObserver> observers_;
 
diff --git a/components/ntp_snippets/BUILD.gn b/components/ntp_snippets/BUILD.gn
index 6129de9..c5473cf 100644
--- a/components/ntp_snippets/BUILD.gn
+++ b/components/ntp_snippets/BUILD.gn
@@ -251,6 +251,7 @@
     "//google_apis/gcm",
     "//net:test_support",
     "//services/identity/public/cpp",
+    "//services/identity/public/cpp:test_support",
     "//testing/gtest",
     "//third_party/icu/",
     "//ui/gfx:test_support",
diff --git a/components/ntp_snippets/contextual/contextual_suggestions_fetcher_impl.cc b/components/ntp_snippets/contextual/contextual_suggestions_fetcher_impl.cc
index cd45f38..40165df1 100644
--- a/components/ntp_snippets/contextual/contextual_suggestions_fetcher_impl.cc
+++ b/components/ntp_snippets/contextual/contextual_suggestions_fetcher_impl.cc
@@ -13,6 +13,7 @@
 #include "components/strings/grit/components_strings.h"
 #include "net/url_request/url_fetcher.h"
 #include "net/url_request/url_request_status.h"
+#include "services/identity/public/cpp/identity_manager.h"
 #include "services/identity/public/cpp/primary_account_access_token_fetcher.h"
 #include "ui/base/l10n/l10n_util.h"
 
@@ -110,13 +111,11 @@
 }  // namespace
 
 ContextualSuggestionsFetcherImpl::ContextualSuggestionsFetcherImpl(
-    SigninManagerBase* signin_manager,
-    OAuth2TokenService* token_service,
+    identity::IdentityManager* identity_manager,
     scoped_refptr<URLRequestContextGetter> url_request_context_getter,
     PrefService* pref_service,
     const ParseJSONCallback& parse_json_callback)
-    : signin_manager_(signin_manager),
-      token_service_(token_service),
+    : identity_manager_(identity_manager),
       url_request_context_getter_(std::move(url_request_context_getter)),
       parse_json_callback_(parse_json_callback),
       fetch_url_(GetFetchEndpoint()) {}
@@ -152,7 +151,7 @@
     SuggestionsAvailableCallback callback,
     const std::string& oauth_access_token) {
   builder.SetUrl(fetch_url_)
-      .SetAuthentication(signin_manager_->GetAuthenticatedAccountId(),
+      .SetAuthentication(identity_manager_->GetPrimaryAccountInfo().account_id,
                          base::StringPrintf(kAuthorizationRequestHeaderFormat,
                                             oauth_access_token.c_str()));
   DVLOG(1) << "ContextualSuggestionsFetcherImpl::StartRequest";
@@ -170,8 +169,8 @@
   }
 
   OAuth2TokenService::ScopeSet scopes{kContentSuggestionsApiScope};
-  token_fetcher_ = std::make_unique<identity::PrimaryAccountAccessTokenFetcher>(
-      "ntp_snippets", signin_manager_, token_service_, scopes,
+  token_fetcher_ = identity_manager_->CreateAccessTokenFetcherForPrimaryAccount(
+      "ntp_snippets", scopes,
       base::BindOnce(
           &ContextualSuggestionsFetcherImpl::AccessTokenFetchFinished,
           base::Unretained(this)),
diff --git a/components/ntp_snippets/contextual/contextual_suggestions_fetcher_impl.h b/components/ntp_snippets/contextual/contextual_suggestions_fetcher_impl.h
index 76bd1c84..5952d1b 100644
--- a/components/ntp_snippets/contextual/contextual_suggestions_fetcher_impl.h
+++ b/components/ntp_snippets/contextual/contextual_suggestions_fetcher_impl.h
@@ -21,11 +21,10 @@
 #include "components/ntp_snippets/status.h"
 #include "net/url_request/url_request_context_getter.h"
 
-class OAuth2TokenService;
 class PrefService;
-class SigninManagerBase;
 
 namespace identity {
+class IdentityManager;
 class PrimaryAccountAccessTokenFetcher;
 }
 
@@ -36,8 +35,7 @@
 class ContextualSuggestionsFetcherImpl : public ContextualSuggestionsFetcher {
  public:
   ContextualSuggestionsFetcherImpl(
-      SigninManagerBase* signin_manager,
-      OAuth2TokenService* token_service,
+      identity::IdentityManager* identity_manager,
       scoped_refptr<net::URLRequestContextGetter> url_request_context_getter,
       PrefService* pref_service,
       const ParseJSONCallback& parse_json_callback);
@@ -77,8 +75,7 @@
                          ContextualSuggestion::PtrVector* suggestions);
 
   // Authentication for signed-in users.
-  SigninManagerBase* signin_manager_;
-  OAuth2TokenService* token_service_;
+  identity::IdentityManager* identity_manager_;
 
   std::unique_ptr<identity::PrimaryAccountAccessTokenFetcher> token_fetcher_;
 
diff --git a/components/ntp_snippets/contextual/contextual_suggestions_fetcher_impl_unittest.cc b/components/ntp_snippets/contextual/contextual_suggestions_fetcher_impl_unittest.cc
index a9615ec1..e0c75e7 100644
--- a/components/ntp_snippets/contextual/contextual_suggestions_fetcher_impl_unittest.cc
+++ b/components/ntp_snippets/contextual/contextual_suggestions_fetcher_impl_unittest.cc
@@ -20,6 +20,7 @@
 #include "google_apis/gaia/fake_oauth2_token_service_delegate.h"
 #include "net/url_request/test_url_fetcher_factory.h"
 #include "net/url_request/url_request_test_util.h"
+#include "services/identity/public/cpp/identity_manager.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -117,14 +118,16 @@
     fake_token_service_ = std::make_unique<FakeProfileOAuth2TokenService>(
         std::make_unique<FakeOAuth2TokenServiceDelegate>(
             request_context_getter.get()));
+    identity_manager_ = std::make_unique<identity::IdentityManager>(
+        test_utils_.fake_signin_manager(), fake_token_service_.get());
     fetcher_ = std::make_unique<ContextualSuggestionsFetcherImpl>(
-        test_utils_.fake_signin_manager(), fake_token_service_.get(),
-        std::move(request_context_getter), test_utils_.pref_service(),
-        base::Bind(&ParseJson));
+        identity_manager_.get(), std::move(request_context_getter),
+        test_utils_.pref_service(), base::BindRepeating(&ParseJson));
     fake_token_service_->AddDiagnosticsObserver(this);
   }
 
   ~ContextualSuggestionsFetcherTest() override {
+    identity_manager_.reset();
     fake_token_service_->RemoveDiagnosticsObserver(this);
   }
 
@@ -133,12 +136,8 @@
   }
 
   void InitializeFakeCredentials() {
-#if defined(OS_CHROMEOS)
-    test_utils_.fake_signin_manager()->SignIn(kTestEmail);
-#else
-    test_utils_.fake_signin_manager()->SignIn(kTestEmail, "user", "password");
-#endif
-    fake_token_service_->GetDelegate()->UpdateCredentials(kTestEmail, "token");
+    identity_manager_->SetPrimaryAccountSynchronouslyForTests(
+        kTestEmail, kTestEmail, "token");
   }
 
   void IssueOAuth2Token() {
@@ -180,6 +179,9 @@
   }
 
   std::unique_ptr<FakeProfileOAuth2TokenService> fake_token_service_;
+
+  // TODO(blundell): Convert this test to use IdentityTestEnvironment.
+  std::unique_ptr<identity::IdentityManager> identity_manager_;
   std::unique_ptr<net::FakeURLFetcherFactory> fake_url_fetcher_factory_;
   std::unique_ptr<ContextualSuggestionsFetcherImpl> fetcher_;
   MockSuggestionsAvailableCallback mock_suggestions_available_callback_;
diff --git a/components/ntp_snippets/remote/remote_suggestions_fetcher_impl_unittest.cc b/components/ntp_snippets/remote/remote_suggestions_fetcher_impl_unittest.cc
index 3df8a732..f0779a4 100644
--- a/components/ntp_snippets/remote/remote_suggestions_fetcher_impl_unittest.cc
+++ b/components/ntp_snippets/remote/remote_suggestions_fetcher_impl_unittest.cc
@@ -27,15 +27,12 @@
 #include "components/ntp_snippets/remote/test_utils.h"
 #include "components/ntp_snippets/user_classifier.h"
 #include "components/prefs/testing_pref_service.h"
-#include "components/signin/core/browser/fake_profile_oauth2_token_service.h"
-#include "components/signin/core/browser/fake_signin_manager.h"
 #include "components/variations/entropy_provider.h"
 #include "components/variations/variations_params_manager.h"
-#include "google_apis/gaia/fake_oauth2_token_service_delegate.h"
 #include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
 #include "net/url_request/test_url_fetcher_factory.h"
 #include "net/url_request/url_request_test_util.h"
-#include "services/identity/public/cpp/identity_manager.h"
+#include "services/identity/public/cpp/identity_test_environment.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -261,9 +258,7 @@
 
 }  // namespace
 
-class RemoteSuggestionsFetcherImplTestBase
-    : public testing::Test,
-      public OAuth2TokenService::DiagnosticsObserver {
+class RemoteSuggestionsFetcherImplTestBase : public testing::Test {
  public:
   explicit RemoteSuggestionsFetcherImplTestBase(const GURL& gurl)
       : default_variation_params_(
@@ -283,8 +278,6 @@
   }
 
   ~RemoteSuggestionsFetcherImplTestBase() override {
-    if (fake_token_service_)
-      fake_token_service_->RemoveDiagnosticsObserver(this);
   }
 
   void ResetFetcher() { ResetFetcherWithAPIKey(kAPIKey); }
@@ -293,25 +286,10 @@
     scoped_refptr<net::TestURLRequestContextGetter> request_context_getter =
         new net::TestURLRequestContextGetter(mock_task_runner_.get());
 
-    if (fake_token_service_) {
-      fake_token_service_->RemoveDiagnosticsObserver(this);
-      identity_manager_.reset();
-    }
-
-    fake_token_service_ = std::make_unique<FakeProfileOAuth2TokenService>(
-        std::make_unique<FakeOAuth2TokenServiceDelegate>(
-            request_context_getter.get()));
-
-    fake_token_service_->AddDiagnosticsObserver(this);
-
-    // TODO(blundell): Convert this test to use IdentityTestEnvironment once
-    // that infrastructure lands in the codebase.
-    identity_manager_ = std::make_unique<identity::IdentityManager>(
-        utils_.fake_signin_manager(), fake_token_service_.get());
-
     fetcher_ = std::make_unique<RemoteSuggestionsFetcherImpl>(
-        identity_manager_.get(), std::move(request_context_getter),
-        utils_.pref_service(), nullptr, base::BindRepeating(&ParseJsonDelayed),
+        identity_test_env_.identity_manager(),
+        std::move(request_context_getter), utils_.pref_service(), nullptr,
+        base::BindRepeating(&ParseJsonDelayed),
         GetFetchEndpoint(version_info::Channel::STABLE), api_key,
         user_classifier_.get());
 
@@ -320,24 +298,8 @@
   }
 
   void SignIn() {
-    identity_manager_->SetPrimaryAccountSynchronouslyForTests(kTestAccount,
-                                                              kTestAccount, "");
-  }
-
-  void IssueRefreshToken() {
-    fake_token_service_->GetDelegate()->UpdateCredentials(kTestAccount,
-                                                          "token");
-  }
-
-  void IssueOAuth2Token() {
-    fake_token_service_->IssueAllTokensForAccount(kTestAccount, "access_token",
-                                                  base::Time::Max());
-  }
-
-  void CancelOAuth2TokenRequests() {
-    fake_token_service_->IssueErrorForAllPendingRequestsForAccount(
-        kTestAccount, GoogleServiceAuthError(
-                          GoogleServiceAuthError::State::REQUEST_CANCELED));
+    identity_test_env_.MakePrimaryAccountAvailable(kTestAccount, kTestAccount,
+                                                   "token");
   }
 
   RemoteSuggestionsFetcher::SnippetsAvailableCallback
@@ -387,23 +349,12 @@
     fake_url_fetcher_factory_->SetFakeResponse(test_url_, response_data,
                                                response_code, status);
   }
-  void set_on_access_token_request_callback(base::OnceClosure callback) {
-    on_access_token_request_callback_ = std::move(callback);
-  }
 
  protected:
   std::map<std::string, std::string> default_variation_params_;
+  identity::IdentityTestEnvironment identity_test_env_;
 
  private:
-  // OAuth2TokenService::DiagnosticsObserver:
-  void OnAccessTokenRequested(
-      const std::string& account_id,
-      const std::string& consumer_id,
-      const OAuth2TokenService::ScopeSet& scopes) override {
-    if (on_access_token_request_callback_)
-      std::move(on_access_token_request_callback_).Run();
-  }
-
   // TODO(tzik): Remove |clock_| after updating GetMockTickClock to own the
   // instance. http://crbug.com/789079
   std::unique_ptr<base::Clock> clock_;
@@ -414,14 +365,11 @@
   FailingFakeURLFetcherFactory failing_url_fetcher_factory_;
   // Initialized lazily in SetFakeResponse().
   std::unique_ptr<net::FakeURLFetcherFactory> fake_url_fetcher_factory_;
-  std::unique_ptr<FakeProfileOAuth2TokenService> fake_token_service_;
-  std::unique_ptr<identity::IdentityManager> identity_manager_;
   std::unique_ptr<RemoteSuggestionsFetcherImpl> fetcher_;
   std::unique_ptr<UserClassifier> user_classifier_;
   MockSnippetsAvailableCallback mock_callback_;
   const GURL test_url_;
   base::HistogramTester histogram_tester_;
-  base::OnceClosure on_access_token_request_callback_;
 
   DISALLOW_COPY_AND_ASSIGN(RemoteSuggestionsFetcherImplTestBase);
 };
@@ -497,11 +445,7 @@
 }
 
 TEST_F(RemoteSuggestionsSignedInFetcherTest, ShouldFetchSuccessfully) {
-  base::RunLoop run_loop;
-  set_on_access_token_request_callback(run_loop.QuitClosure());
-
   SignIn();
-  IssueRefreshToken();
 
   const std::string kJsonStr =
       "{\"categories\" : [{"
@@ -531,9 +475,9 @@
   fetcher().FetchSnippets(test_params(),
                           ToSnippetsAvailableCallback(&mock_callback()));
 
-  run_loop.Run();
+  identity_test_env_.WaitForAccessTokenRequestAndRespondWithToken(
+      "access_token", base::Time::Max());
 
-  IssueOAuth2Token();
   // Wait for the fake response.
   FastForwardUntilNoTasksRemain();
 
@@ -548,11 +492,7 @@
 }
 
 TEST_F(RemoteSuggestionsSignedInFetcherTest, ShouldRetryWhenOAuthCancelled) {
-  base::RunLoop run_loop;
-  set_on_access_token_request_callback(run_loop.QuitClosure());
-
   SignIn();
-  IssueRefreshToken();
 
   const std::string kJsonStr =
       "{\"categories\" : [{"
@@ -582,20 +522,15 @@
   fetcher().FetchSnippets(test_params(),
                           ToSnippetsAvailableCallback(&mock_callback()));
 
-  // Wait for the first access token request to be made.
-  run_loop.Run();
+  // Cancel the first access token request that's made.
+  identity_test_env_.WaitForAccessTokenRequestAndRespondWithError(
+      GoogleServiceAuthError(GoogleServiceAuthError::State::REQUEST_CANCELED));
 
-  // Before cancelling the outstanding access token request, prepare to wait for
-  // the second access token request to be made in response to the cancellation.
-  base::RunLoop run_loop2;
-  set_on_access_token_request_callback(run_loop2.QuitClosure());
+  // RemoteSuggestionsFetcher should retry fetching an access token if the first
+  // attempt is cancelled. Respond with a valid access token on the retry.
+  identity_test_env_.WaitForAccessTokenRequestAndRespondWithToken(
+      "access_token", base::Time::Max());
 
-  CancelOAuth2TokenRequests();
-
-  // Wait for the second access token request to be made.
-  run_loop2.Run();
-
-  IssueOAuth2Token();
   // Wait for the fake response.
   FastForwardUntilNoTasksRemain();
 
diff --git a/components/omnibox/bug-triage.md b/components/omnibox/bug-triage.md
index 2581801a..3c41bb80 100644
--- a/components/omnibox/bug-triage.md
+++ b/components/omnibox/bug-triage.md
@@ -112,7 +112,7 @@
 policies](https://www.chromium.org/for-testers/bug-reporting-guidelines/triage-best-practices).
 *Priority-2* represents wanted for this release but can be punted for a release.
 *Priority-3* are bugs not time sensitive.  There is an even-lower-priority
-state; see the *NextAction=01/09/2018* below.
+state; see the *NextAction=01/08/2019* below.
 
 ### Owners
 
@@ -164,7 +164,7 @@
 | UI>Browser>Omnibox>ZeroSuggest | Suggestions displayed on omnibox focus (both contextual and non-contextual). |
 
 If the bug is extremely low priority, set the **NextAction field** to
-**01/09/2018** and mention that we will "reassess" the bug next year.  This
+**01/08/2019** and mention that we will "reassess" the bug next year.  This
 NextAction field is for Priority-3 bugs that are somehow less important than
 other *priority-3* bugs.  These are bugs we’re sure no one on the team intends
 to fix this year (e.g., really unimportant, or mostly unimportant and hard to
diff --git a/components/page_info_strings.grdp b/components/page_info_strings.grdp
index c8298ef..27af00f 100644
--- a/components/page_info_strings.grdp
+++ b/components/page_info_strings.grdp
@@ -302,6 +302,9 @@
     <message name="IDS_PAGE_INFO_USB_DEVICE_LABEL" desc="The label used to describe a USB device that the user has granted the site permission to access.">
       <ph name="DEVICE_NAME">$1<ex>Android Phone</ex></ph>
     </message>
+    <message name="IDS_PAGE_INFO_USB_DEVICE_SECONDARY_LABEL" desc="The label displayed underneath IDS_PAGE_INFO_USB_DEVICE_LABEL to inform the user that the device name listed is a USB device.">
+      USB device
+    </message>
     <message name="IDS_PAGE_INFO_DELETE_USB_DEVICE" desc="The tooltip displayed when hovering over the button that will remove permission to access a USB device that the user previously granted to the site.">
       Revoke access
     </message>
diff --git a/components/password_manager/core/browser/password_manager.cc b/components/password_manager/core/browser/password_manager.cc
index 91aac72..c4beff27 100644
--- a/components/password_manager/core/browser/password_manager.cc
+++ b/components/password_manager/core/browser/password_manager.cc
@@ -582,6 +582,30 @@
   // Record whether or not this top-level URL has at least one password field.
   client_->AnnotateNavigationEntry(!forms.empty());
 
+  // Only report SSL error status for cases where there are potentially forms to
+  // fill or save from.
+  if (!forms.empty()) {
+    metrics_util::CertificateError cert_error =
+        metrics_util::CertificateError::NONE;
+    const net::CertStatus cert_status = client_->GetMainFrameCertStatus();
+    // The order of the if statements matters -- if the status involves multiple
+    // errors, Chrome should report the one highest up in the list below.
+    if (cert_status & net::CERT_STATUS_AUTHORITY_INVALID)
+      cert_error = metrics_util::CertificateError::AUTHORITY_INVALID;
+    else if (cert_status & net::CERT_STATUS_COMMON_NAME_INVALID)
+      cert_error = metrics_util::CertificateError::COMMON_NAME_INVALID;
+    else if (cert_status & net::CERT_STATUS_WEAK_SIGNATURE_ALGORITHM)
+      cert_error = metrics_util::CertificateError::WEAK_SIGNATURE_ALGORITHM;
+    else if (cert_status & net::CERT_STATUS_DATE_INVALID)
+      cert_error = metrics_util::CertificateError::DATE_INVALID;
+    else if (net::IsCertStatusError(cert_status))
+      cert_error = metrics_util::CertificateError::OTHER;
+
+    UMA_HISTOGRAM_ENUMERATION(
+        "PasswordManager.CertificateErrorsWhileSeeingForms", cert_error,
+        metrics_util::CertificateError::COUNT);
+  }
+
   if (!client_->IsFillingEnabledForCurrentPage())
     return;
 
diff --git a/components/password_manager/core/browser/password_manager_metrics_util.h b/components/password_manager/core/browser/password_manager_metrics_util.h
index d14384c..73d7876 100644
--- a/components/password_manager/core/browser/password_manager_metrics_util.h
+++ b/components/password_manager/core/browser/password_manager_metrics_util.h
@@ -263,6 +263,17 @@
   SHOW_ALL_SAVED_PASSWORDS_CONTEXT_COUNT
 };
 
+// Metrics: "PasswordManager.CertificateErrorsWhileSeeingForms"
+enum class CertificateError {
+  NONE = 0,
+  OTHER = 1,
+  AUTHORITY_INVALID = 2,
+  DATE_INVALID = 3,
+  COMMON_NAME_INVALID = 4,
+  WEAK_SIGNATURE_ALGORITHM = 5,
+  COUNT
+};
+
 // A version of the UMA_HISTOGRAM_BOOLEAN macro that allows the |name|
 // to vary over the program's runtime.
 void LogUMAHistogramBoolean(const std::string& name, bool sample);
diff --git a/components/password_manager/core/browser/password_manager_unittest.cc b/components/password_manager/core/browser/password_manager_unittest.cc
index 9018e95..ac1a60ea 100644
--- a/components/password_manager/core/browser/password_manager_unittest.cc
+++ b/components/password_manager/core/browser/password_manager_unittest.cc
@@ -29,6 +29,7 @@
 #include "components/password_manager/core/browser/stub_password_manager_driver.h"
 #include "components/password_manager/core/common/password_manager_features.h"
 #include "components/password_manager/core/common/password_manager_pref_names.h"
+#include "net/cert/cert_status_flags.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -62,6 +63,7 @@
   }
 
   MOCK_CONST_METHOD0(IsSavingAndFillingEnabledForCurrentPage, bool());
+  MOCK_CONST_METHOD0(GetMainFrameCertStatus, net::CertStatus());
   MOCK_CONST_METHOD0(GetPasswordStore, PasswordStore*());
   // The code inside EXPECT_CALL for PromptUserToSaveOrUpdatePasswordPtr and
   // ShowManualFallbackForSavingPtr owns the PasswordFormManager* argument.
@@ -154,6 +156,7 @@
         .WillRepeatedly(Return(manager_.get()));
     EXPECT_CALL(driver_, GetPasswordAutofillManager())
         .WillRepeatedly(Return(password_autofill_manager_.get()));
+    EXPECT_CALL(client_, GetMainFrameCertStatus()).WillRepeatedly(Return(0));
 
     ON_CALL(client_, GetMainFrameURL()).WillByDefault(ReturnRef(test_url_));
   }
@@ -2207,4 +2210,60 @@
   manager()->OnPasswordFormsRendered(&driver_, observed, true);
 }
 
+// If there are no forms to parse, certificate errors should not be reported.
+TEST_F(PasswordManagerTest, CertErrorReported_NoForms) {
+  const std::vector<PasswordForm> observed;
+  EXPECT_CALL(client_, GetMainFrameCertStatus())
+      .WillRepeatedly(Return(net::CERT_STATUS_AUTHORITY_INVALID));
+  EXPECT_CALL(*store_, GetLogins(_, _))
+      .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms()));
+
+  base::HistogramTester histogram_tester;
+  manager()->OnPasswordFormsParsed(&driver_, observed);
+  histogram_tester.ExpectTotalCount(
+      "PasswordManager.CertificateErrorsWhileSeeingForms", 0);
+}
+
+TEST_F(PasswordManagerTest, CertErrorReported) {
+  constexpr struct {
+    net::CertStatus cert_status;
+    metrics_util::CertificateError expected_error;
+  } kCases[] = {
+      {0, metrics_util::CertificateError::NONE},
+      {net::CERT_STATUS_SHA1_SIGNATURE_PRESENT,  // not an error
+       metrics_util::CertificateError::NONE},
+      {net::CERT_STATUS_COMMON_NAME_INVALID,
+       metrics_util::CertificateError::COMMON_NAME_INVALID},
+      {net::CERT_STATUS_WEAK_SIGNATURE_ALGORITHM,
+       metrics_util::CertificateError::WEAK_SIGNATURE_ALGORITHM},
+      {net::CERT_STATUS_DATE_INVALID,
+       metrics_util::CertificateError::DATE_INVALID},
+      {net::CERT_STATUS_AUTHORITY_INVALID,
+       metrics_util::CertificateError::AUTHORITY_INVALID},
+      {net::CERT_STATUS_WEAK_KEY, metrics_util::CertificateError::OTHER},
+      {net::CERT_STATUS_DATE_INVALID | net::CERT_STATUS_WEAK_KEY,
+       metrics_util::CertificateError::DATE_INVALID},
+      {net::CERT_STATUS_DATE_INVALID | net::CERT_STATUS_AUTHORITY_INVALID,
+       metrics_util::CertificateError::AUTHORITY_INVALID},
+      {net::CERT_STATUS_DATE_INVALID | net::CERT_STATUS_AUTHORITY_INVALID |
+           net::CERT_STATUS_WEAK_KEY,
+       metrics_util::CertificateError::AUTHORITY_INVALID},
+  };
+
+  const std::vector<PasswordForm> observed = {PasswordForm()};
+
+  for (const auto& test_case : kCases) {
+    SCOPED_TRACE(testing::Message("index of test_case = ")
+                 << (&test_case - kCases));
+    EXPECT_CALL(client_, GetMainFrameCertStatus())
+        .WillRepeatedly(Return(test_case.cert_status));
+    base::HistogramTester histogram_tester;
+    EXPECT_CALL(*store_, GetLogins(_, _));
+    manager()->OnPasswordFormsParsed(&driver_, observed);
+    histogram_tester.ExpectUniqueSample(
+        "PasswordManager.CertificateErrorsWhileSeeingForms",
+        test_case.expected_error, 1);
+  }
+}
+
 }  // namespace password_manager
diff --git a/components/password_manager/core/common/password_manager_features.cc b/components/password_manager/core/common/password_manager_features.cc
index b7d2818c..27586a9e 100644
--- a/components/password_manager/core/common/password_manager_features.cc
+++ b/components/password_manager/core/common/password_manager_features.cc
@@ -39,7 +39,7 @@
 // Enable that an omnibox icon is shown when the user types into a password
 // field. When the user clicks on the icon, a password save/update bubble is
 // shown.
-const base::Feature kEnableManualSaving = {"EnableManualSaving",
+const base::Feature kManualSaving = {"ManualSaving",
                                            base::FEATURE_ENABLED_BY_DEFAULT};
 
 // Enable a context menu item in the password field that allows the user
diff --git a/components/password_manager/core/common/password_manager_features.h b/components/password_manager/core/common/password_manager_features.h
index cd495b9f..9d911eb 100644
--- a/components/password_manager/core/common/password_manager_features.h
+++ b/components/password_manager/core/common/password_manager_features.h
@@ -23,7 +23,7 @@
 extern const base::Feature kEnableManualFallbacksFillingStandalone;
 extern const base::Feature kEnableManualFallbacksGeneration;
 extern const base::Feature kEnableManualPasswordGeneration;
-extern const base::Feature kEnableManualSaving;
+extern const base::Feature kManualSaving;
 extern const base::Feature kPasswordForceSaving;
 extern const base::Feature kEnableShowAllSavedPasswordsContextMenu;
 extern const base::Feature kFillOnAccountSelect;
diff --git a/components/policy/resources/policy_templates.json b/components/policy/resources/policy_templates.json
index e6bcd4f..d685b56 100644
--- a/components/policy/resources/policy_templates.json
+++ b/components/policy/resources/policy_templates.json
@@ -5265,7 +5265,7 @@
       'name': 'EnableCommonNameFallbackForLocalAnchors',
       'type': 'main',
       'schema': { 'type': 'boolean' },
-      'supported_on': ['chrome.*:58-65', 'chrome_os:58-65', 'android:58-65'],
+      'supported_on': ['chrome.*:58-66', 'chrome_os:58-66', 'android:58-66'],
       'features': {
         'dynamic_refresh': True,
         'per_profile': False,
diff --git a/components/printing/renderer/print_render_frame_helper.cc b/components/printing/renderer/print_render_frame_helper.cc
index 86c3b7a..74dbf87 100644
--- a/components/printing/renderer/print_render_frame_helper.cc
+++ b/components/printing/renderer/print_render_frame_helper.cc
@@ -932,10 +932,6 @@
   on_ready_.Reset();
 }
 
-bool PrintRenderFrameHelper::Delegate::IsAskPrintSettingsEnabled() {
-  return true;
-}
-
 bool PrintRenderFrameHelper::Delegate::IsScriptedPrintEnabled() {
   return true;
 }
@@ -1491,7 +1487,7 @@
   }
 
   // Ask the browser to show UI to retrieve the final print settings.
-  if (delegate_->IsAskPrintSettingsEnabled()) {
+  {
     // PrintHostMsg_ScriptedPrint in GetPrintSettingsFromUser() will reset
     // |print_scaling_option|, so save the value here and restore it afterwards.
     blink::WebPrintScalingOption scaling_option =
diff --git a/components/printing/renderer/print_render_frame_helper.h b/components/printing/renderer/print_render_frame_helper.h
index b087b9ef..23b3e4e 100644
--- a/components/printing/renderer/print_render_frame_helper.h
+++ b/components/printing/renderer/print_render_frame_helper.h
@@ -99,10 +99,6 @@
 
     virtual bool IsPrintPreviewEnabled() = 0;
 
-    // If true, the user can be asked to provide print settings.
-    // The default implementation returns |true|.
-    virtual bool IsAskPrintSettingsEnabled();
-
     // If false, window.print() won't do anything.
     // The default implementation returns |true|.
     virtual bool IsScriptedPrintEnabled();
diff --git a/components/signin/core/browser/about_signin_internals.cc b/components/signin/core/browser/about_signin_internals.cc
index eadf3b5..10f9e14 100644
--- a/components/signin/core/browser/about_signin_internals.cc
+++ b/components/signin/core/browser/about_signin_internals.cc
@@ -173,9 +173,6 @@
     case signin::AccountConsistencyMethod::kDiceFixAuthErrors:
       return "DICE fixing auth errors";
     case signin::AccountConsistencyMethod::kDicePrepareMigration:
-      return "DICE preparing migration";
-    case signin::AccountConsistencyMethod::
-        kDicePrepareMigrationChromeSyncEndpoint:
       return "DICE preparing migration with Chrome sync Gaia endpoint";
     case signin::AccountConsistencyMethod::kDiceMigration:
       return "DICE migration";
diff --git a/components/signin/core/browser/account_reconcilor_unittest.cc b/components/signin/core/browser/account_reconcilor_unittest.cc
index c8c6e4a..6a8801c 100644
--- a/components/signin/core/browser/account_reconcilor_unittest.cc
+++ b/components/signin/core/browser/account_reconcilor_unittest.cc
@@ -100,8 +100,6 @@
       case signin::AccountConsistencyMethod::kDiceFixAuthErrors:
         return std::make_unique<signin::AccountReconcilorDelegate>();
       case signin::AccountConsistencyMethod::kDicePrepareMigration:
-      case signin::AccountConsistencyMethod::
-          kDicePrepareMigrationChromeSyncEndpoint:
       case signin::AccountConsistencyMethod::kDiceMigration:
       case signin::AccountConsistencyMethod::kDice:
 #if BUILDFLAG(ENABLE_DICE_SUPPORT)
diff --git a/components/signin/core/browser/profile_management_switches.cc b/components/signin/core/browser/profile_management_switches.cc
index 7cf6fc47f..e2a1950e 100644
--- a/components/signin/core/browser/profile_management_switches.cc
+++ b/components/signin/core/browser/profile_management_switches.cc
@@ -38,7 +38,6 @@
     case AccountConsistencyMethod::kMirror:
     case AccountConsistencyMethod::kDiceFixAuthErrors:
     case AccountConsistencyMethod::kDicePrepareMigration:
-    case AccountConsistencyMethod::kDicePrepareMigrationChromeSyncEndpoint:
       return false;
     case AccountConsistencyMethod::kDice:
       return true;
@@ -71,10 +70,7 @@
 const char kAccountConsistencyFeatureMethodDiceFixAuthErrors[] =
     "dice_fix_auth_errors";
 const char kAccountConsistencyFeatureMethodDicePrepareMigration[] =
-    "dice_prepare_migration";
-const char
-    kAccountConsistencyFeatureMethodDicePrepareMigrationChromeSyncEndpoint[] =
-        "dice_prepare_migration_new_endpoint";
+    "dice_prepare_migration_new_endpoint";
 const char kAccountConsistencyFeatureMethodDiceMigration[] = "dice_migration";
 const char kAccountConsistencyFeatureMethodDice[] = "dice";
 
@@ -93,44 +89,38 @@
 #if BUILDFLAG(ENABLE_MIRROR)
   // Mirror is always enabled on Android and iOS.
   return AccountConsistencyMethod::kMirror;
-#else
+#endif
 
 #if BUILDFLAG(ENABLE_DICE_SUPPORT)
   DCHECK(!GetIsGaiaIsolatedCallback()->is_null());
-  if (!GetIsGaiaIsolatedCallback()->Run()) {
-    // Because of limitations in base::Feature, always return kDisabled when
-    // Gaia is not isolated, even though it's not technically a requirement for
-    // all account consistency methods (i.e. kDiceFixAuthErrors could be
-    // allowed).
-    return AccountConsistencyMethod::kDisabled;
-  }
-#endif  // BUILDFLAG(ENABLE_DICE_SUPPORT)
+  const AccountConsistencyMethod kDefaultMethod =
+      AccountConsistencyMethod::kDiceFixAuthErrors;
+
+  if (!GetIsGaiaIsolatedCallback()->Run())
+    return kDefaultMethod;
+#else
+  const AccountConsistencyMethod kDefaultMethod =
+      AccountConsistencyMethod::kDisabled;
+#endif
 
   if (!base::FeatureList::IsEnabled(kAccountConsistencyFeature))
-    return AccountConsistencyMethod::kDisabled;
+    return kDefaultMethod;
 
   std::string method_value = base::GetFieldTrialParamValueByFeature(
       kAccountConsistencyFeature, kAccountConsistencyFeatureMethodParameter);
 
-  if (method_value == kAccountConsistencyFeatureMethodMirror)
-    return AccountConsistencyMethod::kMirror;
-#if BUILDFLAG(ENABLE_DICE_SUPPORT)
-  else if (method_value == kAccountConsistencyFeatureMethodDiceFixAuthErrors)
+  if (method_value == kAccountConsistencyFeatureMethodDiceFixAuthErrors)
     return AccountConsistencyMethod::kDiceFixAuthErrors;
   else if (method_value == kAccountConsistencyFeatureMethodDicePrepareMigration)
     return AccountConsistencyMethod::kDicePrepareMigration;
-  else if (
-      method_value ==
-      kAccountConsistencyFeatureMethodDicePrepareMigrationChromeSyncEndpoint) {
-    return AccountConsistencyMethod::kDicePrepareMigrationChromeSyncEndpoint;
-  } else if (method_value == kAccountConsistencyFeatureMethodDiceMigration)
+  else if (method_value == kAccountConsistencyFeatureMethodDiceMigration)
     return AccountConsistencyMethod::kDiceMigration;
   else if (method_value == kAccountConsistencyFeatureMethodDice)
     return AccountConsistencyMethod::kDice;
-#endif  // BUILDFLAG(ENABLE_DICE_SUPPORT)
+  else if (method_value == kAccountConsistencyFeatureMethodMirror)
+    return AccountConsistencyMethod::kMirror;
 
-  return AccountConsistencyMethod::kDisabled;
-#endif  // BUILDFLAG(ENABLE_MIRROR)
+  return kDefaultMethod;
 }
 
 bool IsAccountConsistencyMirrorEnabled() {
@@ -143,12 +133,6 @@
       AccountConsistencyMethod::kDicePrepareMigration);
 }
 
-bool IsDicePrepareMigrationChromeSyncEndpointEnabled() {
-  return AccountConsistencyMethodGreaterOrEqual(
-      GetAccountConsistencyMethod(),
-      AccountConsistencyMethod::kDicePrepareMigrationChromeSyncEndpoint);
-}
-
 bool IsDiceMigrationEnabled() {
   return AccountConsistencyMethodGreaterOrEqual(
       GetAccountConsistencyMethod(), AccountConsistencyMethod::kDiceMigration);
diff --git a/components/signin/core/browser/profile_management_switches.h b/components/signin/core/browser/profile_management_switches.h
index c4751fc7..90c240d 100644
--- a/components/signin/core/browser/profile_management_switches.h
+++ b/components/signin/core/browser/profile_management_switches.h
@@ -34,8 +34,6 @@
 extern const char kAccountConsistencyFeatureMethodMirror[];
 extern const char kAccountConsistencyFeatureMethodDiceFixAuthErrors[];
 extern const char kAccountConsistencyFeatureMethodDicePrepareMigration[];
-extern const char
-    kAccountConsistencyFeatureMethodDicePrepareMigrationChromeSyncEndpoint[];
 extern const char kAccountConsistencyFeatureMethodDiceMigration[];
 extern const char kAccountConsistencyFeatureMethodDice[];
 
@@ -53,13 +51,9 @@
   kDiceFixAuthErrors,
 
   // Chrome uses the Dice signin flow and silently collects tokens associated
-  // with Gaia cookies to prepare for the migration.
-  kDicePrepareMigration,
-
-  // Chrome uses the Dice signin flow and silently collects tokens associated
   // with Gaia cookies to prepare for the migration. Uses the Chrome sync Gaia
   // endpoint to enable sync.
-  kDicePrepareMigrationChromeSyncEndpoint,
+  kDicePrepareMigration,
 
   // Account management UI on Gaia webpages is enabled once the accounts become
   // consistent.
@@ -85,13 +79,9 @@
 // greater.
 bool IsDiceFixAuthErrorsEnabled();
 
-// Returns true if the account consistency method is kDicePrepareMigration or
-// greater.
-bool IsDicePrepareMigrationEnabled();
-
 // Returns true if the account consistency method is
-// kDicePrepareMigrationChromeSyncEndpoint or greater.
-bool IsDicePrepareMigrationChromeSyncEndpointEnabled();
+// kDicePrepareMigration or greater.
+bool IsDicePrepareMigrationEnabled();
 
 // Returns true if Dice account consistency is enabled or if the Dice migration
 // process is in progress (account consistency method is kDice or
diff --git a/components/signin/core/browser/profile_management_switches_unittest.cc b/components/signin/core/browser/profile_management_switches_unittest.cc
index bc1f103..8aa9c2b 100644
--- a/components/signin/core/browser/profile_management_switches_unittest.cc
+++ b/components/signin/core/browser/profile_management_switches_unittest.cc
@@ -37,8 +37,19 @@
   std::unique_ptr<BooleanPrefMember> dice_pref_member =
       CreateDicePrefMember(&pref_service);
 
-  // By default account consistency is disabled.
+// Check the default account consistency method.
+#if BUILDFLAG(ENABLE_DICE_SUPPORT)
+  EXPECT_EQ(AccountConsistencyMethod::kDiceFixAuthErrors,
+            GetAccountConsistencyMethod());
+#else
   EXPECT_EQ(AccountConsistencyMethod::kDisabled, GetAccountConsistencyMethod());
+  EXPECT_FALSE(IsAccountConsistencyMirrorEnabled());
+  EXPECT_FALSE(IsDiceFixAuthErrorsEnabled());
+  EXPECT_FALSE(IsDiceMigrationEnabled());
+  EXPECT_FALSE(IsDicePrepareMigrationEnabled());
+  EXPECT_FALSE(IsDiceEnabledForProfile(&pref_service));
+  EXPECT_FALSE(IsDiceEnabled(dice_pref_member.get()));
+#endif
 
   struct TestCase {
     AccountConsistencyMethod method;
@@ -49,15 +60,11 @@
     bool expect_dice_migration;
     bool expect_dice_enabled_for_profile;
   } test_cases[] = {
-    {AccountConsistencyMethod::kDisabled, false, false, false, false, false,
-     false},
 #if BUILDFLAG(ENABLE_DICE_SUPPORT)
     {AccountConsistencyMethod::kDiceFixAuthErrors, false, true, false, false,
      false, false},
-    {AccountConsistencyMethod::kDicePrepareMigration, false, true, true, false,
+    {AccountConsistencyMethod::kDicePrepareMigration, false, true, true, true,
      false, false},
-    {AccountConsistencyMethod::kDicePrepareMigrationChromeSyncEndpoint, false,
-     true, true, true, false, false},
     {AccountConsistencyMethod::kDiceMigration, false, true, true, true, true,
      false},
     {AccountConsistencyMethod::kDice, false, true, true, true, true, true},
@@ -73,10 +80,8 @@
     EXPECT_EQ(test_case.expect_dice_fix_auth_errors,
               IsDiceFixAuthErrorsEnabled());
     EXPECT_EQ(test_case.expect_dice_migration, IsDiceMigrationEnabled());
-    EXPECT_EQ(test_case.expect_dice_prepare_migration,
-              IsDicePrepareMigrationEnabled());
     EXPECT_EQ(test_case.expect_dice_prepare_migration_new_endpoint,
-              IsDicePrepareMigrationChromeSyncEndpointEnabled());
+              IsDicePrepareMigrationEnabled());
     EXPECT_EQ(test_case.expect_dice_enabled_for_profile,
               IsDiceEnabledForProfile(&pref_service));
     EXPECT_EQ(test_case.expect_dice_enabled_for_profile,
@@ -100,15 +105,11 @@
   struct TestCase {
     AccountConsistencyMethod method;
     bool expect_dice_enabled_for_profile;
-  } test_cases[] = {
-      {AccountConsistencyMethod::kDisabled, false},
-      {AccountConsistencyMethod::kDiceFixAuthErrors, false},
-      {AccountConsistencyMethod::kDicePrepareMigration, false},
-      {AccountConsistencyMethod::kDicePrepareMigrationChromeSyncEndpoint,
-       false},
-      {AccountConsistencyMethod::kDiceMigration, true},
-      {AccountConsistencyMethod::kDice, true},
-      {AccountConsistencyMethod::kMirror, false}};
+  } test_cases[] = {{AccountConsistencyMethod::kDiceFixAuthErrors, false},
+                    {AccountConsistencyMethod::kDicePrepareMigration, false},
+                    {AccountConsistencyMethod::kDiceMigration, true},
+                    {AccountConsistencyMethod::kDice, true},
+                    {AccountConsistencyMethod::kMirror, false}};
 
   for (const TestCase& test_case : test_cases) {
     ScopedAccountConsistency scoped_method(test_case.method);
diff --git a/components/signin/core/browser/scoped_account_consistency.cc b/components/signin/core/browser/scoped_account_consistency.cc
index 6d111d0..952a08f 100644
--- a/components/signin/core/browser/scoped_account_consistency.cc
+++ b/components/signin/core/browser/scoped_account_consistency.cc
@@ -18,6 +18,7 @@
 
 ScopedAccountConsistency::ScopedAccountConsistency(
     AccountConsistencyMethod method) {
+  DCHECK_NE(AccountConsistencyMethod::kDisabled, method);
 #if !BUILDFLAG(ENABLE_DICE_SUPPORT)
   DCHECK_NE(AccountConsistencyMethod::kDice, method);
   DCHECK_NE(AccountConsistencyMethod::kDiceFixAuthErrors, method);
@@ -30,12 +31,6 @@
 
   signin::SetGaiaOriginIsolatedCallback(base::Bind([] { return true; }));
 
-  if (method == AccountConsistencyMethod::kDisabled) {
-    scoped_feature_list_.InitAndDisableFeature(kAccountConsistencyFeature);
-    DCHECK_EQ(method, GetAccountConsistencyMethod());
-    return;
-  }
-
   // Set up the account consistency method.
   std::string feature_value;
   switch (method) {
@@ -51,10 +46,6 @@
     case AccountConsistencyMethod::kDicePrepareMigration:
       feature_value = kAccountConsistencyFeatureMethodDicePrepareMigration;
       break;
-    case AccountConsistencyMethod::kDicePrepareMigrationChromeSyncEndpoint:
-      feature_value =
-          kAccountConsistencyFeatureMethodDicePrepareMigrationChromeSyncEndpoint;
-      break;
     case AccountConsistencyMethod::kDiceMigration:
       feature_value = kAccountConsistencyFeatureMethodDiceMigration;
       break;
diff --git a/components/signin/core/browser/scoped_account_consistency.h b/components/signin/core/browser/scoped_account_consistency.h
index 5fa9773..0b9db2fd 100644
--- a/components/signin/core/browser/scoped_account_consistency.h
+++ b/components/signin/core/browser/scoped_account_consistency.h
@@ -40,8 +40,6 @@
     DISALLOW_COPY_AND_ASSIGN(ScopedAccountConsistency##method);       \
   }
 
-// ScopedAccountConsistencyDisabled:
-SCOPED_ACCOUNT_CONSISTENCY_SPECIALIZATION(Disabled);
 // ScopedAccountConsistencyMirror:
 SCOPED_ACCOUNT_CONSISTENCY_SPECIALIZATION(Mirror);
 // ScopedAccountConsistencyDiceFixAuthErrors:
diff --git a/components/signin/core/browser/signin_header_helper_unittest.cc b/components/signin/core/browser/signin_header_helper_unittest.cc
index fc8db3f..e3ff9791 100644
--- a/components/signin/core/browser/signin_header_helper_unittest.cc
+++ b/components/signin/core/browser/signin_header_helper_unittest.cc
@@ -213,7 +213,7 @@
 // Tests that the Mirror request is returned when the target is a Gaia URL, even
 // if account consistency is disabled.
 TEST_F(SigninHeaderHelperTest, TestMirrorRequestGaiaURL) {
-  ScopedAccountConsistencyDisabled scoped_no_consistency;
+  ScopedAccountConsistencyDiceFixAuthErrors scoped_dice_fix_auth_errors;
   ASSERT_FALSE(IsAccountConsistencyMirrorEnabled());
   CheckMirrorHeaderRequest(GURL("https://accounts.google.com"), "0123456789",
                            "mode=0,enable_account_consistency=false");
@@ -322,7 +322,7 @@
 // Tests that the Mirror request is returned with the GAIA Id on Drive origin,
 // even if account consistency is disabled.
 TEST_F(SigninHeaderHelperTest, TestMirrorRequestDrive) {
-  ScopedAccountConsistencyDisabled scoped_no_consistency;
+  ScopedAccountConsistencyDiceFixAuthErrors scoped_dice_fix_auth_errors;
   ASSERT_FALSE(IsAccountConsistencyMirrorEnabled());
   CheckMirrorHeaderRequest(
       GURL("https://docs.google.com/document"), "0123456789",
diff --git a/components/viz/service/display/gl_renderer.cc b/components/viz/service/display/gl_renderer.cc
index 66a93a5..86826d2 100644
--- a/components/viz/service/display/gl_renderer.cc
+++ b/components/viz/service/display/gl_renderer.cc
@@ -1384,7 +1384,7 @@
     // |params->filter_image| was populated.
     params->source_needs_flip = kBottomLeft_GrSurfaceOrigin == origin;
   } else if (params->contents_texture) {
-    gl_->BindTexture(GL_TEXTURE_2D, params->contents_texture->id());
+    params->contents_texture->BindForSampling();
     params->contents_and_bypass_color_space =
         params->contents_texture->color_space();
     params->source_needs_flip = params->flip_texture;
@@ -2671,6 +2671,7 @@
 
 void GLRenderer::GenerateMipmap() {
   DCHECK(current_framebuffer_texture_);
+  current_framebuffer_texture_->set_generate_mipmap();
 }
 
 void GLRenderer::SetEnableDCLayers(bool enable) {
diff --git a/components/viz/service/display/gl_renderer_unittest.cc b/components/viz/service/display/gl_renderer_unittest.cc
index 49c429e..3da911f 100644
--- a/components/viz/service/display/gl_renderer_unittest.cc
+++ b/components/viz/service/display/gl_renderer_unittest.cc
@@ -2400,6 +2400,65 @@
   EXPECT_TRUE(output_color_matrix_invoked);
 }
 
+class GenerateMipmapMockGLESInterface : public cc::TestGLES2Interface {
+ public:
+  GenerateMipmapMockGLESInterface() = default;
+
+  MOCK_METHOD3(TexParameteri, void(GLenum target, GLenum pname, GLint param));
+  MOCK_METHOD1(GenerateMipmap, void(GLenum target));
+};
+
+// TODO(crbug.com/803286): Currently npot texture always return false on ubuntu
+// desktop.  The npot texture check is probably failing on desktop GL. This test
+// crashes DCHECK npot texture to catch this. When
+// GLRendererPixelTest.DISABLED_TrilinearFiltering got passed, can remove this.
+TEST_F(GLRendererTest, GenerateMipmap) {
+  // Initialize the mock GL interface, the output surface and the renderer.
+  auto gl_owned = std::make_unique<GenerateMipmapMockGLESInterface>();
+  auto* gl = gl_owned.get();
+  auto provider = cc::TestContextProvider::Create(std::move(gl_owned));
+  provider->BindToCurrentThread();
+  provider->TestContext3d()->set_support_texture_npot(true);
+
+  std::unique_ptr<cc::FakeOutputSurface> output_surface(
+      cc::FakeOutputSurface::Create3d(std::move(provider)));
+  cc::FakeOutputSurfaceClient output_surface_client;
+  output_surface->BindToClient(&output_surface_client);
+  std::unique_ptr<cc::DisplayResourceProvider> resource_provider =
+      cc::FakeResourceProvider::CreateDisplayResourceProvider(
+          output_surface->context_provider(), nullptr);
+  RendererSettings settings;
+  FakeRendererGL renderer(&settings, output_surface.get(),
+                          resource_provider.get());
+  renderer.Initialize();
+  renderer.SetVisible(true);
+
+  gfx::Size viewport_size(100, 100);
+  RenderPassId child_pass_id = 2;
+  // Create a child pass with mipmap to verify that npot texture is enabled.
+  RenderPass* child_pass =
+      cc::AddRenderPass(&render_passes_in_draw_order_, child_pass_id,
+                        gfx::Rect(viewport_size) + gfx::Vector2d(1, 2),
+                        gfx::Transform(), cc::FilterOperations());
+  child_pass->generate_mipmap = true;
+
+  RenderPassId root_pass_id = 1;
+  RenderPass* root_pass = cc::AddRenderPass(
+      &render_passes_in_draw_order_, root_pass_id, gfx::Rect(viewport_size),
+      gfx::Transform(), cc::FilterOperations());
+  root_pass->damage_rect = gfx::Rect(0, 0, 25, 25);
+  cc::AddRenderPassQuad(root_pass, child_pass);
+  renderer.DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
+
+  EXPECT_CALL(*gl, TexParameteri(_, _, _)).Times(4);
+  EXPECT_CALL(*gl, GenerateMipmap(GL_TEXTURE_2D)).Times(1);
+  // When generate_mipmap enabled, the GL_TEXTURE_MIN_FILTER should be
+  // GL_LINEAR_MIPMAP_LINEAR.
+  EXPECT_CALL(*gl, TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
+                                 GL_LINEAR_MIPMAP_LINEAR));
+  DrawFrame(&renderer, viewport_size);
+}
+
 class PartialSwapMockGLES2Interface : public cc::TestGLES2Interface {
  public:
   explicit PartialSwapMockGLES2Interface(bool support_dc_layers)
diff --git a/components/viz/service/display/scoped_render_pass_texture.cc b/components/viz/service/display/scoped_render_pass_texture.cc
index b6e5b54..53b51a2 100644
--- a/components/viz/service/display/scoped_render_pass_texture.cc
+++ b/components/viz/service/display/scoped_render_pass_texture.cc
@@ -96,4 +96,24 @@
   gl_id_ = 0;
 }
 
+void ScopedRenderPassTexture::BindForSampling() {
+  gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL();
+  gl->BindTexture(GL_TEXTURE_2D, gl_id_);
+  switch (mipmap_state_) {
+    case INVALID:
+      break;
+    case GENERATE:
+      // TODO(crbug.com/803286): npot texture always return false on ubuntu
+      // desktop. The npot texture check is probably failing on desktop GL.
+      DCHECK(context_provider_->ContextCapabilities().texture_npot);
+      gl->GenerateMipmap(GL_TEXTURE_2D);
+      mipmap_state_ = VALID;
+    // fall-through
+    case VALID:
+      gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
+                        GL_LINEAR_MIPMAP_LINEAR);
+      break;
+  }
+}
+
 }  // namespace viz
diff --git a/components/viz/service/display/scoped_render_pass_texture.h b/components/viz/service/display/scoped_render_pass_texture.h
index addf61a..b3a79e20 100644
--- a/components/viz/service/display/scoped_render_pass_texture.h
+++ b/components/viz/service/display/scoped_render_pass_texture.h
@@ -31,11 +31,13 @@
 
   ScopedRenderPassTexture(ScopedRenderPassTexture&& other);
   ScopedRenderPassTexture& operator=(ScopedRenderPassTexture&& other);
+  void BindForSampling();
 
   GLuint id() const { return gl_id_; }
   const gfx::Size& size() const { return size_; }
   bool mipmap() const { return mipmap_; }
   const gfx::ColorSpace& color_space() const { return color_space_; }
+  void set_generate_mipmap() { mipmap_state_ = GENERATE; }
 
  private:
   void Free();
@@ -51,6 +53,8 @@
   // TODO(xing.xu): Remove this and set the color space when we draw the
   // RenderPassDrawQuad.
   gfx::ColorSpace color_space_;
+  enum MipmapState { INVALID, GENERATE, VALID };
+  MipmapState mipmap_state_ = INVALID;
 };
 
 }  // namespace viz
diff --git a/content/browser/frame_host/render_frame_host_manager.cc b/content/browser/frame_host/render_frame_host_manager.cc
index 3263eb9..2a054e4 100644
--- a/content/browser/frame_host/render_frame_host_manager.cc
+++ b/content/browser/frame_host/render_frame_host_manager.cc
@@ -2056,8 +2056,8 @@
     if (is_main_frame) {
       render_frame_host_->GetView()->Focus();
     } else {
-      // The main frame's view is already focused, but we need to set
-      // page-level focus in the subframe's renderer.  Before doing that, also
+      // The current tab has page-level focus, so we need to propagate
+      // page-level focus to the subframe's renderer. Before doing that, also
       // tell the new renderer what the focused frame is if that frame is not
       // in its process, so that Blink's page-level focus logic won't try to
       // reset frame focus to the main frame.  See https://crbug.com/802156.
diff --git a/content/browser/loader/cross_site_document_blocking_browsertest.cc b/content/browser/loader/cross_site_document_blocking_browsertest.cc
index 503ca53..f8da0c0 100644
--- a/content/browser/loader/cross_site_document_blocking_browsertest.cc
+++ b/content/browser/loader/cross_site_document_blocking_browsertest.cc
@@ -18,6 +18,7 @@
 #include "content/public/test/test_utils.h"
 #include "content/shell/browser/shell.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
+#include "services/network/public/cpp/network_switches.h"
 #include "testing/gmock/include/gmock/gmock.h"
 
 namespace content {
@@ -54,7 +55,7 @@
     // without having to inject the port number into all URLs), which we can use
     // to create arbitrary SiteInstances.
     command_line->AppendSwitchASCII(
-        switches::kHostResolverRules,
+        network::switches::kHostResolverRules,
         "MAP * " + embedded_test_server()->host_port_pair().ToString() +
             ",EXCLUDE localhost");
 
diff --git a/content/browser/loader/resource_message_filter.cc b/content/browser/loader/resource_message_filter.cc
index 874b809..db2f3ed5 100644
--- a/content/browser/loader/resource_message_filter.cc
+++ b/content/browser/loader/resource_message_filter.cc
@@ -57,9 +57,7 @@
 void ResourceMessageFilter::OnChannelClosing() {
   DCHECK(io_thread_task_runner_->BelongsToCurrentThread());
 
-  // Close all additional Mojo connections opened to this object so that
-  // messages are not dispatched while it is being shut down.
-  bindings_.CloseAllBindings();
+  url_loader_factory_ = nullptr;
 
   // Unhook us from all pending network requests so they don't get sent to a
   // deleted object.
@@ -107,15 +105,14 @@
     return;
   }
 
-  URLLoaderFactoryImpl::CreateLoaderAndStart(
-      requester_info_.get(), std::move(request), routing_id, request_id,
-      options, url_request, std::move(client),
-      net::NetworkTrafficAnnotationTag(traffic_annotation));
+  url_loader_factory_->CreateLoaderAndStart(
+      std::move(request), routing_id, request_id, options, url_request,
+      std::move(client), traffic_annotation);
 }
 
 void ResourceMessageFilter::Clone(
     network::mojom::URLLoaderFactoryRequest request) {
-  bindings_.AddBinding(this, std::move(request));
+  url_loader_factory_->Clone(std::move(request));
 }
 
 int ResourceMessageFilter::child_id() const {
@@ -144,6 +141,7 @@
   // The WeakPtr of the filter must be created on the IO thread. So sets the
   // WeakPtr of |requester_info_| now.
   requester_info_->set_filter(GetWeakPtr());
+  url_loader_factory_ = std::make_unique<URLLoaderFactoryImpl>(requester_info_);
 }
 
 }  // namespace content
diff --git a/content/browser/loader/resource_message_filter.h b/content/browser/loader/resource_message_filter.h
index f0a4253..674e3174 100644
--- a/content/browser/loader/resource_message_filter.h
+++ b/content/browser/loader/resource_message_filter.h
@@ -113,10 +113,7 @@
   bool is_channel_closed_;
   scoped_refptr<ResourceRequesterInfo> requester_info_;
 
-  // An additional set of non-associated bindings (beyond those held by the
-  // BrowserAssociatedInterface parent class) of pipes to this object's
-  // URLLoaderFactory interface.
-  mojo::BindingSet<network::mojom::URLLoaderFactory> bindings_;
+  std::unique_ptr<network::mojom::URLLoaderFactory> url_loader_factory_;
 
   // Task runner for the IO thead.
   scoped_refptr<base::SingleThreadTaskRunner> io_thread_task_runner_;
diff --git a/content/browser/loader/url_loader_factory_impl.cc b/content/browser/loader/url_loader_factory_impl.cc
index a19d764..790b9d4 100644
--- a/content/browser/loader/url_loader_factory_impl.cc
+++ b/content/browser/loader/url_loader_factory_impl.cc
@@ -7,6 +7,7 @@
 #include "base/memory/ptr_util.h"
 #include "content/browser/loader/resource_dispatcher_host_impl.h"
 #include "content/browser/loader/resource_requester_info.h"
+#include "content/public/browser/browser_thread.h"
 #include "mojo/public/cpp/bindings/strong_binding.h"
 #include "net/traffic_annotation/network_traffic_annotation.h"
 #include "services/network/public/cpp/resource_request.h"
@@ -15,19 +16,15 @@
 namespace content {
 
 URLLoaderFactoryImpl::URLLoaderFactoryImpl(
-    scoped_refptr<ResourceRequesterInfo> requester_info,
-    const scoped_refptr<base::SingleThreadTaskRunner>& io_thread_runner)
-    : requester_info_(std::move(requester_info)),
-      io_thread_task_runner_(io_thread_runner) {
+    scoped_refptr<ResourceRequesterInfo> requester_info)
+    : requester_info_(std::move(requester_info)) {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
   DCHECK((requester_info_->IsRenderer() && requester_info_->filter()) ||
          requester_info_->IsNavigationPreload());
-  DCHECK(io_thread_task_runner_->BelongsToCurrentThread());
-  bindings_.set_connection_error_handler(base::Bind(
-      &URLLoaderFactoryImpl::OnConnectionError, base::Unretained(this)));
 }
 
 URLLoaderFactoryImpl::~URLLoaderFactoryImpl() {
-  DCHECK(io_thread_task_runner_->BelongsToCurrentThread());
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
 }
 
 void URLLoaderFactoryImpl::CreateLoaderAndStart(
@@ -38,53 +35,18 @@
     const network::ResourceRequest& url_request,
     network::mojom::URLLoaderClientPtr client,
     const net::MutableNetworkTrafficAnnotationTag& traffic_annotation) {
-  CreateLoaderAndStart(
-      requester_info_.get(), std::move(request), routing_id, request_id,
-      options, url_request, std::move(client),
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  ResourceDispatcherHostImpl* rdh = ResourceDispatcherHostImpl::Get();
+  rdh->OnRequestResourceWithMojo(
+      requester_info_.get(), routing_id, request_id, options, url_request,
+      std::move(request), std::move(client),
       static_cast<net::NetworkTrafficAnnotationTag>(traffic_annotation));
 }
 
 void URLLoaderFactoryImpl::Clone(
     network::mojom::URLLoaderFactoryRequest request) {
+  // The cloned factories stopped working when this factory is destructed.
   bindings_.AddBinding(this, std::move(request));
 }
 
-// static
-void URLLoaderFactoryImpl::CreateLoaderAndStart(
-    ResourceRequesterInfo* requester_info,
-    network::mojom::URLLoaderRequest request,
-    int32_t routing_id,
-    int32_t request_id,
-    uint32_t options,
-    const network::ResourceRequest& url_request,
-    network::mojom::URLLoaderClientPtr client,
-    const net::NetworkTrafficAnnotationTag& traffic_annotation) {
-  DCHECK(ResourceDispatcherHostImpl::Get()
-             ->io_thread_task_runner()
-             ->BelongsToCurrentThread());
-
-  ResourceDispatcherHostImpl* rdh = ResourceDispatcherHostImpl::Get();
-  rdh->OnRequestResourceWithMojo(requester_info, routing_id, request_id,
-                                 options, url_request, std::move(request),
-                                 std::move(client), traffic_annotation);
-}
-
-// static
-void URLLoaderFactoryImpl::Create(
-    scoped_refptr<ResourceRequesterInfo> requester_info,
-    network::mojom::URLLoaderFactoryRequest request,
-    const scoped_refptr<base::SingleThreadTaskRunner>& io_thread_runner) {
-  // This instance is effectively reference counted by the number of pipes open
-  // to it and will get deleted when all clients drop their connections.
-  // Please see OnConnectionError() for details.
-  auto* impl =
-      new URLLoaderFactoryImpl(std::move(requester_info), io_thread_runner);
-  impl->Clone(std::move(request));
-}
-
-void URLLoaderFactoryImpl::OnConnectionError() {
-  if (bindings_.empty())
-    delete this;
-}
-
 }  // namespace content
diff --git a/content/browser/loader/url_loader_factory_impl.h b/content/browser/loader/url_loader_factory_impl.h
index 32c0be4..cf63a765 100644
--- a/content/browser/loader/url_loader_factory_impl.h
+++ b/content/browser/loader/url_loader_factory_impl.h
@@ -18,10 +18,12 @@
 class ResourceRequesterInfo;
 
 // This class is an implementation of network::mojom::URLLoaderFactory that
-// creates a network::mojom::URLLoader. This class is instantiated only for
-// Service Worker navigation preload or test cases.
-class URLLoaderFactoryImpl final : public network::mojom::URLLoaderFactory {
+// creates a network::mojom::URLLoader.
+class CONTENT_EXPORT URLLoaderFactoryImpl final
+    : public network::mojom::URLLoaderFactory {
  public:
+  explicit URLLoaderFactoryImpl(
+      scoped_refptr<ResourceRequesterInfo> requester_info);
   ~URLLoaderFactoryImpl() override;
 
   void CreateLoaderAndStart(network::mojom::URLLoaderRequest request,
@@ -34,37 +36,13 @@
                                 traffic_annotation) override;
   void Clone(network::mojom::URLLoaderFactoryRequest request) override;
 
-  static void CreateLoaderAndStart(
-      ResourceRequesterInfo* requester_info,
-      network::mojom::URLLoaderRequest request,
-      int32_t routing_id,
-      int32_t request_id,
-      uint32_t options,
-      const network::ResourceRequest& url_request,
-      network::mojom::URLLoaderClientPtr client,
-      const net::NetworkTrafficAnnotationTag& traffic_annotation);
-
-  // Creates a URLLoaderFactoryImpl instance. The instance is held by the
-  // StrongBinding in it, so this function doesn't return the instance.
-  CONTENT_EXPORT static void Create(
-      scoped_refptr<ResourceRequesterInfo> requester_info,
-      network::mojom::URLLoaderFactoryRequest request,
-      const scoped_refptr<base::SingleThreadTaskRunner>& io_thread_runner);
-
  private:
-  explicit URLLoaderFactoryImpl(
-      scoped_refptr<ResourceRequesterInfo> requester_info,
-      const scoped_refptr<base::SingleThreadTaskRunner>& io_thread_runner);
-
   void OnConnectionError();
 
   mojo::BindingSet<network::mojom::URLLoaderFactory> bindings_;
 
   scoped_refptr<ResourceRequesterInfo> requester_info_;
 
-  // Task runner for the IO thead.
-  scoped_refptr<base::SingleThreadTaskRunner> io_thread_task_runner_;
-
   DISALLOW_COPY_AND_ASSIGN(URLLoaderFactoryImpl);
 };
 
diff --git a/content/browser/loader/url_loader_factory_impl_unittest.cc b/content/browser/loader/url_loader_factory_impl_unittest.cc
index 0a504b6..42a3702e 100644
--- a/content/browser/loader/url_loader_factory_impl_unittest.cc
+++ b/content/browser/loader/url_loader_factory_impl_unittest.cc
@@ -35,6 +35,7 @@
 #include "mojo/public/c/system/data_pipe.h"
 #include "mojo/public/c/system/types.h"
 #include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/strong_binding.h"
 #include "mojo/public/cpp/system/data_pipe.h"
 #include "net/base/io_buffer.h"
 #include "net/base/net_errors.h"
@@ -103,10 +104,10 @@
     MojoAsyncResourceHandler::SetAllocationSizeForTesting(GetParam());
     rdh_.SetLoaderDelegate(&loader_deleate_);
 
-    URLLoaderFactoryImpl::Create(
-        resource_message_filter_->requester_info_for_test(),
-        mojo::MakeRequest(&factory_),
-        BrowserThread::GetTaskRunnerForThread(BrowserThread::IO));
+    mojo::StrongBinding<network::mojom::URLLoaderFactory>::Create(
+        std::make_unique<URLLoaderFactoryImpl>(
+            resource_message_filter_->requester_info_for_test()),
+        mojo::MakeRequest(&factory_));
 
     // Calling this function creates a request context.
     browser_context_->GetResourceContext()->GetRequestContext();
diff --git a/content/browser/renderer_host/p2p/socket_dispatcher_host.cc b/content/browser/renderer_host/p2p/socket_dispatcher_host.cc
index 41238f6..3bfff890 100644
--- a/content/browser/renderer_host/p2p/socket_dispatcher_host.cc
+++ b/content/browser/renderer_host/p2p/socket_dispatcher_host.cc
@@ -26,6 +26,7 @@
 #include "net/log/net_log_with_source.h"
 #include "net/socket/client_socket_factory.h"
 #include "net/socket/datagram_client_socket.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
 #include "net/url_request/url_request_context_getter.h"
 
 using content::BrowserMessageFilter;
@@ -322,7 +323,9 @@
     return;
   }
 
-  socket->Send(socket_address, data, options, packet_id);
+  // TODO(crbug.com/656607): Get annotation from IPC message.
+  socket->Send(socket_address, data, options, packet_id,
+               NO_TRAFFIC_ANNOTATION_BUG_656607);
 }
 
 void P2PSocketDispatcherHost::OnSetOption(int socket_id,
diff --git a/content/browser/renderer_host/p2p/socket_host.h b/content/browser/renderer_host/p2p/socket_host.h
index a1a50c42..b81a22326 100644
--- a/content/browser/renderer_host/p2p/socket_host.h
+++ b/content/browser/renderer_host/p2p/socket_host.h
@@ -17,6 +17,7 @@
 #include "content/public/browser/render_process_host.h"
 #include "net/base/ip_endpoint.h"
 #include "net/socket/datagram_socket.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
 
 namespace IPC {
 class Sender;
@@ -61,10 +62,12 @@
                     const P2PHostAndIPEndPoint& remote_address) = 0;
 
   // Sends |data| on the socket to |to|.
-  virtual void Send(const net::IPEndPoint& to,
-                    const std::vector<char>& data,
-                    const rtc::PacketOptions& options,
-                    uint64_t packet_id) = 0;
+  virtual void Send(
+      const net::IPEndPoint& to,
+      const std::vector<char>& data,
+      const rtc::PacketOptions& options,
+      uint64_t packet_id,
+      const net::NetworkTrafficAnnotationTag traffic_annotation) = 0;
 
   virtual std::unique_ptr<P2PSocketHost> AcceptIncomingTcpConnection(
       const net::IPEndPoint& remote_address,
diff --git a/content/browser/renderer_host/p2p/socket_host_tcp.cc b/content/browser/renderer_host/p2p/socket_host_tcp.cc
index b0219fe..d1fd53f0db 100644
--- a/content/browser/renderer_host/p2p/socket_host_tcp.cc
+++ b/content/browser/renderer_host/p2p/socket_host_tcp.cc
@@ -53,10 +53,12 @@
 P2PSocketHostTcp::SendBuffer::SendBuffer() : rtc_packet_id(-1) {}
 P2PSocketHostTcp::SendBuffer::SendBuffer(
     int32_t rtc_packet_id,
-    scoped_refptr<net::DrainableIOBuffer> buffer)
-    : rtc_packet_id(rtc_packet_id), buffer(buffer) {}
-P2PSocketHostTcp::SendBuffer::SendBuffer(const SendBuffer& rhs)
-    : rtc_packet_id(rhs.rtc_packet_id), buffer(rhs.buffer) {}
+    scoped_refptr<net::DrainableIOBuffer> buffer,
+    const net::NetworkTrafficAnnotationTag traffic_annotation)
+    : rtc_packet_id(rtc_packet_id),
+      buffer(buffer),
+      traffic_annotation(traffic_annotation) {}
+P2PSocketHostTcp::SendBuffer::SendBuffer(const SendBuffer& rhs) = default;
 P2PSocketHostTcp::SendBuffer::~SendBuffer() {}
 
 P2PSocketHostTcpBase::P2PSocketHostTcpBase(
@@ -363,10 +365,12 @@
 
 // Note: dscp is not actually used on TCP sockets as this point,
 // but may be honored in the future.
-void P2PSocketHostTcpBase::Send(const net::IPEndPoint& to,
-                                const std::vector<char>& data,
-                                const rtc::PacketOptions& options,
-                                uint64_t packet_id) {
+void P2PSocketHostTcpBase::Send(
+    const net::IPEndPoint& to,
+    const std::vector<char>& data,
+    const rtc::PacketOptions& options,
+    uint64_t packet_id,
+    const net::NetworkTrafficAnnotationTag traffic_annotation) {
   if (!socket_) {
     // The Send message may be sent after the an OnError message was
     // sent by hasn't been processed the renderer.
@@ -391,7 +395,7 @@
     }
   }
 
-  DoSend(to, data, options);
+  DoSend(to, data, options, traffic_annotation);
 }
 
 void P2PSocketHostTcpBase::WriteOrQueue(SendBuffer& send_buffer) {
@@ -412,7 +416,8 @@
          !write_pending_) {
     int result = socket_->Write(
         write_buffer_.buffer.get(), write_buffer_.buffer->BytesRemaining(),
-        base::Bind(&P2PSocketHostTcp::OnWritten, base::Unretained(this)));
+        base::Bind(&P2PSocketHostTcp::OnWritten, base::Unretained(this)),
+        net::NetworkTrafficAnnotationTag(write_buffer_.traffic_annotation));
     HandleWriteResult(result);
   }
 }
@@ -543,12 +548,16 @@
   return consumed;
 }
 
-void P2PSocketHostTcp::DoSend(const net::IPEndPoint& to,
-                              const std::vector<char>& data,
-                              const rtc::PacketOptions& options) {
+void P2PSocketHostTcp::DoSend(
+    const net::IPEndPoint& to,
+    const std::vector<char>& data,
+    const rtc::PacketOptions& options,
+    const net::NetworkTrafficAnnotationTag traffic_annotation) {
   int size = kPacketHeaderSize + data.size();
-  SendBuffer send_buffer(options.packet_id, new net::DrainableIOBuffer(
-                                                new net::IOBuffer(size), size));
+  SendBuffer send_buffer(
+      options.packet_id,
+      new net::DrainableIOBuffer(new net::IOBuffer(size), size),
+      traffic_annotation);
   *reinterpret_cast<uint16_t*>(send_buffer.buffer->data()) =
       base::HostToNet16(data.size());
   memcpy(send_buffer.buffer->data() + kPacketHeaderSize, &data[0], data.size());
@@ -599,9 +608,11 @@
   return consumed;
 }
 
-void P2PSocketHostStunTcp::DoSend(const net::IPEndPoint& to,
-                                  const std::vector<char>& data,
-                                  const rtc::PacketOptions& options) {
+void P2PSocketHostStunTcp::DoSend(
+    const net::IPEndPoint& to,
+    const std::vector<char>& data,
+    const rtc::PacketOptions& options,
+    const net::NetworkTrafficAnnotationTag traffic_annotation) {
   // Each packet is expected to have header (STUN/TURN ChannelData), where
   // header contains message type and and length of message.
   if (data.size() < kPacketHeaderSize + kPacketLengthOffset) {
@@ -624,8 +635,10 @@
   // Add any pad bytes to the total size.
   int size = data.size() + pad_bytes;
 
-  SendBuffer send_buffer(options.packet_id, new net::DrainableIOBuffer(
-                                                new net::IOBuffer(size), size));
+  SendBuffer send_buffer(
+      options.packet_id,
+      new net::DrainableIOBuffer(new net::IOBuffer(size), size),
+      traffic_annotation);
   memcpy(send_buffer.buffer->data(), &data[0], data.size());
 
   cricket::ApplyPacketOptions(
diff --git a/content/browser/renderer_host/p2p/socket_host_tcp.h b/content/browser/renderer_host/p2p/socket_host_tcp.h
index e1d673e..e8556c8 100644
--- a/content/browser/renderer_host/p2p/socket_host_tcp.h
+++ b/content/browser/renderer_host/p2p/socket_host_tcp.h
@@ -18,6 +18,7 @@
 #include "content/common/p2p_socket_type.h"
 #include "net/base/completion_callback.h"
 #include "net/base/ip_endpoint.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
 
 namespace net {
 class DrainableIOBuffer;
@@ -47,7 +48,8 @@
   void Send(const net::IPEndPoint& to,
             const std::vector<char>& data,
             const rtc::PacketOptions& options,
-            uint64_t packet_id) override;
+            uint64_t packet_id,
+            const net::NetworkTrafficAnnotationTag traffic_annotation) override;
   std::unique_ptr<P2PSocketHost> AcceptIncomingTcpConnection(
       const net::IPEndPoint& remote_address,
       int id) override;
@@ -56,19 +58,24 @@
  protected:
   struct SendBuffer {
     SendBuffer();
-    SendBuffer(int32_t packet_id, scoped_refptr<net::DrainableIOBuffer> buffer);
+    SendBuffer(int32_t packet_id,
+               scoped_refptr<net::DrainableIOBuffer> buffer,
+               const net::NetworkTrafficAnnotationTag traffic_annotation);
     SendBuffer(const SendBuffer& rhs);
     ~SendBuffer();
 
     int32_t rtc_packet_id;
     scoped_refptr<net::DrainableIOBuffer> buffer;
+    net::MutableNetworkTrafficAnnotationTag traffic_annotation;
   };
 
   // Derived classes will provide the implementation.
   virtual int ProcessInput(char* input, int input_len) = 0;
-  virtual void DoSend(const net::IPEndPoint& to,
-                      const std::vector<char>& data,
-                      const rtc::PacketOptions& options) = 0;
+  virtual void DoSend(
+      const net::IPEndPoint& to,
+      const std::vector<char>& data,
+      const rtc::PacketOptions& options,
+      const net::NetworkTrafficAnnotationTag traffic_annotation) = 0;
 
   void WriteOrQueue(SendBuffer& send_buffer);
   void OnPacket(const std::vector<char>& data);
@@ -123,9 +130,11 @@
 
  protected:
   int ProcessInput(char* input, int input_len) override;
-  void DoSend(const net::IPEndPoint& to,
-              const std::vector<char>& data,
-              const rtc::PacketOptions& options) override;
+  void DoSend(
+      const net::IPEndPoint& to,
+      const std::vector<char>& data,
+      const rtc::PacketOptions& options,
+      const net::NetworkTrafficAnnotationTag traffic_annotation) override;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(P2PSocketHostTcp);
@@ -146,9 +155,11 @@
 
  protected:
   int ProcessInput(char* input, int input_len) override;
-  void DoSend(const net::IPEndPoint& to,
-              const std::vector<char>& data,
-              const rtc::PacketOptions& options) override;
+  void DoSend(
+      const net::IPEndPoint& to,
+      const std::vector<char>& data,
+      const rtc::PacketOptions& options,
+      const net::NetworkTrafficAnnotationTag traffic_annotation) override;
 
  private:
   int GetExpectedPacketSize(const char* data, int len, int* pad_bytes);
diff --git a/content/browser/renderer_host/p2p/socket_host_tcp_server.cc b/content/browser/renderer_host/p2p/socket_host_tcp_server.cc
index fadd45b..b531da6 100644
--- a/content/browser/renderer_host/p2p/socket_host_tcp_server.cc
+++ b/content/browser/renderer_host/p2p/socket_host_tcp_server.cc
@@ -112,10 +112,12 @@
     DoAccept();
 }
 
-void P2PSocketHostTcpServer::Send(const net::IPEndPoint& to,
-                                  const std::vector<char>& data,
-                                  const rtc::PacketOptions& options,
-                                  uint64_t packet_id) {
+void P2PSocketHostTcpServer::Send(
+    const net::IPEndPoint& to,
+    const std::vector<char>& data,
+    const rtc::PacketOptions& options,
+    uint64_t packet_id,
+    const net::NetworkTrafficAnnotationTag traffic_annotation) {
   NOTREACHED();
   OnError();
 }
diff --git a/content/browser/renderer_host/p2p/socket_host_tcp_server.h b/content/browser/renderer_host/p2p/socket_host_tcp_server.h
index e0212b34..1e30a67 100644
--- a/content/browser/renderer_host/p2p/socket_host_tcp_server.h
+++ b/content/browser/renderer_host/p2p/socket_host_tcp_server.h
@@ -20,6 +20,7 @@
 #include "ipc/ipc_sender.h"
 #include "net/base/completion_callback.h"
 #include "net/socket/tcp_server_socket.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
 
 namespace net {
 class StreamSocket;
@@ -42,7 +43,8 @@
   void Send(const net::IPEndPoint& to,
             const std::vector<char>& data,
             const rtc::PacketOptions& options,
-            uint64_t packet_id) override;
+            uint64_t packet_id,
+            const net::NetworkTrafficAnnotationTag traffic_annotation) override;
   std::unique_ptr<P2PSocketHost> AcceptIncomingTcpConnection(
       const net::IPEndPoint& remote_address,
       int id) override;
diff --git a/content/browser/renderer_host/p2p/socket_host_tcp_unittest.cc b/content/browser/renderer_host/p2p/socket_host_tcp_unittest.cc
index e123856..846141b8 100644
--- a/content/browser/renderer_host/p2p/socket_host_tcp_unittest.cc
+++ b/content/browser/renderer_host/p2p/socket_host_tcp_unittest.cc
@@ -13,6 +13,7 @@
 #include "base/sys_byteorder.h"
 #include "content/browser/renderer_host/p2p/socket_host_test_utils.h"
 #include "net/socket/stream_socket.h"
+#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -98,15 +99,18 @@
   rtc::PacketOptions options;
   std::vector<char> packet1;
   CreateStunRequest(&packet1);
-  socket_host_->Send(dest_.ip_address, packet1, options, 0);
+  socket_host_->Send(dest_.ip_address, packet1, options, 0,
+                     TRAFFIC_ANNOTATION_FOR_TESTS);
 
   std::vector<char> packet2;
   CreateStunResponse(&packet2);
-  socket_host_->Send(dest_.ip_address, packet2, options, 0);
+  socket_host_->Send(dest_.ip_address, packet2, options, 0,
+                     TRAFFIC_ANNOTATION_FOR_TESTS);
 
   std::vector<char> packet3;
   CreateStunError(&packet3);
-  socket_host_->Send(dest_.ip_address, packet3, options, 0);
+  socket_host_->Send(dest_.ip_address, packet3, options, 0,
+                     TRAFFIC_ANNOTATION_FOR_TESTS);
 
   std::string expected_data;
   expected_data.append(IntToSize(packet1.size()));
@@ -131,15 +135,18 @@
   rtc::PacketOptions options;
   std::vector<char> packet1;
   CreateStunRequest(&packet1);
-  socket_host_->Send(dest_.ip_address, packet1, options, 0);
+  socket_host_->Send(dest_.ip_address, packet1, options, 0,
+                     TRAFFIC_ANNOTATION_FOR_TESTS);
 
   std::vector<char> packet2;
   CreateStunResponse(&packet2);
-  socket_host_->Send(dest_.ip_address, packet2, options, 0);
+  socket_host_->Send(dest_.ip_address, packet2, options, 0,
+                     TRAFFIC_ANNOTATION_FOR_TESTS);
 
   std::vector<char> packet3;
   CreateStunError(&packet3);
-  socket_host_->Send(dest_.ip_address, packet3, options, 0);
+  socket_host_->Send(dest_.ip_address, packet3, options, 0,
+                     TRAFFIC_ANNOTATION_FOR_TESTS);
 
   std::string received_data;
   received_data.append(IntToSize(packet1.size()));
@@ -178,7 +185,8 @@
   rtc::PacketOptions options;
   std::vector<char> packet;
   CreateRandomPacket(&packet);
-  socket_host_->Send(dest_.ip_address, packet, options, 0);
+  socket_host_->Send(dest_.ip_address, packet, options, 0,
+                     TRAFFIC_ANNOTATION_FOR_TESTS);
 
   EXPECT_EQ(0U, sent_data_.size());
 }
@@ -189,7 +197,8 @@
   EXPECT_CALL(sender_,
               Send(MatchMessage(static_cast<uint32_t>(P2PMsg_OnError::ID))))
       .WillOnce(DoAll(DeleteArg<0>(), Return(true)));
-  socket_host_->Send(dest_.ip_address, {1, 2, 3, 4}, rtc::PacketOptions(), 0);
+  socket_host_->Send(dest_.ip_address, {1, 2, 3, 4}, rtc::PacketOptions(), 0,
+                     TRAFFIC_ANNOTATION_FOR_TESTS);
   testing::Mock::VerifyAndClearExpectations(&sender_);
 
   // Verify that SetOptions() fails, but doesn't crash.
@@ -219,7 +228,8 @@
   // Now we should be able to send any data to |dest_|.
   std::vector<char> packet;
   CreateRandomPacket(&packet);
-  socket_host_->Send(dest_.ip_address, packet, options, 0);
+  socket_host_->Send(dest_.ip_address, packet, options, 0,
+                     TRAFFIC_ANNOTATION_FOR_TESTS);
 
   std::string expected_data;
   expected_data.append(IntToSize(packet.size()));
@@ -244,11 +254,13 @@
   std::vector<char> packet1;
   CreateStunRequest(&packet1);
 
-  socket_host_->Send(dest_.ip_address, packet1, options, 0);
+  socket_host_->Send(dest_.ip_address, packet1, options, 0,
+                     TRAFFIC_ANNOTATION_FOR_TESTS);
 
   std::vector<char> packet2;
   CreateStunResponse(&packet2);
-  socket_host_->Send(dest_.ip_address, packet2, options, 0);
+  socket_host_->Send(dest_.ip_address, packet2, options, 0,
+                     TRAFFIC_ANNOTATION_FOR_TESTS);
 
   base::RunLoop().RunUntilIdle();
 
@@ -279,7 +291,8 @@
   std::vector<char> packet1;
   CreateStunRequest(&packet1);
 
-  socket_host_->Send(dest_.ip_address, packet1, options, 0);
+  socket_host_->Send(dest_.ip_address, packet1, options, 0,
+                     TRAFFIC_ANNOTATION_FOR_TESTS);
 
   base::RunLoop().RunUntilIdle();
 
@@ -313,7 +326,8 @@
   CreateRandomPacket(&packet);
   // Make it a RTP packet.
   *reinterpret_cast<uint16_t*>(&*packet.begin()) = base::HostToNet16(0x8000);
-  socket_host_->Send(dest_.ip_address, packet, options, 0);
+  socket_host_->Send(dest_.ip_address, packet, options, 0,
+                     TRAFFIC_ANNOTATION_FOR_TESTS);
 
   std::string expected_data;
   expected_data.append(IntToSize(packet.size()));
@@ -334,15 +348,18 @@
   rtc::PacketOptions options;
   std::vector<char> packet1;
   CreateStunRequest(&packet1);
-  socket_host_->Send(dest_.ip_address, packet1, options, 0);
+  socket_host_->Send(dest_.ip_address, packet1, options, 0,
+                     TRAFFIC_ANNOTATION_FOR_TESTS);
 
   std::vector<char> packet2;
   CreateStunResponse(&packet2);
-  socket_host_->Send(dest_.ip_address, packet2, options, 0);
+  socket_host_->Send(dest_.ip_address, packet2, options, 0,
+                     TRAFFIC_ANNOTATION_FOR_TESTS);
 
   std::vector<char> packet3;
   CreateStunError(&packet3);
-  socket_host_->Send(dest_.ip_address, packet3, options, 0);
+  socket_host_->Send(dest_.ip_address, packet3, options, 0,
+                     TRAFFIC_ANNOTATION_FOR_TESTS);
 
   std::string expected_data;
   expected_data.append(packet1.begin(), packet1.end());
@@ -364,15 +381,18 @@
   rtc::PacketOptions options;
   std::vector<char> packet1;
   CreateStunRequest(&packet1);
-  socket_host_->Send(dest_.ip_address, packet1, options, 0);
+  socket_host_->Send(dest_.ip_address, packet1, options, 0,
+                     TRAFFIC_ANNOTATION_FOR_TESTS);
 
   std::vector<char> packet2;
   CreateStunResponse(&packet2);
-  socket_host_->Send(dest_.ip_address, packet2, options, 0);
+  socket_host_->Send(dest_.ip_address, packet2, options, 0,
+                     TRAFFIC_ANNOTATION_FOR_TESTS);
 
   std::vector<char> packet3;
   CreateStunError(&packet3);
-  socket_host_->Send(dest_.ip_address, packet3, options, 0);
+  socket_host_->Send(dest_.ip_address, packet3, options, 0,
+                     TRAFFIC_ANNOTATION_FOR_TESTS);
 
   std::string received_data;
   received_data.append(packet1.begin(), packet1.end());
@@ -408,7 +428,8 @@
   rtc::PacketOptions options;
   std::vector<char> packet;
   CreateRandomPacket(&packet);
-  socket_host_->Send(dest_.ip_address, packet, options, 0);
+  socket_host_->Send(dest_.ip_address, packet, options, 0,
+                     TRAFFIC_ANNOTATION_FOR_TESTS);
 
   EXPECT_EQ(0U, sent_data_.size());
 }
@@ -428,11 +449,13 @@
   rtc::PacketOptions options;
   std::vector<char> packet1;
   CreateStunRequest(&packet1);
-  socket_host_->Send(dest_.ip_address, packet1, options, 0);
+  socket_host_->Send(dest_.ip_address, packet1, options, 0,
+                     TRAFFIC_ANNOTATION_FOR_TESTS);
 
   std::vector<char> packet2;
   CreateStunResponse(&packet2);
-  socket_host_->Send(dest_.ip_address, packet2, options, 0);
+  socket_host_->Send(dest_.ip_address, packet2, options, 0,
+                     TRAFFIC_ANNOTATION_FOR_TESTS);
 
   base::RunLoop().RunUntilIdle();
 
diff --git a/content/browser/renderer_host/p2p/socket_host_udp.cc b/content/browser/renderer_host/p2p/socket_host_udp.cc
index 7b484dd5..319cd41 100644
--- a/content/browser/renderer_host/p2p/socket_host_udp.cc
+++ b/content/browser/renderer_host/p2p/socket_host_udp.cc
@@ -78,12 +78,14 @@
     const net::IPEndPoint& to,
     const std::vector<char>& content,
     const rtc::PacketOptions& options,
-    uint64_t id)
+    uint64_t id,
+    const net::NetworkTrafficAnnotationTag traffic_annotation)
     : to(to),
       data(new net::IOBuffer(content.size())),
       size(content.size()),
       packet_options(options),
-      id(id) {
+      id(id),
+      traffic_annotation(traffic_annotation) {
   memcpy(data->data(), &content[0], size);
 }
 
@@ -263,10 +265,12 @@
   }
 }
 
-void P2PSocketHostUdp::Send(const net::IPEndPoint& to,
-                            const std::vector<char>& data,
-                            const rtc::PacketOptions& options,
-                            uint64_t packet_id) {
+void P2PSocketHostUdp::Send(
+    const net::IPEndPoint& to,
+    const std::vector<char>& data,
+    const rtc::PacketOptions& options,
+    uint64_t packet_id,
+    const net::NetworkTrafficAnnotationTag traffic_annotation) {
   if (!socket_) {
     // The Send message may be sent after the an OnError message was
     // sent by hasn't been processed the renderer.
@@ -276,11 +280,12 @@
   IncrementTotalSentPackets();
 
   if (send_pending_) {
-    send_queue_.push_back(PendingPacket(to, data, options, packet_id));
+    send_queue_.push_back(
+        PendingPacket(to, data, options, packet_id, traffic_annotation));
     IncrementDelayedBytes(data.size());
     IncrementDelayedPackets();
   } else {
-    PendingPacket packet(to, data, options, packet_id);
+    PendingPacket packet(to, data, options, packet_id, traffic_annotation);
     DoSend(packet);
   }
 }
@@ -344,6 +349,9 @@
   auto callback_binding =
       base::Bind(&P2PSocketHostUdp::OnSend, base::Unretained(this), packet.id,
                  packet.packet_options.packet_id, send_time);
+
+  // TODO(crbug.com/656607): Pass traffic annotation after DatagramSocketServer
+  // is updated.
   int result = socket_->SendTo(packet.data.get(), packet.size, packet.to,
                                callback_binding);
 
diff --git a/content/browser/renderer_host/p2p/socket_host_udp.h b/content/browser/renderer_host/p2p/socket_host_udp.h
index 5e4bd80..401dfa6 100644
--- a/content/browser/renderer_host/p2p/socket_host_udp.h
+++ b/content/browser/renderer_host/p2p/socket_host_udp.h
@@ -24,6 +24,7 @@
 #include "net/base/ip_endpoint.h"
 #include "net/socket/diff_serv_code_point.h"
 #include "net/socket/udp_server_socket.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
 #include "third_party/webrtc/rtc_base/asyncpacketsocket.h"
 
 namespace net {
@@ -58,7 +59,8 @@
   void Send(const net::IPEndPoint& to,
             const std::vector<char>& data,
             const rtc::PacketOptions& options,
-            uint64_t packet_id) override;
+            uint64_t packet_id,
+            const net::NetworkTrafficAnnotationTag traffic_annotation) override;
   std::unique_ptr<P2PSocketHost> AcceptIncomingTcpConnection(
       const net::IPEndPoint& remote_address,
       int id) override;
@@ -73,7 +75,8 @@
     PendingPacket(const net::IPEndPoint& to,
                   const std::vector<char>& content,
                   const rtc::PacketOptions& options,
-                  uint64_t id);
+                  uint64_t id,
+                  const net::NetworkTrafficAnnotationTag traffic_annotation);
     PendingPacket(const PendingPacket& other);
     ~PendingPacket();
     net::IPEndPoint to;
@@ -81,6 +84,7 @@
     int size;
     rtc::PacketOptions packet_options;
     uint64_t id;
+    const net::NetworkTrafficAnnotationTag traffic_annotation;
   };
 
   void OnError();
diff --git a/content/browser/renderer_host/p2p/socket_host_udp_unittest.cc b/content/browser/renderer_host/p2p/socket_host_udp_unittest.cc
index 924bf66..e286adb 100644
--- a/content/browser/renderer_host/p2p/socket_host_udp_unittest.cc
+++ b/content/browser/renderer_host/p2p/socket_host_udp_unittest.cc
@@ -19,6 +19,7 @@
 #include "net/base/net_errors.h"
 #include "net/log/net_log_with_source.h"
 #include "net/socket/datagram_server_socket.h"
+#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -251,15 +252,15 @@
   rtc::PacketOptions options;
   std::vector<char> packet1;
   CreateStunRequest(&packet1);
-  socket_host_->Send(dest1_, packet1, options, 0);
+  socket_host_->Send(dest1_, packet1, options, 0, TRAFFIC_ANNOTATION_FOR_TESTS);
 
   std::vector<char> packet2;
   CreateStunResponse(&packet2);
-  socket_host_->Send(dest1_, packet2, options, 0);
+  socket_host_->Send(dest1_, packet2, options, 0, TRAFFIC_ANNOTATION_FOR_TESTS);
 
   std::vector<char> packet3;
   CreateStunError(&packet3);
-  socket_host_->Send(dest1_, packet3, options, 0);
+  socket_host_->Send(dest1_, packet3, options, 0, TRAFFIC_ANNOTATION_FOR_TESTS);
 
   ASSERT_EQ(sent_packets_.size(), 3U);
   ASSERT_EQ(sent_packets_[0].second, packet1);
@@ -277,7 +278,7 @@
   rtc::PacketOptions options;
   std::vector<char> packet;
   CreateRandomPacket(&packet);
-  socket_host_->Send(dest1_, packet, options, 0);
+  socket_host_->Send(dest1_, packet, options, 0, TRAFFIC_ANNOTATION_FOR_TESTS);
 
   ASSERT_EQ(sent_packets_.size(), 0U);
 }
@@ -288,7 +289,8 @@
   EXPECT_CALL(sender_,
               Send(MatchMessage(static_cast<uint32_t>(P2PMsg_OnError::ID))))
       .WillOnce(DoAll(DeleteArg<0>(), Return(true)));
-  socket_host_->Send(dest1_, {1, 2, 3, 4}, rtc::PacketOptions(), 0);
+  socket_host_->Send(dest1_, {1, 2, 3, 4}, rtc::PacketOptions(), 0,
+                     TRAFFIC_ANNOTATION_FOR_TESTS);
   testing::Mock::VerifyAndClearExpectations(&sender_);
 
   // Verify that SetOptions() fails, but doesn't crash.
@@ -315,7 +317,7 @@
   rtc::PacketOptions options;
   std::vector<char> packet;
   CreateRandomPacket(&packet);
-  socket_host_->Send(dest1_, packet, options, 0);
+  socket_host_->Send(dest1_, packet, options, 0, TRAFFIC_ANNOTATION_FOR_TESTS);
 
   ASSERT_EQ(1U, sent_packets_.size());
   ASSERT_EQ(dest1_, sent_packets_[0].first);
@@ -341,7 +343,7 @@
   rtc::PacketOptions options;
   std::vector<char> packet;
   CreateRandomPacket(&packet);
-  socket_host_->Send(dest1_, packet, options, 0);
+  socket_host_->Send(dest1_, packet, options, 0, TRAFFIC_ANNOTATION_FOR_TESTS);
 
   ASSERT_EQ(1U, sent_packets_.size());
   ASSERT_EQ(dest1_, sent_packets_[0].first);
@@ -365,7 +367,7 @@
   EXPECT_CALL(sender_,
               Send(MatchMessage(static_cast<uint32_t>(P2PMsg_OnError::ID))))
       .WillOnce(DoAll(DeleteArg<0>(), Return(true)));
-  socket_host_->Send(dest2_, packet, options, 0);
+  socket_host_->Send(dest2_, packet, options, 0, TRAFFIC_ANNOTATION_FOR_TESTS);
 }
 
 // Verify throttler not allowing unlimited sending of ICE messages to
@@ -381,12 +383,12 @@
   std::vector<char> packet1;
   CreateStunRequest(&packet1);
   throttler_.SetSendIceBandwidth(packet1.size() * 2);
-  socket_host_->Send(dest1_, packet1, options, 0);
-  socket_host_->Send(dest2_, packet1, options, 0);
+  socket_host_->Send(dest1_, packet1, options, 0, TRAFFIC_ANNOTATION_FOR_TESTS);
+  socket_host_->Send(dest2_, packet1, options, 0, TRAFFIC_ANNOTATION_FOR_TESTS);
 
   net::IPEndPoint dest3 = ParseAddress(kTestIpAddress1, 2222);
   // This packet must be dropped by the throttler.
-  socket_host_->Send(dest3, packet1, options, 0);
+  socket_host_->Send(dest3, packet1, options, 0, TRAFFIC_ANNOTATION_FOR_TESTS);
   ASSERT_EQ(sent_packets_.size(), 2U);
 }
 
@@ -412,21 +414,21 @@
   CreateStunRequest(&packet1);
   throttler_.SetSendIceBandwidth(packet1.size());
   // |dest1_| is known address, throttling will not be applied.
-  socket_host_->Send(dest1_, packet1, options, 0);
+  socket_host_->Send(dest1_, packet1, options, 0, TRAFFIC_ANNOTATION_FOR_TESTS);
   // Trying to send the packet to dest1_ in the same window. It should go.
-  socket_host_->Send(dest1_, packet1, options, 0);
+  socket_host_->Send(dest1_, packet1, options, 0, TRAFFIC_ANNOTATION_FOR_TESTS);
 
   // Throttler should allow this packet to go through.
-  socket_host_->Send(dest2_, packet1, options, 0);
+  socket_host_->Send(dest2_, packet1, options, 0, TRAFFIC_ANNOTATION_FOR_TESTS);
 
   net::IPEndPoint dest3 = ParseAddress(kTestIpAddress1, 2223);
   // This packet will be dropped, as limit only for a single packet.
-  socket_host_->Send(dest3, packet1, options, 0);
+  socket_host_->Send(dest3, packet1, options, 0, TRAFFIC_ANNOTATION_FOR_TESTS);
   net::IPEndPoint dest4 = ParseAddress(kTestIpAddress1, 2224);
   // This packet should also be dropped.
-  socket_host_->Send(dest4, packet1, options, 0);
+  socket_host_->Send(dest4, packet1, options, 0, TRAFFIC_ANNOTATION_FOR_TESTS);
   // |dest1| is known, we can send as many packets to it.
-  socket_host_->Send(dest1_, packet1, options, 0);
+  socket_host_->Send(dest1_, packet1, options, 0, TRAFFIC_ANNOTATION_FOR_TESTS);
   ASSERT_EQ(sent_packets_.size(), 4U);
 }
 
@@ -451,42 +453,42 @@
   CreateStunRequest(&packet);
   // Limit of 2 packets per second.
   throttler_.SetSendIceBandwidth(packet.size() * 2);
-  socket_host_->Send(dest1_, packet, options, 0);
-  socket_host_->Send(dest2_, packet, options, 0);
+  socket_host_->Send(dest1_, packet, options, 0, TRAFFIC_ANNOTATION_FOR_TESTS);
+  socket_host_->Send(dest2_, packet, options, 0, TRAFFIC_ANNOTATION_FOR_TESTS);
   EXPECT_EQ(2U, sent_packets_.size());
 
   // These packets must be dropped by the throttler since the limit was hit and
   // the time hasn't advanced.
-  socket_host_->Send(dest1_, packet, options, 0);
-  socket_host_->Send(dest2_, packet, options, 0);
+  socket_host_->Send(dest1_, packet, options, 0, TRAFFIC_ANNOTATION_FOR_TESTS);
+  socket_host_->Send(dest2_, packet, options, 0, TRAFFIC_ANNOTATION_FOR_TESTS);
   EXPECT_EQ(2U, sent_packets_.size());
 
   // Advance the time to 0.999 seconds; throttling should still just barely be
   // active.
   fake_clock_.SetTimeNanos(rtc::kNumNanosecsPerMillisec * 999);
-  socket_host_->Send(dest1_, packet, options, 0);
-  socket_host_->Send(dest2_, packet, options, 0);
+  socket_host_->Send(dest1_, packet, options, 0, TRAFFIC_ANNOTATION_FOR_TESTS);
+  socket_host_->Send(dest2_, packet, options, 0, TRAFFIC_ANNOTATION_FOR_TESTS);
   EXPECT_EQ(2U, sent_packets_.size());
 
   // After hitting the second mark, we should be able to send again.
   // Add an extra millisecond to account for rounding errors.
   fake_clock_.SetTimeNanos(rtc::kNumNanosecsPerMillisec * 1001);
-  socket_host_->Send(dest1_, packet, options, 0);
+  socket_host_->Send(dest1_, packet, options, 0, TRAFFIC_ANNOTATION_FOR_TESTS);
   EXPECT_EQ(3U, sent_packets_.size());
 
   // This time, hit the limit in the middle of the period.
   fake_clock_.SetTimeNanos(rtc::kNumNanosecsPerMillisec * 1500);
-  socket_host_->Send(dest2_, packet, options, 0);
+  socket_host_->Send(dest2_, packet, options, 0, TRAFFIC_ANNOTATION_FOR_TESTS);
   EXPECT_EQ(4U, sent_packets_.size());
 
   // Again, throttling should be active until the next second mark.
   fake_clock_.SetTimeNanos(rtc::kNumNanosecsPerMillisec * 1999);
-  socket_host_->Send(dest1_, packet, options, 0);
-  socket_host_->Send(dest2_, packet, options, 0);
+  socket_host_->Send(dest1_, packet, options, 0, TRAFFIC_ANNOTATION_FOR_TESTS);
+  socket_host_->Send(dest2_, packet, options, 0, TRAFFIC_ANNOTATION_FOR_TESTS);
   EXPECT_EQ(4U, sent_packets_.size());
   fake_clock_.SetTimeNanos(rtc::kNumNanosecsPerMillisec * 2002);
-  socket_host_->Send(dest1_, packet, options, 0);
-  socket_host_->Send(dest2_, packet, options, 0);
+  socket_host_->Send(dest1_, packet, options, 0, TRAFFIC_ANNOTATION_FOR_TESTS);
+  socket_host_->Send(dest2_, packet, options, 0, TRAFFIC_ANNOTATION_FOR_TESTS);
   EXPECT_EQ(6U, sent_packets_.size());
 }
 
diff --git a/content/browser/security_exploit_browsertest.cc b/content/browser/security_exploit_browsertest.cc
index 05c2b5e..eb05c34 100644
--- a/content/browser/security_exploit_browsertest.cc
+++ b/content/browser/security_exploit_browsertest.cc
@@ -51,6 +51,7 @@
 #include "net/test/embedded_test_server/embedded_test_server.h"
 #include "net/test/url_request/url_request_slow_download_job.h"
 #include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
+#include "services/network/public/cpp/network_switches.h"
 #include "services/network/public/cpp/resource_request.h"
 #include "services/network/public/interfaces/url_loader.mojom.h"
 #include "third_party/WebKit/public/web/WebTriggeringEventInfo.h"
@@ -166,7 +167,7 @@
     // This allows us to use "real" hostnames in URLs, which we can use to
     // create arbitrary SiteInstances.
     command_line->AppendSwitchASCII(
-        switches::kHostResolverRules,
+        network::switches::kHostResolverRules,
         "MAP * " +
             net::HostPortPair::FromURL(embedded_test_server()->base_url())
                 .ToString() +
diff --git a/content/browser/service_manager/service_manager_context_browsertest.cc b/content/browser/service_manager/service_manager_context_browsertest.cc
index 7cc5d0b..29e6be2 100644
--- a/content/browser/service_manager/service_manager_context_browsertest.cc
+++ b/content/browser/service_manager/service_manager_context_browsertest.cc
@@ -91,10 +91,10 @@
 
 }  // namespace
 
-using ServiceManagerContextTest = ContentBrowserTest;
+using ServiceManagerContextBrowserTest = ContentBrowserTest;
 
 // "MANUAL" tests only run when kRunManualTestsFlag is set.
-IN_PROC_BROWSER_TEST_F(ServiceManagerContextTest,
+IN_PROC_BROWSER_TEST_F(ServiceManagerContextBrowserTest,
                        MANUAL_TerminateOnServiceQuit) {
   ShellContentBrowserClient::Get()
       ->set_should_terminate_on_service_quit_callback(
@@ -112,21 +112,14 @@
   loop.Run();
 }
 
-// Flaky on Chromium OS ASAN: http://crbug.com/803188
-#if defined(OS_CHROMEOS) && defined(ADDRESS_SANITIZER)
-#define MAYBE_TerminateOnServiceQuit DISABLED_TerminateOnServiceQuit
-#else
-#define MAYBE_TerminateOnServiceQuit TerminateOnServiceQuit
-#endif
 // Verifies that if an important service quits then the browser exits.
-IN_PROC_BROWSER_TEST_F(ServiceManagerContextTest,
-                       MAYBE_TerminateOnServiceQuit) {
+TEST(ServiceManagerContextTest, TerminateOnServiceQuit) {
   // Run the above test and collect the test output.
   base::CommandLine new_test =
       base::CommandLine(base::CommandLine::ForCurrentProcess()->GetProgram());
   new_test.AppendSwitchASCII(
       base::kGTestFilterFlag,
-      "ServiceManagerContextTest.MANUAL_TerminateOnServiceQuit");
+      "ServiceManagerContextBrowserTest.MANUAL_TerminateOnServiceQuit");
   new_test.AppendSwitch(kRunManualTestsFlag);
   new_test.AppendSwitch(kSingleProcessTestsFlag);
 
@@ -142,7 +135,8 @@
 #endif
 }
 
-IN_PROC_BROWSER_TEST_F(ServiceManagerContextTest, ServiceProcessReportsPID) {
+IN_PROC_BROWSER_TEST_F(ServiceManagerContextBrowserTest,
+                       ServiceProcessReportsPID) {
   service_manager::mojom::ServiceManagerListenerPtr listener_proxy;
   ServiceInstanceListener listener(mojo::MakeRequest(&listener_proxy));
 
diff --git a/content/browser/service_worker/service_worker_fetch_dispatcher.cc b/content/browser/service_worker/service_worker_fetch_dispatcher.cc
index 2e726ca..d1233912 100644
--- a/content/browser/service_worker/service_worker_fetch_dispatcher.cc
+++ b/content/browser/service_worker/service_worker_fetch_dispatcher.cc
@@ -431,9 +431,10 @@
 class ServiceWorkerFetchDispatcher::URLLoaderAssets
     : public base::RefCounted<ServiceWorkerFetchDispatcher::URLLoaderAssets> {
  public:
-  URLLoaderAssets(network::mojom::URLLoaderFactoryPtr url_loader_factory,
-                  std::unique_ptr<network::mojom::URLLoader> url_loader,
-                  std::unique_ptr<DelegatingURLLoaderClient> url_loader_client)
+  URLLoaderAssets(
+      std::unique_ptr<network::mojom::URLLoaderFactory> url_loader_factory,
+      std::unique_ptr<network::mojom::URLLoader> url_loader,
+      std::unique_ptr<DelegatingURLLoaderClient> url_loader_client)
       : url_loader_factory_(std::move(url_loader_factory)),
         url_loader_(std::move(url_loader)),
         url_loader_client_(std::move(url_loader_client)) {}
@@ -447,7 +448,7 @@
   friend class base::RefCounted<URLLoaderAssets>;
   virtual ~URLLoaderAssets() {}
 
-  network::mojom::URLLoaderFactoryPtr url_loader_factory_;
+  std::unique_ptr<network::mojom::URLLoaderFactory> url_loader_factory_;
   std::unique_ptr<network::mojom::URLLoader> url_loader_;
   std::unique_ptr<DelegatingURLLoaderClient> url_loader_client_;
 
@@ -686,11 +687,8 @@
 
   DCHECK(!url_loader_assets_);
 
-  network::mojom::URLLoaderFactoryPtr url_loader_factory;
-  URLLoaderFactoryImpl::Create(
-      ResourceRequesterInfo::CreateForNavigationPreload(requester_info),
-      mojo::MakeRequest(&url_loader_factory),
-      BrowserThread::GetTaskRunnerForThread(BrowserThread::IO));
+  auto url_loader_factory = std::make_unique<URLLoaderFactoryImpl>(
+      ResourceRequesterInfo::CreateForNavigationPreload(requester_info));
 
   network::ResourceRequest request;
   request.method = original_request->method();
@@ -822,7 +820,7 @@
   // Unlike the non-S13N code path, we don't own the URLLoaderFactory being used
   // (it's the generic network factory), so we don't need to pass it to
   // URLLoaderAssets to keep it alive.
-  network::mojom::URLLoaderFactoryPtr null_factory;
+  std::unique_ptr<network::mojom::URLLoaderFactory> null_factory;
   url_loader_assets_ = base::MakeRefCounted<URLLoaderAssets>(
       std::move(null_factory), std::move(url_loader),
       std::move(url_loader_client));
diff --git a/content/browser/site_per_process_browsertest.cc b/content/browser/site_per_process_browsertest.cc
index 6fb4f1c..4ace5f6 100644
--- a/content/browser/site_per_process_browsertest.cc
+++ b/content/browser/site_per_process_browsertest.cc
@@ -6913,9 +6913,16 @@
   EXPECT_EQ(nullptr, router->wheel_target_.target);
 }
 
+// TODO: Flaking test crbug.com/802828 and related crbug.com/798476
 // Ensure that a cross-process subframe with a touch-handler can receive touch
 // events.
-IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, SubframeTouchEventRouting) {
+#if defined(OS_WIN)
+#define MAYBE_SubframeTouchEventRouting DISABLED_SubframeTouchEventRouting
+#else
+#define MAYBE_SubframeTouchEventRouting SubframeTouchEventRouting
+#endif
+IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
+                       MAYBE_SubframeTouchEventRouting) {
   GURL main_url(embedded_test_server()->GetURL(
       "/frame_tree/page_with_positioned_nested_frames.html"));
   EXPECT_TRUE(NavigateToURL(shell(), main_url));
diff --git a/content/browser/utility_process_host_impl.cc b/content/browser/utility_process_host_impl.cc
index 1271bd60..4c14a70 100644
--- a/content/browser/utility_process_host_impl.cc
+++ b/content/browser/utility_process_host_impl.cc
@@ -297,11 +297,11 @@
 
     // Browser command-line switches to propagate to the utility process.
     static const char* const kSwitchNames[] = {
+      network::switches::kHostResolverRules,
+      network::switches::kLogNetLog,
       network::switches::kNoReferrers,
-      switches::kHostResolverRules,
       switches::kIgnoreCertificateErrors,
       switches::kIgnoreCertificateErrorsSPKIList,
-      switches::kLogNetLog,
       switches::kNoSandbox,
       switches::kOverrideUseSoftwareGLForTests,
       switches::kProxyServer,
diff --git a/content/common/BUILD.gn b/content/common/BUILD.gn
index eab8f4d..914fa3ee 100644
--- a/content/common/BUILD.gn
+++ b/content/common/BUILD.gn
@@ -47,6 +47,7 @@
     "android/media_metadata_android.h",
     "android/sync_compositor_statics.cc",
     "android/sync_compositor_statics.h",
+    "android/use_zoom_for_dsf_policy_android.cc",
     "appcache_interfaces.cc",
     "appcache_interfaces.h",
     "associated_interface_provider_impl.cc",
diff --git a/content/common/android/use_zoom_for_dsf_policy_android.cc b/content/common/android/use_zoom_for_dsf_policy_android.cc
new file mode 100644
index 0000000..aab078a0
--- /dev/null
+++ b/content/common/android/use_zoom_for_dsf_policy_android.cc
@@ -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.
+
+#include <jni.h>
+
+#include "base/android/scoped_java_ref.h"
+#include "content/public/common/use_zoom_for_dsf_policy.h"
+#include "jni/UseZoomForDSFPolicy_jni.h"
+
+using base::android::JavaParamRef;
+
+namespace content {
+
+jboolean JNI_UseZoomForDSFPolicy_IsUseZoomForDSFEnabled(
+    JNIEnv* env,
+    const JavaParamRef<jclass>& clazz) {
+  return UseZoomForDSFEnabled();
+}
+
+}  // namespace content
diff --git a/content/network/DEPS b/content/network/DEPS
index 222cc03..697b0c2 100644
--- a/content/network/DEPS
+++ b/content/network/DEPS
@@ -8,13 +8,7 @@
   "+components/prefs",
   "-content",
   "+content/common/content_export.h",
-  "+content/common/loader_util.h",
   "+content/network",
-  "+content/public/common/content_client.h",
-  "+content/public/common/content_features.h",
-  "+content/public/common/content_switches.h",
-  "+content/public/common/network_service.mojom.h",
-  "+content/public/common/url_constants.h",
   "+content/public/network",
   "+services/network",
   "+services/service_manager/public",
diff --git a/content/network/cache_url_loader.cc b/content/network/cache_url_loader.cc
index f144b03..b2adad91 100644
--- a/content/network/cache_url_loader.cc
+++ b/content/network/cache_url_loader.cc
@@ -8,7 +8,6 @@
 #include "base/macros.h"
 #include "base/strings/string_util.h"
 #include "base/threading/thread_task_runner_handle.h"
-#include "content/public/common/url_constants.h"
 #include "mojo/common/data_pipe_utils.h"
 #include "net/url_request/view_cache_helper.h"
 
@@ -29,16 +28,13 @@
     resource_response.mime_type = "text/html";
     client_->OnReceiveResponse(resource_response, base::nullopt, nullptr);
 
-    DCHECK(base::StartsWith(url.spec(), kChromeUINetworkViewCacheURL,
-                            base::CompareCase::INSENSITIVE_ASCII));
-
-    std::string cache_key =
-        url.spec().substr(strlen(kChromeUINetworkViewCacheURL));
+    auto url_prefix = url.GetWithEmptyPath().spec();
+    std::string cache_key = url.spec().substr(url_prefix.size());
 
     int rv;
     if (cache_key.empty()) {
       rv = cache_helper_.GetContentsHTML(
-          request_context, kChromeUINetworkViewCacheURL, &data_,
+          request_context, url_prefix, &data_,
           base::Bind(&CacheURLLoader::DataAvailable, base::Unretained(this)));
     } else {
       rv = cache_helper_.GetEntryInfoHTML(
diff --git a/content/network/network_context.cc b/content/network/network_context.cc
index a1e1c22..ddd2766 100644
--- a/content/network/network_context.cc
+++ b/content/network/network_context.cc
@@ -30,8 +30,6 @@
 #include "content/network/throttling/throttling_controller.h"
 #include "content/network/throttling/throttling_network_transaction_factory.h"
 #include "content/network/url_loader.h"
-#include "content/public/common/content_client.h"
-#include "content/public/common/content_switches.h"
 #include "content/public/network/ignore_errors_cert_verifier.h"
 #include "content/public/network/url_request_context_builder_mojo.h"
 #include "mojo/public/cpp/bindings/strong_binding.h"
@@ -50,6 +48,7 @@
 #include "net/url_request/url_request_context.h"
 #include "net/url_request/url_request_context_builder.h"
 #include "services/network/proxy_config_service_mojo.h"
+#include "services/network/public/cpp/network_switches.h"
 
 namespace content {
 
@@ -224,17 +223,18 @@
   const base::CommandLine* command_line =
       base::CommandLine::ForCurrentProcess();
 
-  if (command_line->HasSwitch(switches::kHostResolverRules)) {
+  if (command_line->HasSwitch(network::switches::kHostResolverRules)) {
     std::unique_ptr<net::HostResolver> host_resolver(
         net::HostResolver::CreateDefaultResolver(nullptr));
     std::unique_ptr<net::MappedHostResolver> remapped_host_resolver(
         new net::MappedHostResolver(std::move(host_resolver)));
     remapped_host_resolver->SetRulesFromString(
-        command_line->GetSwitchValueASCII(switches::kHostResolverRules));
+        command_line->GetSwitchValueASCII(
+            network::switches::kHostResolverRules));
     builder.set_host_resolver(std::move(remapped_host_resolver));
   }
   builder.set_accept_language("en-us,en");
-  builder.set_user_agent(GetContentClient()->GetUserAgent());
+  builder.set_user_agent(network_context_params->user_agent);
 
   // The cookie configuration is in this method, which is only used by the
   // network process, and not ApplyContextParamsToBuilder which is used by the
diff --git a/content/network/network_service_impl.cc b/content/network/network_service_impl.cc
index b7cb1277..ab98cdc4 100644
--- a/content/network/network_service_impl.cc
+++ b/content/network/network_service_impl.cc
@@ -12,7 +12,6 @@
 #include "base/values.h"
 #include "build/build_config.h"
 #include "content/network/network_context.h"
-#include "content/public/common/content_switches.h"
 #include "content/public/network/url_request_context_builder_mojo.h"
 #include "mojo/public/cpp/bindings/strong_binding.h"
 #include "net/base/logging_network_change_observer.h"
@@ -21,6 +20,7 @@
 #include "net/log/net_log.h"
 #include "net/log/net_log_util.h"
 #include "net/url_request/url_request_context_builder.h"
+#include "services/network/public/cpp/network_switches.h"
 
 namespace content {
 
@@ -64,11 +64,11 @@
   // If specified by the command line, stream network events (NetLog) to a
   // file on disk. This will last for the duration of the process.
   void ProcessCommandLine(const base::CommandLine& command_line) {
-    if (!command_line.HasSwitch(switches::kLogNetLog))
+    if (!command_line.HasSwitch(network::switches::kLogNetLog))
       return;
 
     base::FilePath log_path =
-        command_line.GetSwitchValuePath(switches::kLogNetLog);
+        command_line.GetSwitchValuePath(network::switches::kLogNetLog);
 
     // TODO(eroman): Should get capture mode from the command line.
     net::NetLogCaptureMode capture_mode =
diff --git a/content/public/android/BUILD.gn b/content/public/android/BUILD.gn
index 6cd8114a..55313048 100644
--- a/content/public/android/BUILD.gn
+++ b/content/public/android/BUILD.gn
@@ -263,6 +263,7 @@
     "java/src/org/chromium/content_public/common/Referrer.java",
     "java/src/org/chromium/content_public/common/ResourceRequestBody.java",
     "java/src/org/chromium/content_public/common/ScreenOrientationConstants.java",
+    "java/src/org/chromium/content_public/common/UseZoomForDSFPolicy.java",
   ]
 }
 
@@ -390,6 +391,7 @@
     "java/src/org/chromium/content_public/common/BrowserSideNavigationPolicy.java",
     "java/src/org/chromium/content_public/common/MediaMetadata.java",
     "java/src/org/chromium/content_public/common/ResourceRequestBody.java",
+    "java/src/org/chromium/content_public/common/UseZoomForDSFPolicy.java",
   ]
   jni_package = "content"
 }
diff --git a/content/public/android/java/src/org/chromium/content/browser/ContentViewCoreImpl.java b/content/public/android/java/src/org/chromium/content/browser/ContentViewCoreImpl.java
index 2b6f0618..709c9d6 100644
--- a/content/public/android/java/src/org/chromium/content/browser/ContentViewCoreImpl.java
+++ b/content/public/android/java/src/org/chromium/content/browser/ContentViewCoreImpl.java
@@ -6,12 +6,9 @@
 
 import android.annotation.SuppressLint;
 import android.annotation.TargetApi;
-import android.app.assist.AssistStructure.ViewNode;
 import android.content.Context;
 import android.content.res.Configuration;
-import android.graphics.Rect;
 import android.os.Build;
-import android.os.Build.VERSION_CODES;
 import android.os.Bundle;
 import android.os.SystemClock;
 import android.view.HapticFeedbackConstants;
@@ -22,9 +19,6 @@
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.ViewStructure;
-import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityManager;
-import android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener;
 import android.view.accessibility.AccessibilityNodeProvider;
 
 import org.chromium.base.ObserverList;
@@ -46,7 +40,6 @@
 import org.chromium.content.browser.input.TextSuggestionHost;
 import org.chromium.content.browser.selection.SelectionPopupControllerImpl;
 import org.chromium.content.browser.webcontents.WebContentsImpl;
-import org.chromium.content_public.browser.AccessibilitySnapshotCallback;
 import org.chromium.content_public.browser.AccessibilitySnapshotNode;
 import org.chromium.content_public.browser.ActionModeCallbackHelper;
 import org.chromium.content_public.browser.GestureStateListener;
@@ -71,10 +64,9 @@
  * Implementation of the interface {@ContentViewCore}.
  */
 @JNINamespace("content")
-public class ContentViewCoreImpl
-        implements ContentViewCore, AccessibilityStateChangeListener, DisplayAndroidObserver,
-                   SystemCaptioningBridge.SystemCaptioningBridgeListener, WindowAndroidProvider,
-                   ImeEventObserver {
+public class ContentViewCoreImpl implements ContentViewCore, DisplayAndroidObserver,
+                                            SystemCaptioningBridge.SystemCaptioningBridgeListener,
+                                            WindowAndroidProvider, ImeEventObserver {
     private static final String TAG = "cr_ContentViewCore";
 
     /**
@@ -181,32 +173,13 @@
 
     private boolean mPreserveSelectionOnNextLossOfFocus;
 
-    // Whether native accessibility, i.e. without any script injection, is allowed.
-    private boolean mNativeAccessibilityAllowed;
-
     // Handles native accessibility, i.e. without any script injection.
     private WebContentsAccessibility mWebContentsAccessibility;
 
-    // System accessibility service.
-    private final AccessibilityManager mAccessibilityManager;
-
-    // If true, the web contents are obscured by another view and we shouldn't
-    // return an AccessibilityNodeProvider or process touch exploration events.
-    private boolean mIsObscuredByAnotherView;
-
     // Notifies the ContentViewCore when platform closed caption settings have changed
     // if they are supported. Otherwise does nothing.
     private final SystemCaptioningBridge mSystemCaptioningBridge;
 
-    // Accessibility touch exploration state.
-    private boolean mTouchExplorationEnabled;
-
-    // Whether accessibility focus should be set to the page when it finishes loading.
-    // This only applies if an accessibility service like TalkBack is running.
-    // This is desirable behavior for a browser window, but not for an embedded
-    // WebView.
-    private boolean mShouldSetAccessibilityFocusOnPageLoad;
-
     // Whether a touch scroll sequence is active, used to hide text selection
     // handles. Note that a scroll sequence will *always* bound a pinch
     // sequence, so this will also be true for the duration of a pinch gesture.
@@ -260,8 +233,6 @@
     public ContentViewCoreImpl(Context context, String productVersion) {
         mContext = context;
         mProductVersion = productVersion;
-        mAccessibilityManager =
-                (AccessibilityManager) getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
         mSystemCaptioningBridge = CaptioningBridgeFactory.getSystemCaptioningBridge(mContext);
 
         mWindowAndroidChangedObservers = new ObserverList<WindowAndroidChangedObserver>();
@@ -342,7 +313,8 @@
         setContainerView(containerView);
         mRenderCoordinates = mWebContents.getRenderCoordinates();
         mRenderCoordinates.setDeviceScaleFactor(dipScale, windowAndroid.getContext().get());
-
+        mWebContentsAccessibility = WebContentsAccessibility.create(
+                mContext, containerView, webContents, mProductVersion);
         setContainerViewInternals(internalDispatcher);
 
         mPopupZoomer = new PopupZoomer(mContext, mWebContents, mContainerView);
@@ -458,6 +430,9 @@
         mWebContents = null;
         mNativeContentViewCore = 0;
 
+        // mWebContentsAccessibility needs not nulling since CVC referencing it is going away.
+        mWebContentsAccessibility.destroy();
+
         // See warning in javadoc before adding more clean up code here.
     }
 
@@ -554,7 +529,7 @@
     public void onShow() {
         assert mWebContents != null;
         mWebContents.onShow();
-        setAccessibilityState(mAccessibilityManager.isEnabled());
+        mWebContentsAccessibility.refreshState();
         restoreSelectionPopupsIfNecessary();
     }
 
@@ -613,15 +588,13 @@
     public void onAttachedToWindow() {
         mAttachedToWindow = true;
         addDisplayAndroidObserverIfNeeded();
-        setAccessibilityState(mAccessibilityManager.isEnabled());
-        if (mWebContents != null) updateTextSelectionUI(true);
-        GamepadList.onAttachedToWindow(mContext);
-        mAccessibilityManager.addAccessibilityStateChangeListener(this);
-        mSystemCaptioningBridge.addListener(this);
-        getImeAdapter().onViewAttachedToWindow();
-        if (mWebContentsAccessibility != null) {
-            mWebContentsAccessibility.onAttachedToWindow();
+        if (mWebContents != null) {
+            updateTextSelectionUI(true);
+            getImeAdapter().onViewAttachedToWindow();
         }
+        GamepadList.onAttachedToWindow(mContext);
+        mSystemCaptioningBridge.addListener(this);
+        mWebContentsAccessibility.onAttachedToWindow();
     }
 
     @Override
@@ -641,7 +614,6 @@
         mAttachedToWindow = false;
         removeDisplayAndroidObserver();
         GamepadList.onDetachedFromWindow();
-        mAccessibilityManager.removeAccessibilityStateChangeListener(this);
 
         if (mWebContents != null) {
             // WebView uses PopupWindows for handle rendering, which may remain
@@ -653,9 +625,7 @@
             getImeAdapter().onViewDetachedFromWindow();
         }
         mSystemCaptioningBridge.removeListener(this);
-        if (mWebContentsAccessibility != null) {
-            mWebContentsAccessibility.onDetachedFromWindow();
-        }
+        mWebContentsAccessibility.onDetachedFromWindow();
     }
 
     @SuppressWarnings("javadoc")
@@ -1042,7 +1012,8 @@
         for (int i = 0; i < items.length; i++) {
             popupItems.add(new SelectPopupItem(items[i], enabled[i]));
         }
-        if (DeviceFormFactor.isTablet() && !multiple && !isTouchExplorationEnabled()) {
+        if (DeviceFormFactor.isTablet() && !multiple
+                && !mWebContentsAccessibility.isTouchExplorationEnabled()) {
             mSelectPopup = new SelectPopupDropdown(
                     this, anchorView, popupItems, selectedIndices, rightAligned);
         } else {
@@ -1096,20 +1067,13 @@
     }
 
     @Override
-    public void onAccessibilityStateChanged(boolean enabled) {
-        setAccessibilityState(enabled);
-    }
-
-    @Override
     public boolean supportsAccessibilityAction(int action) {
-        // TODO(dmazzoni): implement this in WebContentsAccessibility.
-        return false;
+        return mWebContentsAccessibility.supportsAction(action);
     }
 
     @Override
     public boolean performAccessibilityAction(int action, Bundle arguments) {
-        // TODO(dmazzoni): implement this in WebContentsAccessibility.
-        return false;
+        return mWebContentsAccessibility.performAction(View.NO_ID, action, arguments);
     }
 
     @Override
@@ -1119,103 +1083,26 @@
 
     @Override
     public AccessibilityNodeProvider getAccessibilityNodeProvider() {
-        if (mIsObscuredByAnotherView) return null;
-
-        // If WebContentsAccessibility is null, create it if native a11y is allowed and WebContent
-        // is not null. Else return null.
-        if (mWebContentsAccessibility == null) {
-            if (!mNativeAccessibilityAllowed || mWebContents == null) {
-                return null;
-            }
-            mWebContentsAccessibility = WebContentsAccessibility.create(
-                    mContext, mContainerView, mWebContents, mShouldSetAccessibilityFocusOnPageLoad);
-            // For Lollipop devices, we need to register a broadcast receiver for locale change.
-            if (Build.VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP
-                    && mContainerView.isAttachedToWindow()) {
-                mWebContentsAccessibility.onAttachedToWindow();
-            }
-        }
-        if (!mWebContentsAccessibility.isEnabled()) {
-            mWebContentsAccessibility.enable();
-        }
         return mWebContentsAccessibility.getAccessibilityNodeProvider();
     }
 
     @Override
     public void setObscuredByAnotherView(boolean isObscured) {
-        if (isObscured != mIsObscuredByAnotherView) {
-            mIsObscuredByAnotherView = isObscured;
-            getContainerView().sendAccessibilityEvent(
-                    AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
-        }
+        mWebContentsAccessibility.setObscuredByAnotherView(isObscured);
     }
 
     @TargetApi(Build.VERSION_CODES.M)
     @Override
     public void onProvideVirtualStructure(
             final ViewStructure structure, final boolean ignoreScrollOffset) {
-        // Do not collect accessibility tree in incognito mode
-        if (getWebContents().isIncognito()) {
-            structure.setChildCount(0);
-            return;
-        }
-        structure.setChildCount(1);
-        final ViewStructure viewRoot = structure.asyncNewChild(0);
-        getWebContents().requestAccessibilitySnapshot(new AccessibilitySnapshotCallback() {
-            @Override
-            public void onAccessibilitySnapshot(AccessibilitySnapshotNode root) {
-                viewRoot.setClassName("");
-                viewRoot.setHint(mProductVersion);
-                if (root == null) {
-                    viewRoot.asyncCommit();
-                    return;
-                }
-                createVirtualStructure(viewRoot, root, ignoreScrollOffset);
-            }
-        });
+        mWebContentsAccessibility.onProvideVirtualStructure(structure, ignoreScrollOffset);
     }
 
     // When creating the View structure, the left and top are relative to the parent node.
     @TargetApi(Build.VERSION_CODES.M)
     private void createVirtualStructure(ViewStructure viewNode, AccessibilitySnapshotNode node,
             final boolean ignoreScrollOffset) {
-        viewNode.setClassName(node.className);
-        if (node.hasSelection) {
-            viewNode.setText(node.text, node.startSelection, node.endSelection);
-        } else {
-            viewNode.setText(node.text);
-        }
-        int left = (int) mRenderCoordinates.fromLocalCssToPix(node.x);
-        int top = (int) mRenderCoordinates.fromLocalCssToPix(node.y);
-        int width = (int) mRenderCoordinates.fromLocalCssToPix(node.width);
-        int height = (int) mRenderCoordinates.fromLocalCssToPix(node.height);
-
-        Rect boundsInParent = new Rect(left, top, left + width, top + height);
-        if (node.isRootNode) {
-            // Offset of the web content relative to the View.
-            boundsInParent.offset(0, (int) mRenderCoordinates.getContentOffsetYPix());
-            if (!ignoreScrollOffset) {
-                boundsInParent.offset(-(int) mRenderCoordinates.getScrollXPix(),
-                        -(int) mRenderCoordinates.getScrollYPix());
-            }
-        }
-
-        viewNode.setDimens(boundsInParent.left, boundsInParent.top, 0, 0, width, height);
-        viewNode.setChildCount(node.children.size());
-        if (node.hasStyle) {
-            // The text size should be in physical pixels, not CSS pixels.
-            float textSize = mRenderCoordinates.fromLocalCssToPix(node.textSize);
-
-            int style = (node.bold ? ViewNode.TEXT_STYLE_BOLD : 0)
-                    | (node.italic ? ViewNode.TEXT_STYLE_ITALIC : 0)
-                    | (node.underline ? ViewNode.TEXT_STYLE_UNDERLINE : 0)
-                    | (node.lineThrough ? ViewNode.TEXT_STYLE_STRIKE_THRU : 0);
-            viewNode.setTextStyle(textSize, node.color, node.bgcolor, style);
-        }
-        for (int i = 0; i < node.children.size(); i++) {
-            createVirtualStructure(viewNode.asyncNewChild(i), node.children.get(i), true);
-        }
-        viewNode.asyncCommit();
+        mWebContentsAccessibility.createVirtualStructure(viewNode, node, ignoreScrollOffset);
     }
 
     @TargetApi(Build.VERSION_CODES.LOLLIPOP)
@@ -1236,23 +1123,17 @@
 
     @Override
     public boolean isTouchExplorationEnabled() {
-        return mTouchExplorationEnabled;
+        return mWebContentsAccessibility.isTouchExplorationEnabled();
     }
 
     @Override
     public void setAccessibilityState(boolean state) {
-        if (!state) {
-            mNativeAccessibilityAllowed = false;
-            mTouchExplorationEnabled = false;
-        } else {
-            mNativeAccessibilityAllowed = true;
-            mTouchExplorationEnabled = mAccessibilityManager.isTouchExplorationEnabled();
-        }
+        mWebContentsAccessibility.setState(state);
     }
 
     @Override
     public void setShouldSetAccessibilityFocusOnPageLoad(boolean on) {
-        mShouldSetAccessibilityFocusOnPageLoad = on;
+        mWebContentsAccessibility.setShouldFocusOnPageLoad(on);
     }
 
     @Override
diff --git a/content/public/android/java/src/org/chromium/content/browser/accessibility/KitKatWebContentsAccessibility.java b/content/public/android/java/src/org/chromium/content/browser/accessibility/KitKatWebContentsAccessibility.java
index c45f36cb..81140ec 100644
--- a/content/public/android/java/src/org/chromium/content/browser/accessibility/KitKatWebContentsAccessibility.java
+++ b/content/public/android/java/src/org/chromium/content/browser/accessibility/KitKatWebContentsAccessibility.java
@@ -24,8 +24,13 @@
     private String mSupportedHtmlElementTypes;
 
     KitKatWebContentsAccessibility(Context context, ViewGroup containerView,
-            WebContents webContents, boolean shouldFocusOnPageLoad) {
-        super(context, containerView, webContents, shouldFocusOnPageLoad);
+            WebContents webContents, String productVersion) {
+        super(context, containerView, webContents, productVersion);
+    }
+
+    @Override
+    protected void onNativeInit() {
+        super.onNativeInit();
         mSupportedHtmlElementTypes = nativeGetSupportedHtmlElementTypes(mNativeObj);
     }
 
diff --git a/content/public/android/java/src/org/chromium/content/browser/accessibility/LollipopWebContentsAccessibility.java b/content/public/android/java/src/org/chromium/content/browser/accessibility/LollipopWebContentsAccessibility.java
index 55c19d05d..6ced502 100644
--- a/content/public/android/java/src/org/chromium/content/browser/accessibility/LollipopWebContentsAccessibility.java
+++ b/content/public/android/java/src/org/chromium/content/browser/accessibility/LollipopWebContentsAccessibility.java
@@ -34,18 +34,24 @@
             new SparseArray<AccessibilityAction>();
     private String mSystemLanguageTag;
     private BroadcastReceiver mBroadcastReceiver;
-    private Context mContext;
 
     LollipopWebContentsAccessibility(Context context, ViewGroup containerView,
-            WebContents webContents, boolean shouldFocusOnPageLoad) {
-        super(context, containerView, webContents, shouldFocusOnPageLoad);
-        mContext = context;
+            WebContents webContents, String productVersion) {
+        super(context, containerView, webContents, productVersion);
+    }
+
+    @Override
+    protected void onNativeInit() {
+        super.onNativeInit();
         mBroadcastReceiver = new BroadcastReceiver() {
             @Override
             public void onReceive(Context context, Intent intent) {
                 mSystemLanguageTag = Locale.getDefault().toLanguageTag();
             }
         };
+
+        // Register a broadcast receiver for locale change for Lollipop or higher version.
+        if (mView.isAttachedToWindow()) registerLocaleChangeReceiver();
     }
 
     @Override
@@ -153,11 +159,19 @@
 
     @Override
     public void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+        if (!isNativeInitialized()) return;
         mContext.unregisterReceiver(mBroadcastReceiver);
     }
 
     @Override
     public void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        registerLocaleChangeReceiver();
+    }
+
+    private void registerLocaleChangeReceiver() {
+        if (!isNativeInitialized()) return;
         try {
             IntentFilter filter = new IntentFilter(Intent.ACTION_LOCALE_CHANGED);
             mContext.registerReceiver(mBroadcastReceiver, filter);
diff --git a/content/public/android/java/src/org/chromium/content/browser/accessibility/OWebContentsAccessibility.java b/content/public/android/java/src/org/chromium/content/browser/accessibility/OWebContentsAccessibility.java
index e7685d8..2cde28b 100644
--- a/content/public/android/java/src/org/chromium/content/browser/accessibility/OWebContentsAccessibility.java
+++ b/content/public/android/java/src/org/chromium/content/browser/accessibility/OWebContentsAccessibility.java
@@ -29,8 +29,8 @@
 @TargetApi(Build.VERSION_CODES.O)
 public class OWebContentsAccessibility extends LollipopWebContentsAccessibility {
     OWebContentsAccessibility(Context context, ViewGroup containerView, WebContents webContents,
-            boolean shouldFocusOnPageLoad) {
-        super(context, containerView, webContents, shouldFocusOnPageLoad);
+            String productVersion) {
+        super(context, containerView, webContents, productVersion);
     }
 
     @Override
diff --git a/content/public/android/java/src/org/chromium/content/browser/accessibility/WebContentsAccessibility.java b/content/public/android/java/src/org/chromium/content/browser/accessibility/WebContentsAccessibility.java
index 5cc1cf4..34193f2 100644
--- a/content/public/android/java/src/org/chromium/content/browser/accessibility/WebContentsAccessibility.java
+++ b/content/public/android/java/src/org/chromium/content/browser/accessibility/WebContentsAccessibility.java
@@ -6,6 +6,8 @@
 
 import android.accessibilityservice.AccessibilityServiceInfo;
 import android.annotation.SuppressLint;
+import android.annotation.TargetApi;
+import android.app.assist.AssistStructure.ViewNode;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.graphics.Rect;
@@ -18,8 +20,10 @@
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.ViewParent;
+import android.view.ViewStructure;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityManager;
+import android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener;
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.view.accessibility.AccessibilityNodeProvider;
 
@@ -27,6 +31,8 @@
 import org.chromium.base.annotations.JNINamespace;
 import org.chromium.content.browser.RenderCoordinates;
 import org.chromium.content.browser.webcontents.WebContentsImpl;
+import org.chromium.content_public.browser.AccessibilitySnapshotCallback;
+import org.chromium.content_public.browser.AccessibilitySnapshotNode;
 import org.chromium.content_public.browser.WebContents;
 
 import java.util.ArrayList;
@@ -34,12 +40,13 @@
 import java.util.Locale;
 
 /**
- * Native accessibility for a {@link WebContents}. Lazily created upon the first request
- * from Android framework on {@link AccessibilityNodeProvider} and shares the lifetime
- * with {@link WebContents}.
+ * Native accessibility for a {@link WebContents}. Actual native instance is
+ * created lazily upon the first request from Android framework on
+ *{@link AccessibilityNodeProvider}, and shares the lifetime with {@link WebContents}.
  */
 @JNINamespace("content")
-public class WebContentsAccessibility extends AccessibilityNodeProvider {
+public class WebContentsAccessibility
+        extends AccessibilityNodeProvider implements AccessibilityStateChangeListener {
     // Constants from AccessibilityNodeInfo defined in the K SDK.
     private static final int ACTION_COLLAPSE = 0x00080000;
     private static final int ACTION_EXPAND = 0x00040000;
@@ -65,9 +72,9 @@
     private static final int NO_GRANULARITY_SELECTED = 0;
 
     protected final AccessibilityManager mAccessibilityManager;
-    private final Context mContext;
-    private final RenderCoordinates mRenderCoordinates;
-    private final WebContentsImpl mWebContents;
+    protected final Context mContext;
+    private final String mProductVersion;
+    private WebContentsImpl mWebContents;
     protected long mNativeObj;
     private Rect mAccessibilityFocusRect;
     private boolean mIsHovering;
@@ -85,42 +92,63 @@
     protected int mSelectionNodeId;
     private Runnable mSendWindowContentChangedRunnable;
     private View mAutofillPopupView;
+
+    // Whether native accessibility is allowed.
+    private boolean mNativeAccessibilityAllowed;
+
+    // Whether accessibility focus should be set to the page when it finishes loading.
+    // This only applies if an accessibility service like TalkBack is running.
+    // This is desirable behavior for a browser window, but not for an embedded
+    // WebView.
     private boolean mShouldFocusOnPageLoad;
 
+    // If true, the web contents are obscured by another view and we shouldn't
+    // return an AccessibilityNodeProvider or process touch exploration events.
+    private boolean mIsObscuredByAnotherView;
+
+    // Accessibility touch exploration state.
+    private boolean mTouchExplorationEnabled;
+
     /**
      * Create a WebContentsAccessibility object.
      */
     public static WebContentsAccessibility create(Context context, ViewGroup containerView,
-            WebContents webContents, boolean shouldFocusOnPageLoad) {
+            WebContents webContents, String productVersion) {
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
             return new OWebContentsAccessibility(
-                    context, containerView, webContents, shouldFocusOnPageLoad);
+                    context, containerView, webContents, productVersion);
         } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
             return new LollipopWebContentsAccessibility(
-                    context, containerView, webContents, shouldFocusOnPageLoad);
+                    context, containerView, webContents, productVersion);
         } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
             return new KitKatWebContentsAccessibility(
-                    context, containerView, webContents, shouldFocusOnPageLoad);
+                    context, containerView, webContents, productVersion);
         } else {
             return new WebContentsAccessibility(
-                    context, containerView, webContents, shouldFocusOnPageLoad);
+                    context, containerView, webContents, productVersion);
         }
     }
 
     protected WebContentsAccessibility(Context context, ViewGroup containerView,
-            WebContents webContents, boolean shouldFocusOnPageLoad) {
+            WebContents webContents, String productVersion) {
         mContext = context;
         mWebContents = (WebContentsImpl) webContents;
+        mView = containerView;
+        mProductVersion = productVersion;
+        mAccessibilityManager =
+                (AccessibilityManager) mContext.getSystemService(Context.ACCESSIBILITY_SERVICE);
+        // Native is initialized lazily, when node provider is actually requested.
+    }
+
+    /**
+     * Called after the native a11y part is initialized. Overridable by subclasses
+     * to do initialization that is not required until the native is set up.
+     */
+    protected void onNativeInit() {
         mAccessibilityFocusId = View.NO_ID;
         mSelectionNodeId = View.NO_ID;
         mIsHovering = false;
         mCurrentRootId = View.NO_ID;
-        mView = containerView;
-        mRenderCoordinates = mWebContents.getRenderCoordinates();
-        mAccessibilityManager =
-                (AccessibilityManager) context.getSystemService(Context.ACCESSIBILITY_SERVICE);
-        mShouldFocusOnPageLoad = shouldFocusOnPageLoad;
-        mNativeObj = nativeInit(webContents);
     }
 
     @CalledByNative
@@ -128,12 +156,12 @@
         mNativeObj = 0;
     }
 
-    public boolean isEnabled() {
-        return mNativeObj != 0 ? nativeIsEnabled(mNativeObj) : false;
+    protected boolean isNativeInitialized() {
+        return mNativeObj != 0;
     }
 
-    public void enable() {
-        if (mNativeObj != 0) nativeEnable(mNativeObj);
+    private boolean isEnabled() {
+        return isNativeInitialized() ? nativeIsEnabled(mNativeObj) : false;
     }
 
     /**
@@ -147,6 +175,14 @@
      * @return An AccessibilityNodeProvider.
      */
     public AccessibilityNodeProvider getAccessibilityNodeProvider() {
+        if (mIsObscuredByAnotherView) return null;
+
+        if (!isNativeInitialized()) {
+            if (!mNativeAccessibilityAllowed || mWebContents == null) return null;
+            mNativeObj = nativeInit(mWebContents);
+            onNativeInit();
+        }
+        if (!isEnabled()) nativeEnable(mNativeObj);
         return this;
     }
 
@@ -392,7 +428,7 @@
 
     /**
      * Notify us when the frame info is initialized,
-     * the first time, since until that point, we can't use mRenderCoordinates to transform
+     * the first time, since until that point, we can't use RenderCoordinates to transform
      * web coordinates to screen coordinates.
      */
     @CalledByNative
@@ -652,7 +688,8 @@
     }
 
     private boolean isAccessibilityEnabled() {
-        return sAccessibilityEnabledForTesting || mAccessibilityManager.isEnabled();
+        return isNativeInitialized()
+                && (sAccessibilityEnabledForTesting || mAccessibilityManager.isEnabled());
     }
 
     private AccessibilityNodeInfo createNodeForHost(int rootId) {
@@ -694,12 +731,12 @@
      * convert web coordinates to screen coordinates. When this is first initialized,
      * notifyFrameInfoInitialized is called - but we shouldn't check whether or not
      * that method was called as a way to determine if frame info is valid because
-     * notifyFrameInfoInitialized might not be called at all if mRenderCoordinates
+     * notifyFrameInfoInitialized might not be called at all if RenderCoordinates
      * gets initialized first.
      */
     private boolean isFrameInfoInitialized() {
-        return mRenderCoordinates.getContentWidthCss() != 0.0
-                || mRenderCoordinates.getContentHeightCss() != 0.0;
+        RenderCoordinates rc = mWebContents.getRenderCoordinates();
+        return rc.getContentWidthCss() != 0.0 || rc.getContentHeightCss() != 0.0;
     }
 
     @CalledByNative
@@ -944,16 +981,17 @@
 
     protected void convertWebRectToAndroidCoordinates(Rect rect) {
         // Offset by the scroll position.
-        rect.offset(-(int) mRenderCoordinates.getScrollX(), -(int) mRenderCoordinates.getScrollY());
+        RenderCoordinates rc = mWebContents.getRenderCoordinates();
+        rect.offset(-(int) rc.getScrollX(), -(int) rc.getScrollY());
 
         // Convert CSS (web) pixels to Android View pixels
-        rect.left = (int) mRenderCoordinates.fromLocalCssToPix(rect.left);
-        rect.top = (int) mRenderCoordinates.fromLocalCssToPix(rect.top);
-        rect.bottom = (int) mRenderCoordinates.fromLocalCssToPix(rect.bottom);
-        rect.right = (int) mRenderCoordinates.fromLocalCssToPix(rect.right);
+        rect.left = (int) rc.fromLocalCssToPix(rect.left);
+        rect.top = (int) rc.fromLocalCssToPix(rect.top);
+        rect.bottom = (int) rc.fromLocalCssToPix(rect.bottom);
+        rect.right = (int) rc.fromLocalCssToPix(rect.right);
 
         // Offset by the location of the web content within the view.
-        rect.offset(0, (int) mRenderCoordinates.getContentOffsetYPix());
+        rect.offset(0, (int) rc.getContentOffsetYPix());
 
         // Finally offset by the location of the view within the screen.
         final int[] viewLocation = new int[2];
@@ -961,7 +999,7 @@
         rect.offset(viewLocation[0], viewLocation[1]);
 
         // Clip to the viewport bounds.
-        int viewportRectTop = viewLocation[1] + (int) mRenderCoordinates.getContentOffsetYPix();
+        int viewportRectTop = viewLocation[1] + (int) rc.getContentOffsetYPix();
         int viewportRectBottom = viewportRectTop + mView.getHeight();
         if (rect.top < viewportRectTop) rect.top = viewportRectTop;
         if (rect.bottom > viewportRectBottom) rect.bottom = viewportRectBottom;
@@ -976,7 +1014,8 @@
                 parentRelativeLeft + width, parentRelativeTop + height);
         if (isRootNode) {
             // Offset of the web content relative to the View.
-            boundsInParent.offset(0, (int) mRenderCoordinates.getContentOffsetYPix());
+            RenderCoordinates rc = mWebContents.getRenderCoordinates();
+            boundsInParent.offset(0, (int) rc.getContentOffsetYPix());
         }
         node.setBoundsInParent(boundsInParent);
 
@@ -1236,18 +1275,143 @@
         return 0;
     }
 
+    // AccessibilityStateChangeListener
+
+    @Override
+    public void onAccessibilityStateChanged(boolean enabled) {
+        setState(enabled);
+    }
+
+    // Calls forwared from CVC.
+
+    public void setObscuredByAnotherView(boolean isObscured) {
+        if (isObscured != mIsObscuredByAnotherView) {
+            mIsObscuredByAnotherView = isObscured;
+            mView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
+        }
+    }
+
+    public boolean isTouchExplorationEnabled() {
+        return mTouchExplorationEnabled;
+    }
+
+    public void setState(boolean state) {
+        if (!state) {
+            mNativeAccessibilityAllowed = false;
+            mTouchExplorationEnabled = false;
+        } else {
+            mNativeAccessibilityAllowed = true;
+            mTouchExplorationEnabled = mAccessibilityManager.isTouchExplorationEnabled();
+        }
+    }
+
+    /**
+     * Called by {@link ContentViewCore}
+     */
+    public void destroy() {
+        // WebContents is destroyed. Native a11y shall not be created afterwards.
+        // Have the state of WebContents seen by these two objects in sync.
+        mWebContents = null;
+    }
+
+    /**
+     * Refresh a11y state with that of {@link AccessibilityManager}.
+     */
+    public void refreshState() {
+        setState(mAccessibilityManager.isEnabled());
+    }
+
+    public void setShouldFocusOnPageLoad(boolean on) {
+        mShouldFocusOnPageLoad = on;
+    }
+
+    public boolean supportsAction(int action) {
+        // TODO(dmazzoni): implement this.
+        return false;
+    }
+
+    @TargetApi(Build.VERSION_CODES.M)
+    public void onProvideVirtualStructure(
+            final ViewStructure structure, final boolean ignoreScrollOffset) {
+        // Do not collect accessibility tree in incognito mode
+        if (mWebContents.isIncognito()) {
+            structure.setChildCount(0);
+            return;
+        }
+        structure.setChildCount(1);
+        final ViewStructure viewRoot = structure.asyncNewChild(0);
+        mWebContents.requestAccessibilitySnapshot(new AccessibilitySnapshotCallback() {
+            @Override
+            public void onAccessibilitySnapshot(AccessibilitySnapshotNode root) {
+                viewRoot.setClassName("");
+                viewRoot.setHint(mProductVersion);
+                if (root == null) {
+                    viewRoot.asyncCommit();
+                    return;
+                }
+                createVirtualStructure(viewRoot, root, ignoreScrollOffset);
+            }
+        });
+    }
+
+    // When creating the View structure, the left and top are relative to the parent node.
+    @TargetApi(Build.VERSION_CODES.M)
+    public void createVirtualStructure(ViewStructure viewNode, AccessibilitySnapshotNode node,
+            final boolean ignoreScrollOffset) {
+        viewNode.setClassName(node.className);
+        if (node.hasSelection) {
+            viewNode.setText(node.text, node.startSelection, node.endSelection);
+        } else {
+            viewNode.setText(node.text);
+        }
+        RenderCoordinates renderCoordinates = mWebContents.getRenderCoordinates();
+        int left = (int) renderCoordinates.fromLocalCssToPix(node.x);
+        int top = (int) renderCoordinates.fromLocalCssToPix(node.y);
+        int width = (int) renderCoordinates.fromLocalCssToPix(node.width);
+        int height = (int) renderCoordinates.fromLocalCssToPix(node.height);
+
+        Rect boundsInParent = new Rect(left, top, left + width, top + height);
+        if (node.isRootNode) {
+            // Offset of the web content relative to the View.
+            boundsInParent.offset(0, (int) renderCoordinates.getContentOffsetYPix());
+            if (!ignoreScrollOffset) {
+                boundsInParent.offset(-(int) renderCoordinates.getScrollXPix(),
+                        -(int) renderCoordinates.getScrollYPix());
+            }
+        }
+
+        viewNode.setDimens(boundsInParent.left, boundsInParent.top, 0, 0, width, height);
+        viewNode.setChildCount(node.children.size());
+        if (node.hasStyle) {
+            // The text size should be in physical pixels, not CSS pixels.
+            float textSize = renderCoordinates.fromLocalCssToPix(node.textSize);
+
+            int style = (node.bold ? ViewNode.TEXT_STYLE_BOLD : 0)
+                    | (node.italic ? ViewNode.TEXT_STYLE_ITALIC : 0)
+                    | (node.underline ? ViewNode.TEXT_STYLE_UNDERLINE : 0)
+                    | (node.lineThrough ? ViewNode.TEXT_STYLE_STRIKE_THRU : 0);
+            viewNode.setTextStyle(textSize, node.color, node.bgcolor, style);
+        }
+        for (int i = 0; i < node.children.size(); i++) {
+            createVirtualStructure(viewNode.asyncNewChild(i), node.children.get(i), true);
+        }
+        viewNode.asyncCommit();
+    }
+
     /**
      * @see View#onDetachedFromWindow()
      */
-    public void onDetachedFromWindow() {}
+    public void onDetachedFromWindow() {
+        mAccessibilityManager.removeAccessibilityStateChangeListener(this);
+    }
 
     /**
      * @see View#onAttachedToWindow()
-     * For versions before L, this method will not be called when container view is already
-     * attached to a window and webContentsAccessibility gets created later as a check for L plus
-     * versions is added in {@link ContentViewCore#getAccessibilityNodeProvider()}.
      */
-    public void onAttachedToWindow() {}
+    public void onAttachedToWindow() {
+        mAccessibilityManager.addAccessibilityStateChangeListener(this);
+        refreshState();
+    }
 
     private native long nativeInit(WebContents webContents);
     private native void nativeOnAutofillPopupDisplayed(long nativeWebContentsAccessibilityAndroid);
@@ -1303,4 +1467,4 @@
     protected native int[] nativeGetCharacterBoundingBoxes(
             long nativeWebContentsAccessibilityAndroid, int id, int start, int len);
     private native int nativeGetTextLength(long nativeWebContentsAccessibilityAndroid, int id);
-}
\ No newline at end of file
+}
diff --git a/content/public/android/java/src/org/chromium/content_public/common/UseZoomForDSFPolicy.java b/content/public/android/java/src/org/chromium/content_public/common/UseZoomForDSFPolicy.java
new file mode 100644
index 0000000..5b6bd7e
--- /dev/null
+++ b/content/public/android/java/src/org/chromium/content_public/common/UseZoomForDSFPolicy.java
@@ -0,0 +1,22 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.content_public.common;
+
+import org.chromium.base.annotations.JNINamespace;
+
+/**
+ * This is a utility class to wrap use_zoom_for_dsf_policy.cc.
+ */
+@JNINamespace("content")
+public final class UseZoomForDSFPolicy {
+    public static boolean isUseZoomForDSFEnabled() {
+        return nativeIsUseZoomForDSFEnabled();
+    }
+
+    private static native boolean nativeIsUseZoomForDSFEnabled();
+
+    // Do not instantiate this class.
+    private UseZoomForDSFPolicy() {}
+}
diff --git a/content/public/browser/android/synchronous_compositor.h b/content/public/browser/android/synchronous_compositor.h
index 5b795163..c9f6047 100644
--- a/content/public/browser/android/synchronous_compositor.h
+++ b/content/public/browser/android/synchronous_compositor.h
@@ -104,7 +104,8 @@
   virtual void SetMemoryPolicy(size_t bytes_limit) = 0;
 
   // Should be called by the embedder after the embedder had modified the
-  // scroll offset of the root layer.
+  // scroll offset of the root layer. |root_offset| must be in physical pixel
+  // scale if --use-zoom-for-dsf is enabled. Otherwise, it must be in DIP scale.
   virtual void DidChangeRootLayerScrollOffset(
       const gfx::ScrollOffset& root_offset) = 0;
 
diff --git a/content/public/browser/content_browser_client.cc b/content/public/browser/content_browser_client.cc
index 2e6eff5..17ce0fc74 100644
--- a/content/public/browser/content_browser_client.cc
+++ b/content/public/browser/content_browser_client.cc
@@ -589,6 +589,7 @@
   network::mojom::NetworkContextPtr network_context;
   network::mojom::NetworkContextParamsPtr context_params =
       network::mojom::NetworkContextParams::New();
+  context_params->user_agent = GetContentClient()->GetUserAgent();
   context_params->enable_data_url_support = true;
   context_params->enable_file_url_support = true;
   GetNetworkService()->CreateNetworkContext(MakeRequest(&network_context),
diff --git a/content/public/common/content_switches.cc b/content/public/common/content_switches.cc
index 986e4bb..6e67358 100644
--- a/content/public/common/content_switches.cc
+++ b/content/public/common/content_switches.cc
@@ -543,9 +543,6 @@
 const char kHistoryEntryRequiresUserGesture[] =
     "history-entry-requires-user-gesture";
 
-// These mappings only apply to the host resolver.
-const char kHostResolverRules[]             = "host-resolver-rules";
-
 // A set of public key hashes for which to ignore certificate-related errors.
 //
 // If the certificate chain presented by the server does not validate, and one
@@ -593,11 +590,6 @@
 // affect which events are logged).
 const char kLogFile[] = "log-file";
 
-// Enables saving net log events to a file. If a value is given, it used as the
-// path the the file, otherwise the file is named netlog.json and placed in the
-// user data directory.
-const char kLogNetLog[]                     = "log-net-log";
-
 // Resizes of the main frame are caused by changing between landscape and
 // portrait mode (i.e. Android) so the page should be rescaled to fit.
 const char kMainFrameResizesAreOrientationChanges[] =
diff --git a/content/public/common/content_switches.h b/content/public/common/content_switches.h
index f9ae1f311..3029695e 100644
--- a/content/public/common/content_switches.h
+++ b/content/public/common/content_switches.h
@@ -163,7 +163,6 @@
 CONTENT_EXPORT extern const char kGpuSandboxStartEarly[];
 CONTENT_EXPORT extern const char kGpuStartupDialog[];
 CONTENT_EXPORT extern const char kHistoryEntryRequiresUserGesture[];
-CONTENT_EXPORT extern const char kHostResolverRules[];
 CONTENT_EXPORT extern const char kIgnoreCertificateErrorsSPKIList[];
 CONTENT_EXPORT extern const char kInProcessGPU[];
 CONTENT_EXPORT extern const char kIPCConnectionTimeout[];
@@ -173,7 +172,6 @@
 CONTENT_EXPORT extern const char kLogGpuControlListDecisions[];
 CONTENT_EXPORT extern const char kLoggingLevel[];
 CONTENT_EXPORT extern const char kLogFile[];
-CONTENT_EXPORT extern const char kLogNetLog[];
 CONTENT_EXPORT extern const char kMainFrameResizesAreOrientationChanges[];
 extern const char kMaxUntiledLayerHeight[];
 extern const char kMaxUntiledLayerWidth[];
diff --git a/content/renderer/loader/resource_dispatcher.cc b/content/renderer/loader/resource_dispatcher.cc
index 16f8c1d..12cd296 100644
--- a/content/renderer/loader/resource_dispatcher.cc
+++ b/content/renderer/loader/resource_dispatcher.cc
@@ -110,11 +110,8 @@
   return sequence.GetNext();  // We start at zero.
 }
 
-ResourceDispatcher::ResourceDispatcher(
-    scoped_refptr<base::SingleThreadTaskRunner> thread_task_runner)
-    : delegate_(nullptr),
-      thread_task_runner_(thread_task_runner),
-      weak_factory_(this) {}
+ResourceDispatcher::ResourceDispatcher()
+    : delegate_(nullptr), weak_factory_(this) {}
 
 ResourceDispatcher::~ResourceDispatcher() {
 }
diff --git a/content/renderer/loader/resource_dispatcher.h b/content/renderer/loader/resource_dispatcher.h
index d287525..e1ebff4 100644
--- a/content/renderer/loader/resource_dispatcher.h
+++ b/content/renderer/loader/resource_dispatcher.h
@@ -69,8 +69,7 @@
   // CORS preflight requests.
   static int MakeRequestID();
 
-  explicit ResourceDispatcher(
-      scoped_refptr<base::SingleThreadTaskRunner> thread_task_runner);
+  ResourceDispatcher();
   virtual ~ResourceDispatcher();
 
   // Call this method to load the resource synchronously (i.e., in one shot).
@@ -138,11 +137,6 @@
     delegate_ = delegate;
   }
 
-  void SetThreadTaskRunner(
-      scoped_refptr<base::SingleThreadTaskRunner> thread_task_runner) {
-    thread_task_runner_ = thread_task_runner;
-  }
-
   base::WeakPtr<ResourceDispatcher> GetWeakPtr() {
     return weak_factory_.GetWeakPtr();
   }
@@ -233,8 +227,6 @@
 
   ResourceDispatcherDelegate* delegate_;
 
-  scoped_refptr<base::SingleThreadTaskRunner> thread_task_runner_;
-
   base::WeakPtrFactory<ResourceDispatcher> weak_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(ResourceDispatcher);
diff --git a/content/renderer/loader/resource_dispatcher_unittest.cc b/content/renderer/loader/resource_dispatcher_unittest.cc
index a90fa944..835f171 100644
--- a/content/renderer/loader/resource_dispatcher_unittest.cc
+++ b/content/renderer/loader/resource_dispatcher_unittest.cc
@@ -57,8 +57,7 @@
 class ResourceDispatcherTest : public testing::Test,
                                public network::mojom::URLLoaderFactory {
  public:
-  ResourceDispatcherTest()
-      : dispatcher_(new ResourceDispatcher(message_loop_.task_runner())) {}
+  ResourceDispatcherTest() : dispatcher_(new ResourceDispatcher()) {}
 
   ~ResourceDispatcherTest() override {
     dispatcher_.reset();
diff --git a/content/renderer/loader/site_isolation_stats_gatherer_browsertest.cc b/content/renderer/loader/site_isolation_stats_gatherer_browsertest.cc
index b0e75551..da91405e 100644
--- a/content/renderer/loader/site_isolation_stats_gatherer_browsertest.cc
+++ b/content/renderer/loader/site_isolation_stats_gatherer_browsertest.cc
@@ -16,6 +16,7 @@
 #include "content/public/test/test_utils.h"
 #include "content/shell/browser/shell.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
+#include "services/network/public/cpp/network_switches.h"
 #include "testing/gmock/include/gmock/gmock.h"
 
 namespace content {
@@ -40,7 +41,7 @@
     // This allows us to use "real" hostnames in URLs, which we can use to
     // create arbitrary SiteInstances.
     command_line->AppendSwitchASCII(
-        switches::kHostResolverRules,
+        network::switches::kHostResolverRules,
         "MAP * " + embedded_test_server()->host_port_pair().ToString() +
             ",EXCLUDE localhost");
 
diff --git a/content/renderer/loader/sync_load_context.cc b/content/renderer/loader/sync_load_context.cc
index 5df463c..a7c3959 100644
--- a/content/renderer/loader/sync_load_context.cc
+++ b/content/renderer/loader/sync_load_context.cc
@@ -49,8 +49,7 @@
       SharedURLLoaderFactory::Create(std::move(url_loader_factory));
 
   // Constructs a new ResourceDispatcher specifically for this request.
-  resource_dispatcher_ =
-      std::make_unique<ResourceDispatcher>(base::ThreadTaskRunnerHandle::Get());
+  resource_dispatcher_ = std::make_unique<ResourceDispatcher>();
 
   // Initialize the final URL with the original request URL. It will be
   // overwritten on redirects.
diff --git a/content/renderer/loader/url_loader_client_impl_unittest.cc b/content/renderer/loader/url_loader_client_impl_unittest.cc
index 8b952c3..92db3a6 100644
--- a/content/renderer/loader/url_loader_client_impl_unittest.cc
+++ b/content/renderer/loader/url_loader_client_impl_unittest.cc
@@ -24,8 +24,7 @@
 class URLLoaderClientImplTest : public ::testing::Test,
                                 public network::mojom::URLLoaderFactory {
  protected:
-  URLLoaderClientImplTest()
-      : dispatcher_(new ResourceDispatcher(message_loop_.task_runner())) {
+  URLLoaderClientImplTest() : dispatcher_(new ResourceDispatcher()) {
     request_id_ = dispatcher_->StartAsync(
         std::make_unique<network::ResourceRequest>(), 0,
         blink::scheduler::GetSingleThreadTaskRunnerForTesting(), url::Origin(),
diff --git a/content/renderer/loader/url_response_body_consumer_unittest.cc b/content/renderer/loader/url_response_body_consumer_unittest.cc
index 7fb870ea..a753611 100644
--- a/content/renderer/loader/url_response_body_consumer_unittest.cc
+++ b/content/renderer/loader/url_response_body_consumer_unittest.cc
@@ -113,8 +113,7 @@
     std::vector<network::mojom::URLLoaderClientPtr> clients_;
   };
 
-  URLResponseBodyConsumerTest()
-      : dispatcher_(new ResourceDispatcher(message_loop_.task_runner())) {}
+  URLResponseBodyConsumerTest() : dispatcher_(new ResourceDispatcher()) {}
 
   ~URLResponseBodyConsumerTest() override {
     dispatcher_.reset();
diff --git a/content/renderer/loader/web_url_loader_impl_unittest.cc b/content/renderer/loader/web_url_loader_impl_unittest.cc
index 2e2ff1d..3833e39 100644
--- a/content/renderer/loader/web_url_loader_impl_unittest.cc
+++ b/content/renderer/loader/web_url_loader_impl_unittest.cc
@@ -64,8 +64,7 @@
 
 class TestResourceDispatcher : public ResourceDispatcher {
  public:
-  TestResourceDispatcher()
-      : ResourceDispatcher(nullptr), canceled_(false), defers_loading_(false) {}
+  TestResourceDispatcher() : canceled_(false), defers_loading_(false) {}
 
   ~TestResourceDispatcher() override {}
 
diff --git a/content/renderer/media/android/media_player_renderer_client.cc b/content/renderer/media/android/media_player_renderer_client.cc
index f45b5c0..b1e1965 100644
--- a/content/renderer/media/android/media_player_renderer_client.cc
+++ b/content/renderer/media/android/media_player_renderer_client.cc
@@ -22,7 +22,13 @@
       compositor_task_runner_(std::move(compositor_task_runner)),
       weak_factory_(this) {}
 
-MediaPlayerRendererClient::~MediaPlayerRendererClient() {}
+MediaPlayerRendererClient::~MediaPlayerRendererClient() {
+  // Clearing the STW's callback into |this| must happen first. Otherwise, the
+  // underlying StreamTextureProxy can callback into OnFrameAvailable() on the
+  // |compositor_task_runner_|, while we are destroying |this|.
+  // See https://crbug.com/688466.
+  stream_texture_wrapper_->ClearReceivedFrameCBOnAnyThread();
+}
 
 void MediaPlayerRendererClient::Initialize(
     media::MediaResource* media_resource,
diff --git a/content/renderer/media/android/stream_texture_wrapper_impl.cc b/content/renderer/media/android/stream_texture_wrapper_impl.cc
index b26079e..4199845 100644
--- a/content/renderer/media/android/stream_texture_wrapper_impl.cc
+++ b/content/renderer/media/android/stream_texture_wrapper_impl.cc
@@ -109,6 +109,12 @@
   stream_texture_proxy_->ForwardStreamTextureForSurfaceRequest(request_token);
 }
 
+void StreamTextureWrapperImpl::ClearReceivedFrameCBOnAnyThread() {
+  // Safely stop StreamTextureProxy from signaling the arrival of new frames.
+  if (stream_texture_proxy_)
+    stream_texture_proxy_->ClearReceivedFrameCB();
+}
+
 void StreamTextureWrapperImpl::SetCurrentFrameInternal(
     const scoped_refptr<media::VideoFrame>& video_frame) {
   base::AutoLock auto_lock(current_frame_lock_);
@@ -176,15 +182,9 @@
 }
 
 void StreamTextureWrapperImpl::Destroy() {
-  // Safely stop StreamTextureProxy from signaling the arrival of new frames.
-  // |stream_texture_proxy_| will be cleared on the main task runner, and its
-  // deleter will destroy the underlying object on the right task runner.
-  if (stream_texture_proxy_)
-    stream_texture_proxy_->ClearReceivedFrameCB();
-
   if (!main_task_runner_->BelongsToCurrentThread()) {
     // base::Unretained is safe here because this function is the only one that
-    // can can call delete.
+    // can call delete.
     main_task_runner_->PostTask(
         FROM_HERE,
         base::Bind(&StreamTextureWrapperImpl::Destroy, base::Unretained(this)));
diff --git a/content/renderer/media/android/stream_texture_wrapper_impl.h b/content/renderer/media/android/stream_texture_wrapper_impl.h
index 4809633..80f96c7 100644
--- a/content/renderer/media/android/stream_texture_wrapper_impl.h
+++ b/content/renderer/media/android/stream_texture_wrapper_impl.h
@@ -83,6 +83,10 @@
   void ForwardStreamTextureForSurfaceRequest(
       const base::UnguessableToken& request_token) override;
 
+  // Clears the |received_frame_cb| passed in Initialize().
+  // Should be safe to call from any thread.
+  void ClearReceivedFrameCBOnAnyThread() override;
+
  private:
   StreamTextureWrapperImpl(
       bool enable_texture_copy,
diff --git a/content/renderer/media/webrtc/rtc_rtp_sender_unittest.cc b/content/renderer/media/webrtc/rtc_rtp_sender_unittest.cc
index 5574baec..f902a1a 100644
--- a/content/renderer/media/webrtc/rtc_rtp_sender_unittest.cc
+++ b/content/renderer/media/webrtc/rtc_rtp_sender_unittest.cc
@@ -10,6 +10,7 @@
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "base/single_thread_task_runner.h"
+#include "build/build_config.h"
 #include "content/child/child_process.h"
 #include "content/renderer/media/media_stream_audio_source.h"
 #include "content/renderer/media/webrtc/mock_peer_connection_dependency_factory.h"
@@ -134,7 +135,14 @@
   EXPECT_EQ(web_track2.UniqueId(), sender_->Track().UniqueId());
 }
 
-TEST_F(RTCRtpSenderTest, ReplaceTrackWithNullTrack) {
+// This test is flaky on Android and Linux.
+// See crbug.com/803597 for detail.
+#if defined(OS_ANDROID) || defined(OS_LINUX)
+#define MAYBE_ReplaceTrackWithNullTrack DISABLED_ReplaceTrackWithNullTrack
+#else
+#define MAYBE_ReplaceTrackWithNullTrack ReplaceTrackWithNullTrack
+#endif
+TEST_F(RTCRtpSenderTest, MAYBE_ReplaceTrackWithNullTrack) {
   auto web_track = CreateWebTrack("track_id");
   sender_ = CreateSender(web_track);
 
diff --git a/content/renderer/render_thread_impl.cc b/content/renderer/render_thread_impl.cc
index f55d956..1475c85 100644
--- a/content/renderer/render_thread_impl.cc
+++ b/content/renderer/render_thread_impl.cc
@@ -705,8 +705,7 @@
       new NotificationDispatcher(thread_safe_sender());
   AddFilter(notification_dispatcher_->GetFilter());
 
-  resource_dispatcher_.reset(
-      new ResourceDispatcher(message_loop()->task_runner()));
+  resource_dispatcher_.reset(new ResourceDispatcher());
   quota_dispatcher_.reset(new QuotaDispatcher(message_loop()->task_runner()));
   url_loader_throttle_provider_ =
       GetContentClient()->renderer()->CreateURLLoaderThrottleProvider(
@@ -1250,16 +1249,6 @@
       base::Bind(base::IgnoreResult(&RenderThreadImpl::OnMessageReceived),
                  base::Unretained(this)));
 
-  scoped_refptr<base::SingleThreadTaskRunner> resource_task_queue2;
-  if (resource_task_queue) {
-    resource_task_queue2 = resource_task_queue;
-  } else {
-    resource_task_queue2 = renderer_scheduler_->LoadingTaskRunner();
-  }
-  // The ResourceDispatcher needs to use the same queue to ensure tasks are
-  // executed in the expected order.
-  resource_dispatcher_->SetThreadTaskRunner(resource_task_queue2);
-
   if (!command_line.HasSwitch(switches::kDisableThreadedCompositing))
     InitializeCompositorThread();
 
diff --git a/content/renderer/service_worker/service_worker_fetch_context_impl.cc b/content/renderer/service_worker/service_worker_fetch_context_impl.cc
index 1c9f6199..ca6923c6 100644
--- a/content/renderer/service_worker/service_worker_fetch_context_impl.cc
+++ b/content/renderer/service_worker/service_worker_fetch_context_impl.cc
@@ -28,10 +28,8 @@
 
 ServiceWorkerFetchContextImpl::~ServiceWorkerFetchContextImpl() {}
 
-void ServiceWorkerFetchContextImpl::InitializeOnWorkerThread(
-    scoped_refptr<base::SingleThreadTaskRunner> loading_task_runner) {
-  resource_dispatcher_ =
-      std::make_unique<ResourceDispatcher>(std::move(loading_task_runner));
+void ServiceWorkerFetchContextImpl::InitializeOnWorkerThread() {
+  resource_dispatcher_ = std::make_unique<ResourceDispatcher>();
 
   url_loader_factory_getter_ = url_loader_factory_getter_info_.Bind();
 }
diff --git a/content/renderer/service_worker/service_worker_fetch_context_impl.h b/content/renderer/service_worker/service_worker_fetch_context_impl.h
index 712a5d6..ab43322b 100644
--- a/content/renderer/service_worker/service_worker_fetch_context_impl.h
+++ b/content/renderer/service_worker/service_worker_fetch_context_impl.h
@@ -10,10 +10,6 @@
 #include "third_party/WebKit/public/platform/WebWorkerFetchContext.h"
 #include "url/gurl.h"
 
-namespace base {
-class SingleThreadTaskRunner;
-}  // namespace base
-
 namespace content {
 class ResourceDispatcher;
 class URLLoaderThrottleProvider;
@@ -28,8 +24,7 @@
   ~ServiceWorkerFetchContextImpl() override;
 
   // blink::WebWorkerFetchContext implementation:
-  void InitializeOnWorkerThread(
-      scoped_refptr<base::SingleThreadTaskRunner>) override;
+  void InitializeOnWorkerThread() override;
   std::unique_ptr<blink::WebURLLoaderFactory> CreateURLLoaderFactory() override;
   void WillSendRequest(blink::WebURLRequest&) override;
   bool IsControlledByServiceWorker() const override;
diff --git a/content/renderer/service_worker/worker_fetch_context_impl.cc b/content/renderer/service_worker/worker_fetch_context_impl.cc
index bd205b4..25b8870 100644
--- a/content/renderer/service_worker/worker_fetch_context_impl.cc
+++ b/content/renderer/service_worker/worker_fetch_context_impl.cc
@@ -123,13 +123,10 @@
 
 WorkerFetchContextImpl::~WorkerFetchContextImpl() {}
 
-void WorkerFetchContextImpl::InitializeOnWorkerThread(
-    scoped_refptr<base::SingleThreadTaskRunner> loading_task_runner) {
-  DCHECK(loading_task_runner->RunsTasksInCurrentSequence());
+void WorkerFetchContextImpl::InitializeOnWorkerThread() {
   DCHECK(!resource_dispatcher_);
   DCHECK(!binding_.is_bound());
-  resource_dispatcher_ =
-      std::make_unique<ResourceDispatcher>(std::move(loading_task_runner));
+  resource_dispatcher_ = std::make_unique<ResourceDispatcher>();
 
   url_loader_factory_getter_ = url_loader_factory_getter_info_.Bind();
   if (service_worker_client_request_.is_pending())
diff --git a/content/renderer/service_worker/worker_fetch_context_impl.h b/content/renderer/service_worker/worker_fetch_context_impl.h
index 1bc77171..1e2da3e7 100644
--- a/content/renderer/service_worker/worker_fetch_context_impl.h
+++ b/content/renderer/service_worker/worker_fetch_context_impl.h
@@ -18,10 +18,6 @@
 #include "third_party/WebKit/public/platform/WebWorkerFetchContext.h"
 #include "url/gurl.h"
 
-namespace base {
-class SingleThreadTaskRunner;
-}  // namespace base
-
 namespace IPC {
 class Message;
 }  // namespace IPC
@@ -48,8 +44,7 @@
   ~WorkerFetchContextImpl() override;
 
   // blink::WebWorkerFetchContext implementation:
-  void InitializeOnWorkerThread(
-      scoped_refptr<base::SingleThreadTaskRunner>) override;
+  void InitializeOnWorkerThread() override;
   std::unique_ptr<blink::WebURLLoaderFactory> CreateURLLoaderFactory() override;
   void WillSendRequest(blink::WebURLRequest&) override;
   bool IsControlledByServiceWorker() const override;
diff --git a/content/shell/DEPS b/content/shell/DEPS
index 5d690166..f9ea525 100644
--- a/content/shell/DEPS
+++ b/content/shell/DEPS
@@ -12,6 +12,9 @@
   "+content/app/strings/grit",  # For generated headers
   "+content/public",
 
+  # Network service public library.
+  "+services/network/public/cpp",
+
   # The content_shell is an embedder so it must work with resource bundles.
   "+ui/base/l10n",
   "+ui/base/resource",
diff --git a/content/shell/app/shell_main_delegate.cc b/content/shell/app/shell_main_delegate.cc
index 83eee06..653c57c 100644
--- a/content/shell/app/shell_main_delegate.cc
+++ b/content/shell/app/shell_main_delegate.cc
@@ -41,6 +41,7 @@
 #include "media/base/media_switches.h"
 #include "net/cookies/cookie_monster.h"
 #include "ppapi/features/features.h"
+#include "services/network/public/cpp/network_switches.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/base/ui_base_paths.h"
 #include "ui/base/ui_base_switches.h"
@@ -219,7 +220,7 @@
 
     command_line.AppendSwitch(switches::kEnablePreciseMemoryInfo);
 
-    command_line.AppendSwitchASCII(switches::kHostResolverRules,
+    command_line.AppendSwitchASCII(network::switches::kHostResolverRules,
                                    "MAP *.test 127.0.0.1");
 
     command_line.AppendSwitch(switches::kEnablePartialRaster);
diff --git a/content/shell/browser/shell_net_log.cc b/content/shell/browser/shell_net_log.cc
index 7958b16..ba691ae 100644
--- a/content/shell/browser/shell_net_log.cc
+++ b/content/shell/browser/shell_net_log.cc
@@ -17,6 +17,7 @@
 #include "content/public/common/content_switches.h"
 #include "net/log/file_net_log_observer.h"
 #include "net/log/net_log_util.h"
+#include "services/network/public/cpp/network_switches.h"
 
 namespace content {
 
@@ -46,9 +47,9 @@
   const base::CommandLine* command_line =
       base::CommandLine::ForCurrentProcess();
 
-  if (command_line->HasSwitch(switches::kLogNetLog)) {
+  if (command_line->HasSwitch(network::switches::kLogNetLog)) {
     base::FilePath log_path =
-        command_line->GetSwitchValuePath(switches::kLogNetLog);
+        command_line->GetSwitchValuePath(network::switches::kLogNetLog);
     net::NetLogCaptureMode capture_mode = net::NetLogCaptureMode::Default();
 
     file_net_log_observer_ = net::FileNetLogObserver::CreateUnbounded(
diff --git a/content/shell/browser/shell_url_request_context_getter.cc b/content/shell/browser/shell_url_request_context_getter.cc
index ea95e19..5d6b814 100644
--- a/content/shell/browser/shell_url_request_context_getter.cc
+++ b/content/shell/browser/shell_url_request_context_getter.cc
@@ -41,6 +41,7 @@
 #include "net/ssl/default_channel_id_store.h"
 #include "net/url_request/url_request_context.h"
 #include "net/url_request/url_request_context_builder.h"
+#include "services/network/public/cpp/network_switches.h"
 #include "url/url_constants.h"
 
 namespace content {
@@ -174,12 +175,12 @@
         ignore_certificate_errors_;
     builder.set_http_network_session_params(network_session_params);
 
-    if (command_line.HasSwitch(switches::kHostResolverRules)) {
+    if (command_line.HasSwitch(network::switches::kHostResolverRules)) {
       std::unique_ptr<net::MappedHostResolver> mapped_host_resolver(
           new net::MappedHostResolver(
               net::HostResolver::CreateDefaultResolver(net_log_)));
-      mapped_host_resolver->SetRulesFromString(
-          command_line.GetSwitchValueASCII(switches::kHostResolverRules));
+      mapped_host_resolver->SetRulesFromString(command_line.GetSwitchValueASCII(
+          network::switches::kHostResolverRules));
       builder.set_host_resolver(std::move(mapped_host_resolver));
     }
 
diff --git a/content/test/gpu/gpu_tests/webgl_conformance_expectations_unittest.py b/content/test/gpu/gpu_tests/webgl_conformance_expectations_unittest.py
index d2d8dc5..e609a23c 100644
--- a/content/test/gpu/gpu_tests/webgl_conformance_expectations_unittest.py
+++ b/content/test/gpu/gpu_tests/webgl_conformance_expectations_unittest.py
@@ -49,6 +49,9 @@
 
 class WebGLConformanceExpectationsTest(unittest.TestCase):
   def testGlslConstructVecMatIndexExpectationOnWin(self):
+    # TODO(kbr): re-enable after Catapult rolls forward. crbug.com/801578
+    if True:
+      return unittest.skip('Skipping due to crbug.com/801578')
     possible_browser = fakes.FakePossibleBrowser()
     browser = possible_browser.Create(None)
     browser.platform = FakeWindowsPlatform()
diff --git a/device/bluetooth/bluetooth_service_record_win.cc b/device/bluetooth/bluetooth_service_record_win.cc
index 463a561..2ed1323 100644
--- a/device/bluetooth/bluetooth_service_record_win.cc
+++ b/device/bluetooth/bluetooth_service_record_win.cc
@@ -4,6 +4,8 @@
 
 #include "device/bluetooth/bluetooth_service_record_win.h"
 
+#include <math.h>
+
 #include <string>
 
 #include "base/strings/string_number_conversions.h"
diff --git a/docs/network_traffic_annotations.md b/docs/network_traffic_annotations.md
index a7aaee9..dc5d180 100644
--- a/docs/network_traffic_annotations.md
+++ b/docs/network_traffic_annotations.md
@@ -418,10 +418,12 @@
 where after serialization, the annotation object is first created, then receives
 value. In these cases, `net::MutableNetworkTrafficAnnotationTag` and
 `net::MutablePartialNetworkTrafficAnnotationTag` can be used which do not have
-this limitation. It is strongly suggested that mutable annotations would be used
-only if there is no other way around it. Use cases are checked with the
-`traffic_annotation_auditor` to ensure proper values for the mutable
-annotations.
+this limitation.
+Mutable annotations have a run time check before being converted into normal
+annotations to ensure their content is valid. Therefore it is suggested that
+they would be used only if there is no other way around it. Use cases are
+checked with the `traffic_annotation_auditor` to ensure proper initialization
+values for the mutable annotations.
 
 
 ## Mojo Interfaces (Advanced)
diff --git a/docs/security/faq.md b/docs/security/faq.md
index fc97b934..3d4ab3f 100644
--- a/docs/security/faq.md
+++ b/docs/security/faq.md
@@ -570,9 +570,10 @@
      credentials in "Login Data" in the Chrome users profile directory, but
      encrypted on disk with a key that is then stored in the user's Keychain.
      See [Issue 466638](https://crbug.com/466638) for further explanation.
-*    On Linux, credentials are stored in an encrypted database, and the password
-     to decrypt the contents of that database are stored in KWallet or Gnome
-     Keyring. (See [Issue 602624](https://crbug.com/602624).)
+*    On Linux, credentials are stored into Gnome-Keyring or KWallet, depending
+     on the environment. On environments which don't ship with Gnome-Keyring
+     or KWallet, the password is stored into "Login Data" in an unprotected
+     format.
 *    On iOS, passwords are currently stored directly in the iOS Keychain and
      referenced from the rest of the metadata stored in a separate DB. The plan
      there is to just store them in plain text in the DB, because iOS gives
diff --git a/extensions/browser/BUILD.gn b/extensions/browser/BUILD.gn
index 24e5672..7c8904dc 100644
--- a/extensions/browser/BUILD.gn
+++ b/extensions/browser/BUILD.gn
@@ -78,6 +78,8 @@
     "content_hash_tree.h",
     "content_verifier.cc",
     "content_verifier.h",
+    "content_verifier/content_hash.cc",
+    "content_verifier/content_hash.h",
     "content_verifier_delegate.h",
     "content_verifier_io_data.cc",
     "content_verifier_io_data.h",
@@ -161,7 +163,6 @@
     "extension_registry_observer.h",
     "extension_request_limiting_throttle.cc",
     "extension_request_limiting_throttle.h",
-    "extension_scoped_prefs.h",
     "extension_service_worker_message_filter.cc",
     "extension_service_worker_message_filter.h",
     "extension_system.cc",
diff --git a/extensions/browser/api/declarative/rules_cache_delegate.cc b/extensions/browser/api/declarative/rules_cache_delegate.cc
index be85fde..f950c28 100644
--- a/extensions/browser/api/declarative/rules_cache_delegate.cc
+++ b/extensions/browser/api/declarative/rules_cache_delegate.cc
@@ -203,8 +203,7 @@
 bool RulesCacheDelegate::GetDeclarativeRulesStored(
     const std::string& extension_id) const {
   CHECK(browser_context_);
-  const ExtensionScopedPrefs* extension_prefs =
-      ExtensionPrefs::Get(browser_context_);
+  const ExtensionPrefs* extension_prefs = ExtensionPrefs::Get(browser_context_);
 
   bool rules_stored = true;
   if (extension_prefs->ReadPrefAsBoolean(
@@ -223,7 +222,7 @@
   DCHECK(ExtensionRegistry::Get(browser_context_)
              ->GetExtensionById(extension_id, ExtensionRegistry::EVERYTHING));
 
-  ExtensionScopedPrefs* extension_prefs = ExtensionPrefs::Get(browser_context_);
+  ExtensionPrefs* extension_prefs = ExtensionPrefs::Get(browser_context_);
   extension_prefs->UpdateExtensionPref(
       extension_id, rules_stored_key_,
       std::make_unique<base::Value>(rules_stored));
diff --git a/extensions/browser/api/declarative_net_request/BUILD.gn b/extensions/browser/api/declarative_net_request/BUILD.gn
index c4db6c72..9508334 100644
--- a/extensions/browser/api/declarative_net_request/BUILD.gn
+++ b/extensions/browser/api/declarative_net_request/BUILD.gn
@@ -32,7 +32,6 @@
     "//components/web_cache/browser:browser",
     "//content/public/browser:browser",
     "//extensions/browser:browser_sources",
-    "//extensions/browser/api/declarative_net_request/flat:extension_ruleset",
     "//extensions/common",
     "//extensions/common/api",
     "//net",
diff --git a/extensions/browser/content_hash_fetcher.cc b/extensions/browser/content_hash_fetcher.cc
index c6f1a44..3a674ec 100644
--- a/extensions/browser/content_hash_fetcher.cc
+++ b/extensions/browser/content_hash_fetcher.cc
@@ -10,25 +10,16 @@
 #include <memory>
 #include <vector>
 
-#include "base/base64.h"
-#include "base/files/file_enumerator.h"
 #include "base/files/file_util.h"
 #include "base/json/json_reader.h"
 #include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/metrics/histogram_macros.h"
 #include "base/synchronization/lock.h"
 #include "base/task_scheduler/post_task.h"
-#include "base/timer/elapsed_timer.h"
-#include "base/version.h"
 #include "content/public/browser/browser_thread.h"
-#include "crypto/sha2.h"
-#include "extensions/browser/computed_hashes.h"
-#include "extensions/browser/content_hash_tree.h"
+#include "extensions/browser/content_verifier/content_hash.h"
 #include "extensions/browser/content_verifier_delegate.h"
 #include "extensions/browser/extension_file_task_runner.h"
 #include "extensions/browser/verified_contents.h"
-#include "extensions/common/constants.h"
 #include "extensions/common/extension.h"
 #include "extensions/common/file_util.h"
 #include "net/base/load_flags.h"
@@ -37,14 +28,28 @@
 #include "net/url_request/url_fetcher_delegate.h"
 #include "net/url_request/url_request_status.h"
 
+namespace extensions {
+
 namespace {
 
-typedef std::set<base::FilePath> SortedFilePathSet;
+std::unique_ptr<ContentHash> ReadContentHashAfterVerifiedContentsWritten(
+    const ContentHash::ExtensionKey& extension_key,
+    bool force,
+    const ContentHash::IsCancelledCallback& is_cancelled) {
+  // This function is called after writing verified_contents.json, so we'd
+  // expect a valid file at this point. Even in the case where the file turns
+  // out to be invalid right after writing it (malicous behavior?) don't delete
+  // it.
+  int mode = 0;
+
+  if (force)
+    mode |= ContentHash::Mode::kForceRecreateExistingComputedHashesFile;
+
+  return ContentHash::Create(extension_key, mode, is_cancelled);
+}
 
 }  // namespace
 
-namespace extensions {
-
 // This class takes care of doing the disk and network I/O work to ensure we
 // have both verified_contents.json files from the webstore and
 // computed_hashes.json files computed over the files in an extension's
@@ -56,9 +61,7 @@
   using CompletionCallback =
       base::Callback<void(scoped_refptr<ContentHashFetcherJob>)>;
   ContentHashFetcherJob(net::URLRequestContextGetter* request_context,
-                        const ContentVerifierKey& key,
-                        const std::string& extension_id,
-                        const base::FilePath& extension_path,
+                        const ContentHash::ExtensionKey& extension_key,
                         const GURL& fetch_url,
                         bool force,
                         const CompletionCallback& callback);
@@ -78,9 +81,9 @@
   // are available by calling hash_mismatch_unix_paths().
   bool success() { return success_; }
 
-  bool force() { return force_; }
+  bool force() const { return force_; }
 
-  const std::string& extension_id() { return extension_id_; }
+  const std::string& extension_id() { return extension_key_.extension_id; }
 
   // Returns the set of paths (with unix style '/' separators) that had a hash
   // mismatch.
@@ -92,52 +95,42 @@
   friend class base::RefCountedThreadSafe<ContentHashFetcherJob>;
   ~ContentHashFetcherJob() override;
 
-  // Tries to load a verified_contents.json file at |path|. On successfully
-  // reading and validing the file, the verified_contents_ member variable will
-  // be set and this function will return true. If the file does not exist, or
-  // exists but is invalid, it will return false. Also, any invalid
-  // file will be removed from disk and
-  bool LoadVerifiedContents(const base::FilePath& path);
+  // Methods called when job completes.
+  void Succeeded(const std::set<base::FilePath>& hash_mismatch_unix_paths);
+  void Failed();
+
+  // Returns content hashes after trying to load them.
+  // Invalid verified_contents.json will be removed from disk.
+  std::unique_ptr<ContentHash> LoadVerifiedContents();
 
   // Callback for when we're done doing file I/O to see if we already have
-  // a verified contents file. If we don't, this will kick off a network
-  // request to get one.
-  void DoneCheckingForVerifiedContents(bool found);
+  // content hashes. If we don't have verified_contents.json, this will kick off
+  // a network request to get one.
+  void DoneCheckingForVerifiedContents(
+      std::unique_ptr<ContentHash> content_hash);
 
   // URLFetcherDelegate interface
   void OnURLFetchComplete(const net::URLFetcher* source) override;
 
-  // Callback for when we're done ensuring we have verified contents, and are
-  // ready to move on to MaybeCreateHashes.
-  void DoneFetchingVerifiedContents(bool success);
+  // Callback for when we've read verified contents after fetching it from
+  // network and writing it to disk.
+  void ReadCompleteAfterWrite(std::unique_ptr<ContentHash> content_hash);
 
   // Callback for the job to write the verified contents to the filesystem.
   void OnVerifiedContentsWritten(size_t expected_size, int write_result);
 
-  // The verified contents file from the webstore only contains the treehash
-  // root hash, but for performance we want to cache the individual block level
-  // hashes. This function will create that cache with block-level hashes for
-  // each file in the extension if needed (the treehash root hash for each of
-  // these should equal what is in the verified contents file from the
-  // webstore).
-  void MaybeCreateHashes();
-
-  // Computes hashes for all files in |extension_path_|, and uses a
-  // ComputedHashes::Writer to write that information into
-  // |hashes_file|. Returns true on success.
-  bool CreateHashes(const base::FilePath& hashes_file);
-
   // Will call the callback, if we haven't been cancelled.
   void DispatchCallback();
 
   net::URLRequestContextGetter* request_context_;
-  std::string extension_id_;
-  base::FilePath extension_path_;
+
+  // Note: Read from multiple threads/sequences.
+  const ContentHash::ExtensionKey extension_key_;
 
   // The url we'll need to use to fetch a verified_contents.json file.
   GURL fetch_url_;
 
-  bool force_;
+  const bool force_;
 
   CompletionCallback callback_;
   content::BrowserThread::ID creation_thread_;
@@ -146,9 +139,6 @@
   // Created and destroyed on |creation_thread_|.
   std::unique_ptr<net::URLFetcher> url_fetcher_;
 
-  // The key used to validate verified_contents.json.
-  ContentVerifierKey key_;
-
   // The parsed contents of the verified_contents.json file, either read from
   // disk or fetched from the network and then written to disk.
   std::unique_ptr<VerifiedContents> verified_contents_;
@@ -159,9 +149,6 @@
   // Paths that were found to have a mismatching hash.
   std::set<base::FilePath> hash_mismatch_unix_paths_;
 
-  // The block size to use for hashing.
-  int block_size_;
-
   // Note: this may be accessed from multiple threads, so all access should
   // be protected by |cancelled_lock_|.
   bool cancelled_;
@@ -174,23 +161,16 @@
 
 ContentHashFetcherJob::ContentHashFetcherJob(
     net::URLRequestContextGetter* request_context,
-    const ContentVerifierKey& key,
-    const std::string& extension_id,
-    const base::FilePath& extension_path,
+    const ContentHash::ExtensionKey& extension_key,
     const GURL& fetch_url,
     bool force,
     const CompletionCallback& callback)
     : request_context_(request_context),
-      extension_id_(extension_id),
-      extension_path_(extension_path),
+      extension_key_(extension_key),
       fetch_url_(fetch_url),
       force_(force),
       callback_(callback),
-      key_(key),
       success_(false),
-      // TODO(asargent) - use the value from verified_contents.json for each
-      // file, instead of using a constant.
-      block_size_(4096),
       cancelled_(false) {
   bool got_id =
       content::BrowserThread::GetCurrentThreadIdentifier(&creation_thread_);
@@ -198,14 +178,11 @@
 }
 
 void ContentHashFetcherJob::Start() {
-  base::FilePath verified_contents_path =
-      file_util::GetVerifiedContentsPath(extension_path_);
-  base::PostTaskWithTraitsAndReplyWithResult(
-      FROM_HERE, {base::MayBlock(), base::TaskPriority::USER_VISIBLE},
-      base::Bind(&ContentHashFetcherJob::LoadVerifiedContents, this,
-                 verified_contents_path),
-      base::Bind(&ContentHashFetcherJob::DoneCheckingForVerifiedContents,
-                 this));
+  base::PostTaskAndReplyWithResult(
+      GetExtensionFileTaskRunner().get(), FROM_HERE,
+      base::BindOnce(&ContentHashFetcherJob::LoadVerifiedContents, this),
+      base::BindOnce(&ContentHashFetcherJob::DoneCheckingForVerifiedContents,
+                     this));
 }
 
 void ContentHashFetcherJob::Cancel() {
@@ -221,35 +198,43 @@
 
 ContentHashFetcherJob::~ContentHashFetcherJob() {
   // Destroy |url_fetcher_| on correct thread.
-  // It was possible for it to be deleted on blocking pool from
-  // MaybeCreateHashes(). See https://crbug.com/702300 for details.
+  // It was possible for it to be deleted on blocking pool. See
+  // https://crbug.com/702300 for details.
+  // TODO(lazyboy): Make ContentHashFetcherJob non ref-counted.
   if (url_fetcher_ && !content::BrowserThread::CurrentlyOn(creation_thread_)) {
     content::BrowserThread::DeleteSoon(creation_thread_, FROM_HERE,
                                        url_fetcher_.release());
   }
 }
 
-bool ContentHashFetcherJob::LoadVerifiedContents(const base::FilePath& path) {
-  if (!base::PathExists(path))
-    return false;
-  verified_contents_.reset(new VerifiedContents(key_.data, key_.size));
-  if (!verified_contents_->InitFrom(path)) {
-    verified_contents_.reset();
-    if (!base::DeleteFile(path, false))
-      LOG(WARNING) << "Failed to delete " << path.value();
-    return false;
-  }
-  return true;
+std::unique_ptr<ContentHash> ContentHashFetcherJob::LoadVerifiedContents() {
+  // Will delete invalid verified contents file.
+  int mode = ContentHash::Mode::kDeleteInvalidVerifiedContents;
+  if (force_)
+    mode |= ContentHash::Mode::kForceRecreateExistingComputedHashesFile;
+
+  return ContentHash::Create(
+      extension_key_, mode,
+      base::BindRepeating(&ContentHashFetcherJob::IsCancelled, this));
 }
 
-void ContentHashFetcherJob::DoneCheckingForVerifiedContents(bool found) {
+void ContentHashFetcherJob::DoneCheckingForVerifiedContents(
+    std::unique_ptr<ContentHash> content_hash) {
   if (IsCancelled())
     return;
-  if (found) {
-    VLOG(1) << "Found verified contents for " << extension_id_;
-    DoneFetchingVerifiedContents(true);
+  if (content_hash->has_verified_contents()) {
+    VLOG(1) << "Found verified contents for " << extension_key_.extension_id;
+    if (content_hash->succeeded()) {
+      // We've found both verified_contents.json and computed_hashes.json, we're
+      // done.
+      Succeeded(content_hash->hash_mismatch_unix_paths());
+    } else {
+      // Even though we attempted to write computed_hashes.json after reading
+      // verified_contents.json, something went wrong.
+      Failed();
+    }
   } else {
-    VLOG(1) << "Missing verified contents for " << extension_id_
+    VLOG(1) << "Missing verified contents for " << extension_key_.extension_id
             << ", fetching...";
     net::NetworkTrafficAnnotationTag traffic_annotation =
         net::DefineNetworkTrafficAnnotation("content_hash_verification_job", R"(
@@ -298,7 +283,7 @@
 }
 
 void ContentHashFetcherJob::OnURLFetchComplete(const net::URLFetcher* source) {
-  VLOG(1) << "URLFetchComplete for " << extension_id_
+  VLOG(1) << "URLFetchComplete for " << extension_key_.extension_id
           << " is_success:" << url_fetcher_->GetStatus().is_success() << " "
           << fetch_url_.possibly_invalid_spec();
   // Delete |url_fetcher_| once we no longer need it.
@@ -309,7 +294,7 @@
   std::unique_ptr<std::string> response(new std::string);
   if (!url_fetcher->GetStatus().is_success() ||
       !url_fetcher->GetResponseAsString(response.get())) {
-    DoneFetchingVerifiedContents(false);
+    Failed();
     return;
   }
 
@@ -318,134 +303,71 @@
   // the right cookies).  TODO(asargent) - It would be a nice enhancement to
   // move to parsing this in a sandboxed helper (crbug.com/372878).
   std::unique_ptr<base::Value> parsed(base::JSONReader::Read(*response));
-  if (parsed) {
-    VLOG(1) << "JSON parsed ok for " << extension_id_;
-
-    parsed.reset();  // no longer needed
-    base::FilePath destination =
-        file_util::GetVerifiedContentsPath(extension_path_);
-    size_t size = response->size();
-    base::PostTaskWithTraitsAndReplyWithResult(
-        FROM_HERE, {base::MayBlock(), base::TaskPriority::USER_VISIBLE},
-        base::Bind(&WriteFileHelper, destination, base::Passed(&response)),
-        base::Bind(&ContentHashFetcherJob::OnVerifiedContentsWritten, this,
-                   size));
-  } else {
-    DoneFetchingVerifiedContents(false);
+  if (!parsed) {
+    Failed();
+    return;
   }
+
+  VLOG(1) << "JSON parsed ok for " << extension_key_.extension_id;
+
+  parsed.reset();  // no longer needed
+  base::FilePath destination =
+      file_util::GetVerifiedContentsPath(extension_key_.extension_root);
+  size_t size = response->size();
+  base::PostTaskWithTraitsAndReplyWithResult(
+      FROM_HERE, {base::MayBlock(), base::TaskPriority::USER_VISIBLE},
+      // TODO(lazyboy): Consider creating VerifiedContents directly from
+      // |response| instead of reading the file again.
+      base::BindOnce(&WriteFileHelper, destination, base::Passed(&response)),
+      base::BindOnce(&ContentHashFetcherJob::OnVerifiedContentsWritten, this,
+                     size));
 }
 
 void ContentHashFetcherJob::OnVerifiedContentsWritten(size_t expected_size,
                                                       int write_result) {
   bool success =
-      (write_result >= 0 && static_cast<size_t>(write_result) == expected_size);
-  DoneFetchingVerifiedContents(success);
-}
-
-void ContentHashFetcherJob::DoneFetchingVerifiedContents(bool success) {
-  if (IsCancelled())
-    return;
+      write_result >= 0 && static_cast<size_t>(write_result) == expected_size;
 
   if (!success) {
-    DispatchCallback();
+    Failed();
     return;
   }
 
-  GetExtensionFileTaskRunner()->PostTask(
-      FROM_HERE, base::Bind(&ContentHashFetcherJob::MaybeCreateHashes, this));
+  base::PostTaskAndReplyWithResult(
+      GetExtensionFileTaskRunner().get(), FROM_HERE,
+      // TODO(lazyboy): Consider creating VerifiedContents directly from
+      // |response| instead of reading the file again.
+      base::BindOnce(
+          &ReadContentHashAfterVerifiedContentsWritten, extension_key_, force_,
+          base::BindRepeating(&ContentHashFetcherJob::IsCancelled, this)),
+      base::BindOnce(&ContentHashFetcherJob::ReadCompleteAfterWrite, this));
 }
 
-void ContentHashFetcherJob::MaybeCreateHashes() {
+void ContentHashFetcherJob::ReadCompleteAfterWrite(
+    std::unique_ptr<ContentHash> content_hash) {
   if (IsCancelled())
     return;
-  base::FilePath hashes_file =
-      file_util::GetComputedHashesPath(extension_path_);
 
-  if (!force_ && base::PathExists(hashes_file)) {
-    success_ = true;
+  if (content_hash->succeeded()) {
+    Succeeded(content_hash->hash_mismatch_unix_paths());
   } else {
-    if (force_)
-      base::DeleteFile(hashes_file, false /* recursive */);
-    success_ = CreateHashes(hashes_file);
+    Failed();
   }
-
-  content::BrowserThread::PostTask(
-      creation_thread_,
-      FROM_HERE,
-      base::Bind(&ContentHashFetcherJob::DispatchCallback, this));
 }
 
-bool ContentHashFetcherJob::CreateHashes(const base::FilePath& hashes_file) {
-  base::ElapsedTimer timer;
-  if (IsCancelled())
-    return false;
-  // Make sure the directory exists.
-  if (!base::CreateDirectoryAndGetError(hashes_file.DirName(), NULL))
-    return false;
+void ContentHashFetcherJob::Failed() {
+  success_ = false;
+  DispatchCallback();
+}
 
-  if (!verified_contents_.get()) {
-    base::FilePath verified_contents_path =
-        file_util::GetVerifiedContentsPath(extension_path_);
-    verified_contents_.reset(new VerifiedContents(key_.data, key_.size));
-    if (!verified_contents_->InitFrom(verified_contents_path)) {
-      verified_contents_.reset();
-      return false;
-    }
-  }
+void ContentHashFetcherJob::Succeeded(
+    const std::set<base::FilePath>& hash_mismatch_unix_paths) {
+  success_ = true;
 
-  base::FileEnumerator enumerator(extension_path_,
-                                  true, /* recursive */
-                                  base::FileEnumerator::FILES);
-  // First discover all the file paths and put them in a sorted set.
-  SortedFilePathSet paths;
-  for (;;) {
-    if (IsCancelled())
-      return false;
+  // TODO(lazyboy): Avoid this copy.
+  hash_mismatch_unix_paths_ = hash_mismatch_unix_paths;
 
-    base::FilePath full_path = enumerator.Next();
-    if (full_path.empty())
-      break;
-    paths.insert(full_path);
-  }
-
-  // Now iterate over all the paths in sorted order and compute the block hashes
-  // for each one.
-  ComputedHashes::Writer writer;
-  for (SortedFilePathSet::iterator i = paths.begin(); i != paths.end(); ++i) {
-    if (IsCancelled())
-      return false;
-    const base::FilePath& full_path = *i;
-    base::FilePath relative_unix_path;
-    extension_path_.AppendRelativePath(full_path, &relative_unix_path);
-    relative_unix_path = relative_unix_path.NormalizePathSeparatorsTo('/');
-
-    if (!verified_contents_->HasTreeHashRoot(relative_unix_path))
-      continue;
-
-    std::string contents;
-    if (!base::ReadFileToString(full_path, &contents)) {
-      LOG(ERROR) << "Could not read " << full_path.MaybeAsASCII();
-      continue;
-    }
-
-    // Iterate through taking the hash of each block of size (block_size_) of
-    // the file.
-    std::vector<std::string> hashes;
-    ComputedHashes::ComputeHashesForContent(contents, block_size_, &hashes);
-    std::string root =
-        ComputeTreeHashRoot(hashes, block_size_ / crypto::kSHA256Length);
-    if (!verified_contents_->TreeHashRootEquals(relative_unix_path, root)) {
-      VLOG(1) << "content mismatch for " << relative_unix_path.AsUTF8Unsafe();
-      hash_mismatch_unix_paths_.insert(relative_unix_path);
-      continue;
-    }
-
-    writer.AddHashes(relative_unix_path, block_size_, hashes);
-  }
-  bool result = writer.WriteToFile(hashes_file);
-  UMA_HISTOGRAM_TIMES("ExtensionContentHashFetcher.CreateHashesTime",
-                      timer.Elapsed());
-  return result;
+  DispatchCallback();
 }
 
 void ContentHashFetcherJob::DispatchCallback() {
@@ -497,11 +419,16 @@
 
   GURL url =
       delegate_->GetSignatureFetchUrl(extension->id(), extension->version());
-  ContentHashFetcherJob* job =
-      new ContentHashFetcherJob(context_getter_, delegate_->GetPublicKey(),
-                                extension->id(), extension->path(), url, force,
-                                base::Bind(&ContentHashFetcher::JobFinished,
-                                           weak_ptr_factory_.GetWeakPtr()));
+  ContentHashFetcherJob* job = new ContentHashFetcherJob(
+      context_getter_,
+      ContentHash::ExtensionKey(extension->id(), extension->path(),
+                                extension->version(),
+                                delegate_->GetPublicKey()),
+      url, force,
+      // TODO(lazyboy): Use BindOnce, ContentHashFetcherJob should respond at
+      // most once.
+      base::BindRepeating(&ContentHashFetcher::JobFinished,
+                          weak_ptr_factory_.GetWeakPtr()));
   jobs_.insert(std::make_pair(key, job));
   job->Start();
 }
diff --git a/extensions/browser/content_hash_reader.cc b/extensions/browser/content_hash_reader.cc
index b5e72a8..067ddb44 100644
--- a/extensions/browser/content_hash_reader.cc
+++ b/extensions/browser/content_hash_reader.cc
@@ -4,9 +4,7 @@
 
 #include "extensions/browser/content_hash_reader.h"
 
-#include "base/base64.h"
 #include "base/files/file_util.h"
-#include "base/json/json_reader.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/strings/string_util.h"
 #include "base/timer/elapsed_timer.h"
@@ -14,13 +12,8 @@
 #include "crypto/sha2.h"
 #include "extensions/browser/computed_hashes.h"
 #include "extensions/browser/content_hash_tree.h"
+#include "extensions/browser/content_verifier/content_hash.h"
 #include "extensions/browser/verified_contents.h"
-#include "extensions/common/extension.h"
-#include "extensions/common/file_util.h"
-
-using base::DictionaryValue;
-using base::ListValue;
-using base::Value;
 
 namespace extensions {
 
@@ -42,30 +35,18 @@
   base::ElapsedTimer timer;
   DCHECK_EQ(status_, NOT_INITIALIZED);
   status_ = FAILURE;
-  base::FilePath verified_contents_path =
-      file_util::GetVerifiedContentsPath(extension_root_);
-  if (!base::PathExists(verified_contents_path))
-    return false;
 
-  VerifiedContents verified_contents(key_.data, key_.size);
-  if (!verified_contents.InitFrom(verified_contents_path) ||
-      !verified_contents.valid_signature() ||
-      verified_contents.version() != extension_version_ ||
-      verified_contents.extension_id() != extension_id_) {
-    return false;
-  }
+  std::unique_ptr<ContentHash> content_hash =
+      ContentHash::Create(ContentHash::ExtensionKey(
+          extension_id_, extension_root_, extension_version_, key_));
 
-  base::FilePath computed_hashes_path =
-      file_util::GetComputedHashesPath(extension_root_);
-  if (!base::PathExists(computed_hashes_path))
-    return false;
-
-  ComputedHashes::Reader reader;
-  if (!reader.InitFromFile(computed_hashes_path))
+  if (!content_hash->succeeded())
     return false;
 
   has_content_hashes_ = true;
 
+  const VerifiedContents& verified_contents = content_hash->verified_contents();
+
   // Extensions sometimes request resources that do not have an entry in
   // verified_contents.json. This can happen when an extension sends an XHR to a
   // resource.
@@ -82,9 +63,11 @@
     return false;
   }
 
+  const ComputedHashes::Reader& reader = content_hash->computed_hashes();
   if (!reader.GetHashes(relative_path_, &block_size_, &hashes_) ||
-      block_size_ % crypto::kSHA256Length != 0)
+      block_size_ % crypto::kSHA256Length != 0) {
     return false;
+  }
 
   std::string root =
       ComputeTreeHashRoot(hashes_, block_size_ / crypto::kSHA256Length);
diff --git a/extensions/browser/content_verifier/content_hash.cc b/extensions/browser/content_verifier/content_hash.cc
new file mode 100644
index 0000000..9e7b3c0f
--- /dev/null
+++ b/extensions/browser/content_verifier/content_hash.cc
@@ -0,0 +1,206 @@
+// 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 "extensions/browser/content_verifier/content_hash.h"
+
+#include "base/files/file_enumerator.h"
+#include "base/files/file_util.h"
+#include "base/memory/ptr_util.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/threading/thread_restrictions.h"
+#include "base/timer/elapsed_timer.h"
+#include "crypto/sha2.h"
+#include "extensions/browser/content_hash_tree.h"
+#include "extensions/common/file_util.h"
+
+namespace {
+
+using SortedFilePathSet = std::set<base::FilePath>;
+
+}  // namespace
+
+namespace extensions {
+
+ContentHash::ExtensionKey::ExtensionKey(const ExtensionId& extension_id,
+                                        const base::FilePath& extension_root,
+                                        const base::Version& extension_version,
+                                        const ContentVerifierKey& verifier_key)
+    : extension_id(extension_id),
+      extension_root(extension_root),
+      extension_version(extension_version),
+      verifier_key(verifier_key) {}
+
+ContentHash::ExtensionKey::ExtensionKey(
+    const ContentHash::ExtensionKey& other) = default;
+
+ContentHash::ExtensionKey& ContentHash::ExtensionKey::operator=(
+    const ContentHash::ExtensionKey& other) = default;
+
+// static
+std::unique_ptr<ContentHash> ContentHash::Create(const ExtensionKey& key) {
+  return ContentHash::CreateImpl(key, 0 /* mode */,
+                                 false /* create_computed_hashes_file */,
+                                 IsCancelledCallback());
+}
+
+// static
+std::unique_ptr<ContentHash> ContentHash::Create(
+    const ExtensionKey& key,
+    int mode,
+    const IsCancelledCallback& is_cancelled) {
+  return ContentHash::CreateImpl(
+      key, mode, true /* create_computed_hashes_file */, is_cancelled);
+}
+
+ContentHash::~ContentHash() = default;
+
+const VerifiedContents& ContentHash::verified_contents() const {
+  DCHECK(status_ >= Status::kHasVerifiedContents && verified_contents_);
+  return *verified_contents_;
+}
+
+const ComputedHashes::Reader& ContentHash::computed_hashes() const {
+  DCHECK(status_ == Status::kSucceeded && computed_hashes_);
+  return *computed_hashes_;
+}
+
+ContentHash::ContentHash(
+    const ExtensionKey& key,
+    std::unique_ptr<VerifiedContents> verified_contents,
+    std::unique_ptr<ComputedHashes::Reader> computed_hashes)
+    : key_(key),
+      verified_contents_(std::move(verified_contents)),
+      computed_hashes_(std::move(computed_hashes)) {
+  if (!verified_contents_)
+    status_ = Status::kInvalid;
+  else if (!computed_hashes_)
+    status_ = Status::kHasVerifiedContents;
+  else
+    status_ = Status::kSucceeded;
+}
+
+// static
+std::unique_ptr<ContentHash> ContentHash::CreateImpl(
+    const ExtensionKey& key,
+    int mode,
+    bool create_computed_hashes_file,
+    const IsCancelledCallback& is_cancelled) {
+  base::AssertBlockingAllowed();
+
+  // verified_contents.json:
+  base::FilePath verified_contents_path =
+      file_util::GetVerifiedContentsPath(key.extension_root);
+  if (!base::PathExists(verified_contents_path)) {
+    // kInvalid.
+    return base::WrapUnique(new ContentHash(key, nullptr, nullptr));
+  }
+
+  auto verified_contents = std::make_unique<VerifiedContents>(
+      key.verifier_key.data, key.verifier_key.size);
+  if (!verified_contents->InitFrom(verified_contents_path)) {
+    if (mode & Mode::kDeleteInvalidVerifiedContents) {
+      if (!base::DeleteFile(verified_contents_path, false))
+        LOG(WARNING) << "Failed to delete " << verified_contents_path.value();
+    }
+    // kInvalid.
+    return base::WrapUnique(new ContentHash(key, nullptr, nullptr));
+  }
+
+  // computed_hashes.json: create if necessary.
+  base::FilePath computed_hashes_path =
+      file_util::GetComputedHashesPath(key.extension_root);
+
+  std::unique_ptr<ContentHash> hash = base::WrapUnique(
+      new ContentHash(key, std::move(verified_contents), nullptr));
+  if (create_computed_hashes_file) {
+    // If force recreate wasn't requested, existence of computed_hashes.json is
+    // enough, otherwise create computed_hashes.json.
+    bool need_to_create =
+        (mode & Mode::kForceRecreateExistingComputedHashesFile) != 0 ||
+        !base::PathExists(computed_hashes_path);
+    if (need_to_create)
+      hash->CreateHashes(computed_hashes_path, is_cancelled);
+  }
+
+  // computed_hashes.json: read.
+  if (!base::PathExists(computed_hashes_path))
+    return hash;
+
+  auto computed_hashes = std::make_unique<ComputedHashes::Reader>();
+  if (!computed_hashes->InitFromFile(computed_hashes_path))
+    return hash;
+
+  hash->status_ = Status::kSucceeded;
+  hash->computed_hashes_ = std::move(computed_hashes);
+
+  return hash;
+}
+
+bool ContentHash::CreateHashes(const base::FilePath& hashes_file,
+                               const IsCancelledCallback& is_cancelled) {
+  base::ElapsedTimer timer;
+  // Make sure the directory exists.
+  if (!base::CreateDirectoryAndGetError(hashes_file.DirName(), nullptr))
+    return false;
+
+  base::FileEnumerator enumerator(key_.extension_root, true, /* recursive */
+                                  base::FileEnumerator::FILES);
+  // First discover all the file paths and put them in a sorted set.
+  SortedFilePathSet paths;
+  for (;;) {
+    if (is_cancelled && is_cancelled.Run())
+      return false;
+
+    base::FilePath full_path = enumerator.Next();
+    if (full_path.empty())
+      break;
+    paths.insert(full_path);
+  }
+
+  // Now iterate over all the paths in sorted order and compute the block hashes
+  // for each one.
+  ComputedHashes::Writer writer;
+  for (SortedFilePathSet::iterator i = paths.begin(); i != paths.end(); ++i) {
+    if (is_cancelled && is_cancelled.Run())
+      return false;
+
+    const base::FilePath& full_path = *i;
+    base::FilePath relative_unix_path;
+    key_.extension_root.AppendRelativePath(full_path, &relative_unix_path);
+    relative_unix_path = relative_unix_path.NormalizePathSeparatorsTo('/');
+
+    if (!verified_contents_->HasTreeHashRoot(relative_unix_path))
+      continue;
+
+    std::string contents;
+    if (!base::ReadFileToString(full_path, &contents)) {
+      LOG(ERROR) << "Could not read " << full_path.MaybeAsASCII();
+      continue;
+    }
+
+    // Iterate through taking the hash of each block of size (block_size_) of
+    // the file.
+    std::vector<std::string> hashes;
+    ComputedHashes::ComputeHashesForContent(contents, block_size_, &hashes);
+    std::string root =
+        ComputeTreeHashRoot(hashes, block_size_ / crypto::kSHA256Length);
+    if (!verified_contents_->TreeHashRootEquals(relative_unix_path, root)) {
+      VLOG(1) << "content mismatch for " << relative_unix_path.AsUTF8Unsafe();
+      hash_mismatch_unix_paths_.insert(relative_unix_path);
+      continue;
+    }
+
+    writer.AddHashes(relative_unix_path, block_size_, hashes);
+  }
+  bool result = writer.WriteToFile(hashes_file);
+  UMA_HISTOGRAM_TIMES("ExtensionContentHashFetcher.CreateHashesTime",
+                      timer.Elapsed());
+
+  if (result)
+    status_ = Status::kSucceeded;
+
+  return result;
+}
+
+}  // namespace extensions
diff --git a/extensions/browser/content_verifier/content_hash.h b/extensions/browser/content_verifier/content_hash.h
new file mode 100644
index 0000000..a0fad959
--- /dev/null
+++ b/extensions/browser/content_verifier/content_hash.h
@@ -0,0 +1,147 @@
+// 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 EXTENSIONS_BROWSER_CONTENT_VERIFIER_CONTENT_HASH_H_
+#define EXTENSIONS_BROWSER_CONTENT_VERIFIER_CONTENT_HASH_H_
+
+#include <set>
+
+#include "base/files/file_path.h"
+#include "base/version.h"
+#include "extensions/browser/computed_hashes.h"
+#include "extensions/browser/content_verifier_delegate.h"
+#include "extensions/browser/verified_contents.h"
+#include "extensions/common/extension_id.h"
+
+namespace extensions {
+
+// Represents content verification hashes for an extension.
+//
+// Instances can be created using Create() factory methods on sequences with
+// blocking IO access. If hash retrieval succeeds then ContentHash::succeeded()
+// will return true and
+// a. ContentHash::verified_contents() will return structured representation of
+//    verified_contents.json
+// b. ContentHash::computed_hashes() will return structured representation of
+//    computed_hashes.json.
+//
+// Additionally if computed_hashes.json was required to be written to disk and
+// it was successful, ContentHash::hash_mismatch_unix_paths() will return all
+// FilePaths from the extension directory that had content verification
+// mismatch.
+class ContentHash {
+ public:
+  // Key to identify an extension.
+  struct ExtensionKey {
+    ExtensionId extension_id;
+    base::FilePath extension_root;
+    base::Version extension_version;
+    // The key used to validate verified_contents.json.
+    ContentVerifierKey verifier_key;
+
+    ExtensionKey(const ExtensionId& extension_id,
+                 const base::FilePath& extension_root,
+                 const base::Version& extension_version,
+                 const ContentVerifierKey& verifier_key);
+
+    ExtensionKey(const ExtensionKey& other);
+    ExtensionKey& operator=(const ExtensionKey& other);
+  };
+
+  // Specifiable modes for ContentHash instantiation.
+  enum Mode {
+    // Deletes verified_contents.json if the file on disk is invalid.
+    kDeleteInvalidVerifiedContents = 1 << 0,
+
+    // Always creates computed_hashes.json (as opposed to only when the file is
+    // non-existent).
+    kForceRecreateExistingComputedHashesFile = 1 << 1,
+  };
+
+  using IsCancelledCallback = base::RepeatingCallback<bool(void)>;
+
+  // Factories:
+  // These will never return nullptr, but verified_contents or computed_hashes
+  // may be empty if something fails.
+  // Reads existing hashes from disk.
+  static std::unique_ptr<ContentHash> Create(const ExtensionKey& key);
+  // Reads existing hashes from disk, with specifying flags from |Mode|.
+  static std::unique_ptr<ContentHash> Create(
+      const ExtensionKey& key,
+      int mode,
+      const IsCancelledCallback& is_cancelled);
+
+  ~ContentHash();
+
+  const VerifiedContents& verified_contents() const;
+  const ComputedHashes::Reader& computed_hashes() const;
+
+  bool has_verified_contents() const {
+    return status_ >= Status::kHasVerifiedContents;
+  }
+  bool succeeded() const { return status_ >= Status::kSucceeded; }
+
+  // If ContentHash creation writes computed_hashes.json, then this returns the
+  // FilePaths whose content hash didn't match expected hashes.
+  const std::set<base::FilePath>& hash_mismatch_unix_paths() {
+    return hash_mismatch_unix_paths_;
+  }
+
+ private:
+  enum class Status {
+    // Retrieving hashes failed.
+    kInvalid,
+    // Retrieved valid verified_contents.json, but there was no
+    // computed_hashes.json.
+    kHasVerifiedContents,
+    // Both verified_contents.json and computed_hashes.json were read
+    // correctly.
+    kSucceeded,
+  };
+
+  ContentHash(const ExtensionKey& key,
+              std::unique_ptr<VerifiedContents> verified_contents,
+              std::unique_ptr<ComputedHashes::Reader> computed_hashes);
+
+  static std::unique_ptr<ContentHash> CreateImpl(
+      const ExtensionKey& key,
+      int mode,
+      bool create_computed_hashes_file,
+      const IsCancelledCallback& is_cancelled);
+
+  // Computes hashes for all files in |key_.extension_root|, and uses
+  // a ComputedHashes::Writer to write that information into |hashes_file|.
+  // Returns true on success.
+  // The verified contents file from the webstore only contains the treehash
+  // root hash, but for performance we want to cache the individual block level
+  // hashes. This function will create that cache with block-level hashes for
+  // each file in the extension if needed (the treehash root hash for each of
+  // these should equal what is in the verified contents file from the
+  // webstore).
+  bool CreateHashes(const base::FilePath& hashes_file,
+                    const IsCancelledCallback& is_cancelled);
+
+  ExtensionKey key_;
+
+  Status status_;
+
+  // TODO(lazyboy): Avoid dynamic allocations here, |this| already supports
+  // move.
+  std::unique_ptr<VerifiedContents> verified_contents_;
+  std::unique_ptr<ComputedHashes::Reader> computed_hashes_;
+
+  // Paths that were found to have a mismatching hash.
+  std::set<base::FilePath> hash_mismatch_unix_paths_;
+
+  // The block size to use for hashing.
+  // TODO(asargent) - use the value from verified_contents.json for each
+  // file, instead of using a constant.
+  int block_size_ = 4096;
+
+  DISALLOW_COPY_AND_ASSIGN(ContentHash);
+};
+
+}  // namespace extensions
+
+#endif  // EXTENSIONS_BROWSER_CONTENT_VERIFIER_CONTENT_HASH_H_
diff --git a/extensions/browser/extension_prefs.h b/extensions/browser/extension_prefs.h
index 0f92103..c129214c 100644
--- a/extensions/browser/extension_prefs.h
+++ b/extensions/browser/extension_prefs.h
@@ -21,7 +21,6 @@
 #include "components/sync/model/string_ordinal.h"
 #include "extensions/browser/blacklist_state.h"
 #include "extensions/browser/disable_reason.h"
-#include "extensions/browser/extension_scoped_prefs.h"
 #include "extensions/browser/install_flag.h"
 #include "extensions/common/constants.h"
 #include "extensions/common/extension.h"
@@ -70,7 +69,7 @@
 //       preference. Extension-controlled preferences are stored in
 //       PrefValueStore::extension_prefs(), which this class populates and
 //       maintains as the underlying extensions change.
-class ExtensionPrefs : public ExtensionScopedPrefs, public KeyedService {
+class ExtensionPrefs : public KeyedService {
  public:
   using ExtensionsInfo = std::vector<std::unique_ptr<ExtensionInfo>>;
 
@@ -233,35 +232,33 @@
   // Populates |out| with the ids of all installed extensions.
   void GetExtensions(ExtensionIdList* out) const;
 
-  // ExtensionScopedPrefs methods:
   void UpdateExtensionPref(const std::string& id,
                            base::StringPiece key,
-                           std::unique_ptr<base::Value> value) override;
+                           std::unique_ptr<base::Value> value);
 
-  void DeleteExtensionPrefs(const std::string& id) override;
+  void DeleteExtensionPrefs(const std::string& id);
 
   bool ReadPrefAsBoolean(const std::string& extension_id,
                          base::StringPiece pref_key,
-                         bool* out_value) const override;
+                         bool* out_value) const;
 
   bool ReadPrefAsInteger(const std::string& extension_id,
                          base::StringPiece pref_key,
-                         int* out_value) const override;
+                         int* out_value) const;
 
   bool ReadPrefAsString(const std::string& extension_id,
                         base::StringPiece pref_key,
-                        std::string* out_value) const override;
+                        std::string* out_value) const;
 
   bool ReadPrefAsList(const std::string& extension_id,
                       base::StringPiece pref_key,
-                      const base::ListValue** out_value) const override;
+                      const base::ListValue** out_value) const;
 
-  bool ReadPrefAsDictionary(
-      const std::string& extension_id,
-      base::StringPiece pref_key,
-      const base::DictionaryValue** out_value) const override;
+  bool ReadPrefAsDictionary(const std::string& extension_id,
+                            base::StringPiece pref_key,
+                            const base::DictionaryValue** out_value) const;
 
-  bool HasPrefForExtension(const std::string& extension_id) const override;
+  bool HasPrefForExtension(const std::string& extension_id) const;
 
   // Did the extension ask to escalate its permission during an upgrade?
   bool DidExtensionEscalatePermissions(const std::string& id) const;
diff --git a/extensions/browser/extension_scoped_prefs.h b/extensions/browser/extension_scoped_prefs.h
deleted file mode 100644
index 2e988d8..0000000
--- a/extensions/browser/extension_scoped_prefs.h
+++ /dev/null
@@ -1,67 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef EXTENSIONS_BROWSER_EXTENSION_SCOPED_PREFS_H_
-#define EXTENSIONS_BROWSER_EXTENSION_SCOPED_PREFS_H_
-
-#include <memory>
-#include <string>
-
-#include "base/strings/string_piece_forward.h"
-
-namespace base {
-class DictionaryValue;
-class ListValue;
-class Value;
-}
-
-namespace extensions {
-
-class ExtensionScopedPrefs {
- public:
-  ExtensionScopedPrefs() {}
-  ~ExtensionScopedPrefs() {}
-
-  // Sets the pref |key| for extension |id| to |value|.
-  virtual void UpdateExtensionPref(const std::string& id,
-                                   base::StringPiece key,
-                                   std::unique_ptr<base::Value> value) = 0;
-
-  // Deletes the pref dictionary for extension |id|.
-  virtual void DeleteExtensionPrefs(const std::string& id) = 0;
-
-  // Reads a boolean pref |pref_key| from extension with id |extension_id|.
-  virtual bool ReadPrefAsBoolean(const std::string& extension_id,
-                                 base::StringPiece pref_key,
-                                 bool* out_value) const = 0;
-
-  // Reads an integer pref |pref_key| from extension with id |extension_id|.
-  virtual bool ReadPrefAsInteger(const std::string& extension_id,
-                                 base::StringPiece pref_key,
-                                 int* out_value) const = 0;
-
-  // Reads a string pref |pref_key| from extension with id |extension_id|.
-  virtual bool ReadPrefAsString(const std::string& extension_id,
-                                base::StringPiece pref_key,
-                                std::string* out_value) const = 0;
-
-  // Reads a list pref |pref_key| from extension with id |extension_id|.
-  virtual bool ReadPrefAsList(const std::string& extension_id,
-                              base::StringPiece pref_key,
-                              const base::ListValue** out_value) const = 0;
-
-  // Reads a dictionary pref |pref_key| from extension with id |extension_id|.
-  virtual bool ReadPrefAsDictionary(
-      const std::string& extension_id,
-      base::StringPiece pref_key,
-      const base::DictionaryValue** out_value) const = 0;
-
-  // Returns true if the prefs contain an entry for an extension with id
-  // |extension_id|.
-  virtual bool HasPrefForExtension(const std::string& extension_id) const = 0;
-};
-
-}  // namespace extensions
-
-#endif  // EXTENSIONS_BROWSER_EXTENSION_SCOPED_PREFS_H_
diff --git a/extensions/common/file_util_unittest.cc b/extensions/common/file_util_unittest.cc
index be157eb..55bbe9a9e 100644
--- a/extensions/common/file_util_unittest.cc
+++ b/extensions/common/file_util_unittest.cc
@@ -298,7 +298,7 @@
       install_dir, Manifest::UNPACKED, Extension::NO_FLAGS, &error));
   ASSERT_TRUE(extension.get() == NULL);
   ASSERT_FALSE(error.empty());
-  ASSERT_STREQ("Manifest file is missing or unreadable.", error.c_str());
+  ASSERT_EQ(manifest_errors::kManifestUnreadable, error);
 }
 
 TEST_F(FileUtilTest, LoadExtensionGivesHelpfullErrorOnBadManifest) {
@@ -312,10 +312,9 @@
       install_dir, Manifest::UNPACKED, Extension::NO_FLAGS, &error));
   ASSERT_TRUE(extension.get() == NULL);
   ASSERT_FALSE(error.empty());
-  ASSERT_STREQ(
-      "Manifest is not valid JSON.  "
-      "Line: 2, column: 16, Syntax error.",
-      error.c_str());
+  ASSERT_EQ(manifest_errors::kManifestParseError +
+                std::string("  Line: 2, column: 16, Syntax error."),
+            error);
 }
 
 TEST_F(FileUtilTest, ValidateThemeUTF8) {
diff --git a/extensions/common/manifest_constants.cc b/extensions/common/manifest_constants.cc
index 0d33492f..23d5236 100644
--- a/extensions/common/manifest_constants.cc
+++ b/extensions/common/manifest_constants.cc
@@ -519,8 +519,7 @@
     "Invalid 'url' for linked app icon. Must be a string that is a valid URL";
 const char kInvalidLinkedAppIcons[] =
     "Invalid 'app.linked_icons'. Must be an array";
-const char kInvalidManifest[] =
-    "Manifest file is invalid.";
+const char kInvalidManifest[] = "Manifest file is invalid";
 const char kInvalidManifestVersion[] =
     "Invalid value for 'manifest_version'. Must be an integer greater than "
     "zero.";
@@ -715,8 +714,7 @@
     "Default locale was specified, but _locales subtree is missing.";
 const char kManifestParseError[] =
     "Manifest is not valid JSON.";
-const char kManifestUnreadable[] =
-    "Manifest file is missing or unreadable.";
+const char kManifestUnreadable[] = "Manifest file is missing or unreadable";
 const char kMissingFile[] =
     "At least one js or css file is required for 'content_scripts[*]'.";
 const char kMultipleOverrides[] =
diff --git a/extensions/renderer/bindings/api_binding.cc b/extensions/renderer/bindings/api_binding.cc
index a9933f3..71c5386a 100644
--- a/extensions/renderer/bindings/api_binding.cc
+++ b/extensions/renderer/bindings/api_binding.cc
@@ -65,7 +65,7 @@
 void RunAPIBindingHandlerCallback(
     const v8::FunctionCallbackInfo<v8::Value>& info) {
   gin::Arguments args(info);
-  if (!binding::IsContextValid(args.isolate()->GetCurrentContext()))
+  if (!binding::IsContextValidOrThrowError(args.isolate()->GetCurrentContext()))
     return;
 
   v8::Local<v8::External> external;
@@ -508,7 +508,7 @@
   v8::Isolate* isolate = info.GetIsolate();
   v8::HandleScope handle_scope(isolate);
   v8::Local<v8::Context> context = info.Holder()->CreationContext();
-  if (!binding::IsContextValid(context))
+  if (!binding::IsContextValidOrThrowError(context))
     return;
 
   CHECK(info.Data()->IsExternal());
diff --git a/extensions/renderer/bindings/api_binding_unittest.cc b/extensions/renderer/bindings/api_binding_unittest.cc
index a091816..287c6c1 100644
--- a/extensions/renderer/bindings/api_binding_unittest.cc
+++ b/extensions/renderer/bindings/api_binding_unittest.cc
@@ -717,7 +717,10 @@
       FunctionFromString(context, "(function(obj) { obj.oneString('foo'); })");
   v8::Local<v8::Value> argv[] = {binding_object};
   DisposeContext(context);
-  RunFunction(func, context, arraysize(argv), argv);
+
+  RunFunctionAndExpectError(func, context, arraysize(argv), argv,
+                            "Uncaught Error: Extension context invalidated.");
+
   EXPECT_FALSE(HandlerWasInvoked());
   // This test passes if this does not crash, even under AddressSanitizer
   // builds.
@@ -736,7 +739,10 @@
       FunctionFromString(context, "(function(obj) { obj.oneString('foo'); })");
   v8::Local<v8::Value> argv[] = {binding_object};
   binding::InvalidateContext(context);
-  RunFunction(func, context, arraysize(argv), argv);
+
+  RunFunctionAndExpectError(func, context, arraysize(argv), argv,
+                            "Uncaught Error: Extension context invalidated.");
+
   EXPECT_FALSE(HandlerWasInvoked());
   // This test passes if this does not crash, even under AddressSanitizer
   // builds.
@@ -1574,4 +1580,22 @@
                                                 "calledCustomCallback"));
 }
 
+TEST_F(APIBindingUnittest, AccessAPIMethodsAndEventsAfterInvalidation) {
+  SetEvents(R"([{"name": "onFoo"}])");
+  InitializeBinding();
+
+  v8::HandleScope handle_scope(isolate());
+  v8::Local<v8::Context> context = MainContext();
+
+  v8::Local<v8::Object> binding_object = binding()->CreateInstance(context);
+
+  v8::Local<v8::Function> function = FunctionFromString(
+      context, "(function(obj) { obj.onFoo.addListener(function() {}); })");
+  binding::InvalidateContext(context);
+
+  v8::Local<v8::Value> argv[] = {binding_object};
+  RunFunctionAndExpectError(function, context, arraysize(argv), argv,
+                            "Uncaught Error: Extension context invalidated.");
+}
+
 }  // namespace extensions
diff --git a/extensions/renderer/bindings/api_binding_util.cc b/extensions/renderer/bindings/api_binding_util.cc
index a342bce..f51baf95f 100644
--- a/extensions/renderer/bindings/api_binding_util.cc
+++ b/extensions/renderer/bindings/api_binding_util.cc
@@ -7,6 +7,7 @@
 #include "base/logging.h"
 #include "base/supports_user_data.h"
 #include "build/build_config.h"
+#include "gin/converter.h"
 #include "gin/per_context_data.h"
 
 namespace extensions {
@@ -24,6 +25,15 @@
          per_context_data->GetUserData(kInvalidatedContextFlagKey) == nullptr;
 }
 
+bool IsContextValidOrThrowError(v8::Local<v8::Context> context) {
+  if (IsContextValid(context))
+    return true;
+  v8::Isolate* isolate = context->GetIsolate();
+  isolate->ThrowException(v8::Exception::Error(
+      gin::StringToV8(isolate, "Extension context invalidated.")));
+  return false;
+}
+
 void InvalidateContext(v8::Local<v8::Context> context) {
   gin::PerContextData* per_context_data = gin::PerContextData::From(context);
   if (!per_context_data)
diff --git a/extensions/renderer/bindings/api_binding_util.h b/extensions/renderer/bindings/api_binding_util.h
index a55f91a..e9f8d01 100644
--- a/extensions/renderer/bindings/api_binding_util.h
+++ b/extensions/renderer/bindings/api_binding_util.h
@@ -21,6 +21,9 @@
 // points. See https://crbug.com/772071.
 bool IsContextValid(v8::Local<v8::Context> context);
 
+// Same as above, but throws an exception in the |context| if it is invalid.
+bool IsContextValidOrThrowError(v8::Local<v8::Context> context);
+
 // Marks the given |context| as invalid.
 void InvalidateContext(v8::Local<v8::Context> context);
 
diff --git a/extensions/renderer/chrome_setting.cc b/extensions/renderer/chrome_setting.cc
index 3c3094a..7c309b2 100644
--- a/extensions/renderer/chrome_setting.cc
+++ b/extensions/renderer/chrome_setting.cc
@@ -7,6 +7,7 @@
 #include "base/memory/ptr_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/values.h"
+#include "extensions/renderer/bindings/api_binding_util.h"
 #include "extensions/renderer/bindings/api_event_handler.h"
 #include "extensions/renderer/bindings/api_request_handler.h"
 #include "extensions/renderer/bindings/api_signature.h"
@@ -84,6 +85,9 @@
   v8::HandleScope handle_scope(isolate);
   v8::Local<v8::Context> context = arguments->GetHolderCreationContext();
 
+  if (!binding::IsContextValidOrThrowError(context))
+    return;
+
   v8::Local<v8::Value> value = arguments->PeekNext();
   // The set schema included in the Schema object is generic, since it varies
   // per-setting. However, this is only ever for a single setting, so we can
@@ -107,6 +111,10 @@
   v8::Isolate* isolate = arguments->isolate();
   v8::Local<v8::Context> context = arguments->GetHolderCreationContext();
   v8::Local<v8::Object> wrapper = GetWrapper(isolate).ToLocalChecked();
+
+  if (!binding::IsContextValidOrThrowError(context))
+    return v8::Undefined(isolate);
+
   v8::Local<v8::Private> key = v8::Private::ForApi(
       isolate, gin::StringToSymbol(isolate, "onChangeEvent"));
   v8::Local<v8::Value> event;
@@ -139,6 +147,9 @@
   v8::HandleScope handle_scope(isolate);
   v8::Local<v8::Context> context = arguments->GetHolderCreationContext();
 
+  if (!binding::IsContextValidOrThrowError(context))
+    return;
+
   std::vector<v8::Local<v8::Value>> argument_list = arguments->GetAll();
 
   std::string full_name = "types.ChromeSetting." + method_name;
diff --git a/extensions/renderer/content_setting.cc b/extensions/renderer/content_setting.cc
index ffce888..0b4a6c38 100644
--- a/extensions/renderer/content_setting.cc
+++ b/extensions/renderer/content_setting.cc
@@ -9,6 +9,7 @@
 #include "base/values.h"
 #include "content/public/common/console_message_level.h"
 #include "extensions/renderer/bindings/api_binding_types.h"
+#include "extensions/renderer/bindings/api_binding_util.h"
 #include "extensions/renderer/bindings/api_request_handler.h"
 #include "extensions/renderer/bindings/api_signature.h"
 #include "extensions/renderer/bindings/api_type_reference_map.h"
@@ -130,6 +131,9 @@
   v8::HandleScope handle_scope(isolate);
   v8::Local<v8::Context> context = arguments->GetHolderCreationContext();
 
+  if (!binding::IsContextValidOrThrowError(context))
+    return;
+
   std::vector<v8::Local<v8::Value>> argument_list = arguments->GetAll();
 
   std::string full_name = "contentSettings.ContentSetting." + method_name;
diff --git a/extensions/renderer/easy_unlock_proximity_required_stub.cc b/extensions/renderer/easy_unlock_proximity_required_stub.cc
index 89cb44fc8..8d9c8f70 100644
--- a/extensions/renderer/easy_unlock_proximity_required_stub.cc
+++ b/extensions/renderer/easy_unlock_proximity_required_stub.cc
@@ -4,6 +4,7 @@
 
 #include "extensions/renderer/easy_unlock_proximity_required_stub.h"
 
+#include "extensions/renderer/bindings/api_binding_util.h"
 #include "extensions/renderer/bindings/api_event_handler.h"
 #include "gin/arguments.h"
 #include "gin/handle.h"
@@ -46,6 +47,10 @@
   v8::Isolate* isolate = arguments->isolate();
   v8::Local<v8::Context> context = arguments->GetHolderCreationContext();
   v8::Local<v8::Object> wrapper = GetWrapper(isolate).ToLocalChecked();
+
+  if (!binding::IsContextValidOrThrowError(context))
+    return v8::Undefined(isolate);
+
   v8::Local<v8::Private> key = v8::Private::ForApi(
       isolate, gin::StringToSymbol(isolate, "onChangeEvent"));
   v8::Local<v8::Value> event;
diff --git a/extensions/renderer/storage_area.cc b/extensions/renderer/storage_area.cc
index c3be8eb2..347f7b9c 100644
--- a/extensions/renderer/storage_area.cc
+++ b/extensions/renderer/storage_area.cc
@@ -195,8 +195,7 @@
 
   // The context may have been invalidated, as in the case where this could be
   // a reference to an object from a removed frame.
-  // TODO(devlin): Should we throw an error here?
-  if (!binding::IsContextValid(context))
+  if (!binding::IsContextValidOrThrowError(context))
     return;
 
   std::string full_method_name = "storage." + method_name;
diff --git a/extensions/renderer/storage_area_unittest.cc b/extensions/renderer/storage_area_unittest.cc
index d333ec8..802dc20 100644
--- a/extensions/renderer/storage_area_unittest.cc
+++ b/extensions/renderer/storage_area_unittest.cc
@@ -43,7 +43,8 @@
   DisposeContext(context);
 
   EXPECT_FALSE(binding::IsContextValid(context));
-  RunFunction(run_storage_get, context, arraysize(args), args);
+  RunFunctionAndExpectError(run_storage_get, context, arraysize(args), args,
+                            "Uncaught Error: Extension context invalidated.");
 }
 
 }  // namespace extensions
diff --git a/extensions/strings/extensions_strings.grd b/extensions/strings/extensions_strings.grd
index 57ccd769..44b64eb 100644
--- a/extensions/strings/extensions_strings.grd
+++ b/extensions/strings/extensions_strings.grd
@@ -164,10 +164,10 @@
         Localization used, but default_locale wasn't specified in the manifest.
       </message>
       <message name="IDS_EXTENSION_MANIFEST_UNREADABLE" desc="">
-        Manifest file is missing or unreadable.
+        Manifest file is missing or unreadable
       </message>
       <message name="IDS_EXTENSION_MANIFEST_INVALID" desc="">
-        Manifest file is invalid.
+        Manifest file is invalid
       </message>
       <message name="IDS_EXTENSION_PACKAGE_DIRECTORY_ERROR" desc="Message for when an error occurs while trying to create the temporary directory needed to unzip a packaged extension or app.">
         Could not create directory for unzipping: '<ph name="DIRECTORY_PATH">$1<ex>profile/Extensions/CRX_INSTALL</ex></ph>'
diff --git a/google_apis/gcm/BUILD.gn b/google_apis/gcm/BUILD.gn
index efe4098..298b5de 100644
--- a/google_apis/gcm/BUILD.gn
+++ b/google_apis/gcm/BUILD.gn
@@ -106,6 +106,7 @@
   deps = [
     "//base",
     "//net",
+    "//net:test_support",
     "//testing/gtest",
   ]
 }
diff --git a/google_apis/gcm/base/socket_stream.cc b/google_apis/gcm/base/socket_stream.cc
index 45af7579..776813b 100644
--- a/google_apis/gcm/base/socket_stream.cc
+++ b/google_apis/gcm/base/socket_stream.cc
@@ -212,13 +212,16 @@
     callback.Run();
 }
 
-SocketOutputStream::SocketOutputStream(net::StreamSocket* socket)
+SocketOutputStream::SocketOutputStream(
+    net::StreamSocket* socket,
+    const net::NetworkTrafficAnnotationTag& traffic_annotation)
     : socket_(socket),
       io_buffer_(new net::IOBuffer(kDefaultBufferSize)),
-      write_buffer_(new net::DrainableIOBuffer(io_buffer_.get(),
-                                               kDefaultBufferSize)),
+      write_buffer_(
+          new net::DrainableIOBuffer(io_buffer_.get(), kDefaultBufferSize)),
       next_pos_(0),
       last_error_(net::OK),
+      traffic_annotation_(traffic_annotation),
       weak_ptr_factory_(this) {
   DCHECK(socket->IsConnected());
 }
@@ -264,11 +267,10 @@
 
   DVLOG(1) << "Flushing " << next_pos_ << " bytes into socket.";
   int result =
-      socket_->Write(write_buffer_.get(),
-                     next_pos_,
+      socket_->Write(write_buffer_.get(), next_pos_,
                      base::Bind(&SocketOutputStream::FlushCompletionCallback,
-                                weak_ptr_factory_.GetWeakPtr(),
-                                callback));
+                                weak_ptr_factory_.GetWeakPtr(), callback),
+                     traffic_annotation_);
   DVLOG(1) << "Write returned " << result;
   if (result == net::ERR_IO_PENDING) {
     last_error_ = net::ERR_IO_PENDING;
diff --git a/google_apis/gcm/base/socket_stream.h b/google_apis/gcm/base/socket_stream.h
index e9bdaa71..2b85088 100644
--- a/google_apis/gcm/base/socket_stream.h
+++ b/google_apis/gcm/base/socket_stream.h
@@ -18,6 +18,7 @@
 #include "google/protobuf/io/zero_copy_stream.h"
 #include "google_apis/gcm/base/gcm_export.h"
 #include "net/base/net_errors.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
 
 namespace net {
 class DrainableIOBuffer;
@@ -160,7 +161,9 @@
   };
 
   // |socket| should already be connected.
-  explicit SocketOutputStream(net::StreamSocket* socket);
+  SocketOutputStream(
+      net::StreamSocket* socket,
+      const net::NetworkTrafficAnnotationTag& traffic_annotation);
   ~SocketOutputStream() override;
 
   // ZeroCopyOutputStream implementation.
@@ -197,6 +200,11 @@
   // Note: last_error_ == net::ERR_IO_PENDING implies GetState() == FLUSHING.
   net::Error last_error_;
 
+  // Network traffic annotation for downstream socket write. SocketOutputStream
+  // is not reused, hence annotation can be added in constructor and used in all
+  // subsequent writes.
+  const net::NetworkTrafficAnnotationTag traffic_annotation_;
+
   base::WeakPtrFactory<SocketOutputStream> weak_ptr_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(SocketOutputStream);
diff --git a/google_apis/gcm/base/socket_stream_unittest.cc b/google_apis/gcm/base/socket_stream_unittest.cc
index b8f02fe4..9661c9f 100644
--- a/google_apis/gcm/base/socket_stream_unittest.cc
+++ b/google_apis/gcm/base/socket_stream_unittest.cc
@@ -16,6 +16,7 @@
 #include "net/base/ip_address.h"
 #include "net/log/net_log_source.h"
 #include "net/socket/socket_test_util.h"
+#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace gcm {
@@ -194,7 +195,8 @@
 
 void GCMSocketStreamTest::ResetOutputStream() {
   DCHECK(socket_.get());
-  socket_output_stream_.reset(new SocketOutputStream(socket_.get()));
+  socket_output_stream_.reset(
+      new SocketOutputStream(socket_.get(), TRAFFIC_ANNOTATION_FOR_TESTS));
 }
 
 // A read where all data is already available.
diff --git a/google_apis/gcm/engine/connection_factory_impl.cc b/google_apis/gcm/engine/connection_factory_impl.cc
index 8b98ee2..79f8f07 100644
--- a/google_apis/gcm/engine/connection_factory_impl.cc
+++ b/google_apis/gcm/engine/connection_factory_impl.cc
@@ -344,7 +344,9 @@
     event_tracker_.WriteToLoginRequest(&login_request);
   }
 
-  connection_handler_->Init(login_request, socket_handle_.socket());
+  // TODO(crbug.com/656607): Add Proper annotation
+  connection_handler_->Init(login_request, NO_TRAFFIC_ANNOTATION_BUG_656607,
+                            socket_handle_.socket());
 }
 
 std::unique_ptr<net::BackoffEntry> ConnectionFactoryImpl::CreateBackoffEntry(
diff --git a/google_apis/gcm/engine/connection_factory_impl_unittest.cc b/google_apis/gcm/engine/connection_factory_impl_unittest.cc
index d54d7f82..dc2921f 100644
--- a/google_apis/gcm/engine/connection_factory_impl_unittest.cc
+++ b/google_apis/gcm/engine/connection_factory_impl_unittest.cc
@@ -17,6 +17,7 @@
 #include "google_apis/gcm/monitoring/fake_gcm_stats_recorder.h"
 #include "net/base/backoff_entry.h"
 #include "net/http/http_network_session.h"
+#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 class Policy;
@@ -168,7 +169,7 @@
   ASSERT_GT(num_expected_attempts_, 0);
   ASSERT_FALSE(GetConnectionHandler()->CanSendMessage());
   std::unique_ptr<mcs_proto::LoginRequest> request(BuildLoginRequest(0, 0, ""));
-  GetConnectionHandler()->Init(*request, NULL);
+  GetConnectionHandler()->Init(*request, TRAFFIC_ANNOTATION_FOR_TESTS, NULL);
   OnConnectDone(connect_result_);
   if (!NextRetryAttempt().is_null()) {
     // Advance the time to the next retry time.
diff --git a/google_apis/gcm/engine/connection_handler.h b/google_apis/gcm/engine/connection_handler.h
index 68720a98..ee110c11 100644
--- a/google_apis/gcm/engine/connection_handler.h
+++ b/google_apis/gcm/engine/connection_handler.h
@@ -9,6 +9,7 @@
 
 #include "base/callback.h"
 #include "google_apis/gcm/base/gcm_export.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
 
 namespace net{
 class StreamSocket;
@@ -47,6 +48,7 @@
   // Note: It is correct and expected to call Init more than once, as connection
   // issues are encountered and new connections must be made.
   virtual void Init(const mcs_proto::LoginRequest& login_request,
+                    const net::NetworkTrafficAnnotationTag& traffic_annotation,
                     net::StreamSocket* socket) = 0;
 
   // Resets the handler and any internal state. Should be called any time
diff --git a/google_apis/gcm/engine/connection_handler_impl.cc b/google_apis/gcm/engine/connection_handler_impl.cc
index d2c071ad..887a4bea 100644
--- a/google_apis/gcm/engine/connection_handler_impl.cc
+++ b/google_apis/gcm/engine/connection_handler_impl.cc
@@ -66,6 +66,7 @@
 
 void ConnectionHandlerImpl::Init(
     const mcs_proto::LoginRequest& login_request,
+    const net::NetworkTrafficAnnotationTag& traffic_annotation,
     net::StreamSocket* socket) {
   DCHECK(!read_callback_.is_null());
   DCHECK(!write_callback_.is_null());
@@ -79,7 +80,7 @@
   message_size_ = 0;
   socket_ = socket;
   input_stream_.reset(new SocketInputStream(socket_));
-  output_stream_.reset(new SocketOutputStream(socket_));
+  output_stream_.reset(new SocketOutputStream(socket_, traffic_annotation));
 
   Login(login_request);
 }
diff --git a/google_apis/gcm/engine/connection_handler_impl.h b/google_apis/gcm/engine/connection_handler_impl.h
index 89fc972b..5cd1749 100644
--- a/google_apis/gcm/engine/connection_handler_impl.h
+++ b/google_apis/gcm/engine/connection_handler_impl.h
@@ -14,6 +14,7 @@
 #include "base/time/time.h"
 #include "base/timer/timer.h"
 #include "google_apis/gcm/engine/connection_handler.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
 
 namespace mcs_proto {
 class LoginRequest;
@@ -42,6 +43,7 @@
 
   // ConnectionHandler implementation.
   void Init(const mcs_proto::LoginRequest& login_request,
+            const net::NetworkTrafficAnnotationTag& traffic_annotation,
             net::StreamSocket* socket) override;
   void Reset() override;
   bool CanSendMessage() const override;
diff --git a/google_apis/gcm/engine/connection_handler_impl_unittest.cc b/google_apis/gcm/engine/connection_handler_impl_unittest.cc
index 447c9be..40f70c5 100644
--- a/google_apis/gcm/engine/connection_handler_impl_unittest.cc
+++ b/google_apis/gcm/engine/connection_handler_impl_unittest.cc
@@ -25,6 +25,7 @@
 #include "net/log/net_log_source.h"
 #include "net/socket/socket_test_util.h"
 #include "net/socket/stream_socket.h"
+#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace gcm {
@@ -239,9 +240,8 @@
           base::Bind(&GCMConnectionHandlerImplTest::ConnectionContinuation,
                      base::Unretained(this))));
   EXPECT_FALSE(connection_handler()->CanSendMessage());
-  connection_handler_->Init(
-      *BuildLoginRequest(kAuthId, kAuthToken, ""),
-      socket_.get());
+  connection_handler_->Init(*BuildLoginRequest(kAuthId, kAuthToken, ""),
+                            TRAFFIC_ANNOTATION_FOR_TESTS, socket_.get());
 }
 
 void GCMConnectionHandlerImplTest::ReadContinuation(
diff --git a/google_apis/gcm/engine/fake_connection_factory.cc b/google_apis/gcm/engine/fake_connection_factory.cc
index eaec8615..4631e573 100644
--- a/google_apis/gcm/engine/fake_connection_factory.cc
+++ b/google_apis/gcm/engine/fake_connection_factory.cc
@@ -7,6 +7,7 @@
 #include "google_apis/gcm/engine/fake_connection_handler.h"
 #include "google_apis/gcm/protocol/mcs.pb.h"
 #include "net/socket/stream_socket.h"
+#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
 
 namespace gcm {
 
@@ -35,7 +36,7 @@
 void FakeConnectionFactory::Connect() {
   mcs_proto::LoginRequest login_request;
   request_builder_.Run(&login_request);
-  connection_handler_->Init(login_request, NULL);
+  connection_handler_->Init(login_request, TRAFFIC_ANNOTATION_FOR_TESTS, NULL);
 }
 
 bool FakeConnectionFactory::IsEndpointReachable() const {
diff --git a/google_apis/gcm/engine/fake_connection_handler.cc b/google_apis/gcm/engine/fake_connection_handler.cc
index ca0ba5ae..34da9b1 100644
--- a/google_apis/gcm/engine/fake_connection_handler.cc
+++ b/google_apis/gcm/engine/fake_connection_handler.cc
@@ -42,8 +42,10 @@
 FakeConnectionHandler::~FakeConnectionHandler() {
 }
 
-void FakeConnectionHandler::Init(const mcs_proto::LoginRequest& login_request,
-                                 net::StreamSocket* socket) {
+void FakeConnectionHandler::Init(
+    const mcs_proto::LoginRequest& login_request,
+    const net::NetworkTrafficAnnotationTag& traffic_annotation,
+    net::StreamSocket* socket) {
   ASSERT_GE(expected_outgoing_messages_.size(), 1U);
   EXPECT_EQ(expected_outgoing_messages_.front().SerializeAsString(),
             login_request.SerializeAsString());
diff --git a/google_apis/gcm/engine/fake_connection_handler.h b/google_apis/gcm/engine/fake_connection_handler.h
index 1c79667..9afee54 100644
--- a/google_apis/gcm/engine/fake_connection_handler.h
+++ b/google_apis/gcm/engine/fake_connection_handler.h
@@ -10,6 +10,7 @@
 #include "base/macros.h"
 #include "google_apis/gcm/base/mcs_message.h"
 #include "google_apis/gcm/engine/connection_handler.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
 
 namespace gcm {
 
@@ -24,6 +25,7 @@
 
   // ConnectionHandler implementation.
   void Init(const mcs_proto::LoginRequest& login_request,
+            const net::NetworkTrafficAnnotationTag& traffic_annotation,
             net::StreamSocket* socket) override;
   void Reset() override;
   bool CanSendMessage() const override;
diff --git a/gpu/command_buffer/common/capabilities.h b/gpu/command_buffer/common/capabilities.h
index a27f69e..32b234c 100644
--- a/gpu/command_buffer/common/capabilities.h
+++ b/gpu/command_buffer/common/capabilities.h
@@ -147,6 +147,7 @@
   bool image_ycbcr_422 = false;
   bool image_ycbcr_420v = false;
   bool image_ycbcr_420v_disabled_for_video_frames = false;
+  bool image_xr30 = false;
   bool render_buffer_format_bgra8888 = false;
   bool occlusion_query = false;
   bool occlusion_query_boolean = false;
diff --git a/gpu/command_buffer/common/gpu_memory_buffer_support.cc b/gpu/command_buffer/common/gpu_memory_buffer_support.cc
index d86a011f..680827e 100644
--- a/gpu/command_buffer/common/gpu_memory_buffer_support.cc
+++ b/gpu/command_buffer/common/gpu_memory_buffer_support.cc
@@ -45,6 +45,8 @@
       return gfx::BufferFormat::YUV_420_BIPLANAR;
     case GL_RGB_YCBCR_422_CHROMIUM:
       return gfx::BufferFormat::UYVY_422;
+    case GL_RGB10_A2_EXT:
+      return gfx::BufferFormat::BGRX_1010102;
     default:
       NOTREACHED();
       return gfx::BufferFormat::RGBA_8888;
@@ -61,6 +63,7 @@
     case gfx::BufferFormat::ATCIA:
     case gfx::BufferFormat::BGRA_8888:
     case gfx::BufferFormat::BGRX_8888:
+    case gfx::BufferFormat::BGRX_1010102:
     case gfx::BufferFormat::DXT1:
     case gfx::BufferFormat::DXT5:
     case gfx::BufferFormat::ETC1:
@@ -74,7 +77,6 @@
       return format == BufferFormatForInternalFormat(internalformat);
     case gfx::BufferFormat::BGR_565:
     case gfx::BufferFormat::RGBX_8888:
-    case gfx::BufferFormat::BGRX_1010102:
       return internalformat == GL_RGB;
     case gfx::BufferFormat::RGBA_4444:
     case gfx::BufferFormat::RGBA_F16:
@@ -108,11 +110,12 @@
       return capabilities.texture_rg;
     case gfx::BufferFormat::UYVY_422:
       return capabilities.image_ycbcr_422;
+    case gfx::BufferFormat::BGRX_1010102:
+      return capabilities.image_xr30;
     case gfx::BufferFormat::BGR_565:
     case gfx::BufferFormat::RGBA_4444:
     case gfx::BufferFormat::RGBA_8888:
     case gfx::BufferFormat::RGBX_8888:
-    case gfx::BufferFormat::BGRX_1010102:
     case gfx::BufferFormat::YVU_420:
       return true;
     case gfx::BufferFormat::RGBA_F16:
diff --git a/gpu/command_buffer/service/feature_info.cc b/gpu/command_buffer/service/feature_info.cc
index 4323e81..3de5d1a 100644
--- a/gpu/command_buffer/service/feature_info.cc
+++ b/gpu/command_buffer/service/feature_info.cc
@@ -25,6 +25,8 @@
 
 #if !defined(OS_MACOSX)
 #include "ui/gl/gl_fence_egl.h"
+#else
+#include "base/mac/mac_util.h"
 #endif
 
 namespace gpu {
@@ -1072,6 +1074,24 @@
     feature_flags_.chromium_image_ycbcr_422 = true;
   }
 
+#if defined(OS_MACOSX)
+  // Mac can create GLImages out of XR30 IOSurfaces only after High Sierra.
+  feature_flags_.chromium_image_xr30 = base::mac::IsAtLeastOS10_13();
+#elif !defined(OS_WIN)
+  // TODO(mcasas): connect in Windows, https://crbug.com/803451
+  // XR30 support was introduced in GLES 3.0/ OpenGL 4.2, before that it was
+  // signalled via a specific extension.
+  feature_flags_.chromium_image_xr30 =
+      gl_version_info_->is_es3 || gl_version_info_->IsAtLeastGL(4, 2) ||
+      gl::HasExtension(extensions, "GL_EXT_texture_type_2_10_10_10_REV");
+#endif
+  if (feature_flags_.chromium_image_xr30){
+    validators_.texture_internal_format.AddValue(GL_RGB10_A2_EXT);
+    validators_.render_buffer_format.AddValue(GL_RGB10_A2_EXT);
+    validators_.texture_internal_format_storage.AddValue(GL_RGB10_A2_EXT);
+    validators_.pixel_type.AddValue(GL_UNSIGNED_INT_2_10_10_10_REV);
+  }
+
   // TODO(gman): Add support for these extensions.
   //     GL_OES_depth32
 
diff --git a/gpu/command_buffer/service/feature_info.h b/gpu/command_buffer/service/feature_info.h
index 2548add..4790d74 100644
--- a/gpu/command_buffer/service/feature_info.h
+++ b/gpu/command_buffer/service/feature_info.h
@@ -93,6 +93,7 @@
     bool ext_texture_norm16 = false;
     bool chromium_image_ycbcr_420v = false;
     bool chromium_image_ycbcr_422 = false;
+    bool chromium_image_xr30 = false;
     bool emulate_primitive_restart_fixed_index = false;
     bool ext_render_buffer_format_bgra8888 = false;
     bool ext_multisample_compatibility = false;
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc
index bb809b0..343fc49 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -4029,6 +4029,7 @@
   caps.image_ycbcr_420v_disabled_for_video_frames =
       group_->gpu_preferences()
           .disable_biplanar_gpu_memory_buffers_for_video_frames;
+  caps.image_xr30 = feature_info_->feature_flags().chromium_image_xr30;
   caps.max_copy_texture_chromium_size =
       workarounds().max_copy_texture_chromium_size;
   caps.render_buffer_format_bgra8888 =
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.cc b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.cc
index af67c91..870fcff 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.cc
@@ -1164,6 +1164,7 @@
   caps.image_ycbcr_420v_disabled_for_video_frames =
       group_->gpu_preferences()
           .disable_biplanar_gpu_memory_buffers_for_video_frames;
+  caps.image_xr30 = feature_info_->feature_flags().chromium_image_xr30;
   caps.max_copy_texture_chromium_size =
       feature_info_->workarounds().max_copy_texture_chromium_size;
   caps.render_buffer_format_bgra8888 =
diff --git a/gpu/command_buffer/service/texture_manager.cc b/gpu/command_buffer/service/texture_manager.cc
index 0be44b5..6b99be35 100644
--- a/gpu/command_buffer/service/texture_manager.cc
+++ b/gpu/command_buffer/service/texture_manager.cc
@@ -361,6 +361,11 @@
     return true;
   }
 
+  if (feature_info->feature_flags().chromium_image_xr30 &&
+      internal_format == GL_RGB10_A2_EXT) {
+    return true;
+  }
+
   // TODO(dshwang): check if it's possible to remove
   // CHROMIUM_color_buffer_float_rgb. crbug.com/329605
   if (feature_info->feature_flags().chromium_color_buffer_float_rgb &&
diff --git a/gpu/command_buffer/tests/gl_unittest.cc b/gpu/command_buffer/tests/gl_unittest.cc
index 7acc5e9..15b683a 100644
--- a/gpu/command_buffer/tests/gl_unittest.cc
+++ b/gpu/command_buffer/tests/gl_unittest.cc
@@ -121,6 +121,7 @@
   EXPECT_EQ(caps.texture_rg, flags.ext_texture_rg);
   EXPECT_EQ(caps.image_ycbcr_422, flags.chromium_image_ycbcr_422);
   EXPECT_EQ(caps.image_ycbcr_420v, flags.chromium_image_ycbcr_420v);
+  EXPECT_EQ(caps.image_xr30, flags.chromium_image_xr30);
   EXPECT_EQ(caps.render_buffer_format_bgra8888,
             flags.ext_render_buffer_format_bgra8888);
   EXPECT_EQ(caps.occlusion_query_boolean, flags.occlusion_query_boolean);
diff --git a/gpu/ipc/common/gpu_command_buffer_traits_multi.h b/gpu/ipc/common/gpu_command_buffer_traits_multi.h
index 237dbd3..21686ac 100644
--- a/gpu/ipc/common/gpu_command_buffer_traits_multi.h
+++ b/gpu/ipc/common/gpu_command_buffer_traits_multi.h
@@ -119,6 +119,7 @@
   IPC_STRUCT_TRAITS_MEMBER(image_ycbcr_422)
   IPC_STRUCT_TRAITS_MEMBER(image_ycbcr_420v)
   IPC_STRUCT_TRAITS_MEMBER(image_ycbcr_420v_disabled_for_video_frames)
+  IPC_STRUCT_TRAITS_MEMBER(image_xr30)
   IPC_STRUCT_TRAITS_MEMBER(render_buffer_format_bgra8888)
   IPC_STRUCT_TRAITS_MEMBER(occlusion_query)
   IPC_STRUCT_TRAITS_MEMBER(occlusion_query_boolean)
diff --git a/headless/DEPS b/headless/DEPS
index 5a088fd..5d6e91dc 100644
--- a/headless/DEPS
+++ b/headless/DEPS
@@ -14,6 +14,7 @@
   "+mojo/public",
   "+net",
   "+printing/features",
+  "+services/network/public/cpp",
   "+ui/base",
   "+ui/base/resource",
   "+ui/display",
diff --git a/headless/app/headless_shell.cc b/headless/app/headless_shell.cc
index 332713d5..2755fefb 100644
--- a/headless/app/headless_shell.cc
+++ b/headless/app/headless_shell.cc
@@ -40,6 +40,7 @@
 #include "net/base/net_errors.h"
 #include "net/http/http_util.h"
 #include "net/socket/ssl_client_socket.h"
+#include "services/network/public/cpp/network_switches.h"
 #include "ui/base/ui_base_switches.h"
 #include "ui/gfx/geometry/size.h"
 
@@ -741,9 +742,9 @@
     builder.SetProxyConfig(std::move(proxy_config));
   }
 
-  if (command_line.HasSwitch(switches::kHostResolverRules)) {
-    builder.SetHostResolverRules(
-        command_line.GetSwitchValueASCII(switches::kHostResolverRules));
+  if (command_line.HasSwitch(::network::switches::kHostResolverRules)) {
+    builder.SetHostResolverRules(command_line.GetSwitchValueASCII(
+        ::network::switches::kHostResolverRules));
   }
 
   if (command_line.HasSwitch(switches::kUseGL)) {
diff --git a/headless/app/headless_shell_switches.h b/headless/app/headless_shell_switches.h
index cef8353..5d62fc8 100644
--- a/headless/app/headless_shell_switches.h
+++ b/headless/app/headless_shell_switches.h
@@ -35,7 +35,6 @@
 extern const char kAuthServerWhitelist[];
 
 // Switches which are replicated from content.
-using ::switches::kHostResolverRules;
 using ::switches::kRemoteDebuggingPort;
 
 }  // namespace switches
diff --git a/headless/lib/browser/headless_browser_impl.cc b/headless/lib/browser/headless_browser_impl.cc
index 86fc0a33..86783d2 100644
--- a/headless/lib/browser/headless_browser_impl.cc
+++ b/headless/lib/browser/headless_browser_impl.cc
@@ -25,6 +25,7 @@
 #include "headless/lib/headless_content_main_delegate.h"
 #include "headless/public/internal/headless_devtools_client_impl.h"
 #include "net/http/http_util.h"
+#include "services/network/public/cpp/network_switches.h"
 #include "ui/aura/client/focus_client.h"
 #include "ui/aura/env.h"
 #include "ui/aura/window.h"
@@ -142,9 +143,9 @@
 void HeadlessBrowserImpl::PreMainMessageLoopRun() {
   const base::CommandLine* command_line =
       base::CommandLine::ForCurrentProcess();
-  if (command_line->HasSwitch(::switches::kLogNetLog)) {
+  if (command_line->HasSwitch(::network::switches::kLogNetLog)) {
     base::FilePath log_path =
-        command_line->GetSwitchValuePath(::switches::kLogNetLog);
+        command_line->GetSwitchValuePath(::network::switches::kLogNetLog);
     net_log_.reset(new HeadlessNetLog(log_path));
   } else {
     net_log_.reset(new net::NetLog());
diff --git a/headless/lib/renderer/headless_print_render_frame_helper_delegate.cc b/headless/lib/renderer/headless_print_render_frame_helper_delegate.cc
index 1b0995d..38475be 100644
--- a/headless/lib/renderer/headless_print_render_frame_helper_delegate.cc
+++ b/headless/lib/renderer/headless_print_render_frame_helper_delegate.cc
@@ -33,8 +33,4 @@
   return false;
 }
 
-bool HeadlessPrintRenderFrameHelperDelegate::IsAskPrintSettingsEnabled() {
-  return true;
-}
-
 }  // namespace headless
diff --git a/headless/lib/renderer/headless_print_render_frame_helper_delegate.h b/headless/lib/renderer/headless_print_render_frame_helper_delegate.h
index c23a7e98..d3d3a2c 100644
--- a/headless/lib/renderer/headless_print_render_frame_helper_delegate.h
+++ b/headless/lib/renderer/headless_print_render_frame_helper_delegate.h
@@ -16,11 +16,11 @@
   HeadlessPrintRenderFrameHelperDelegate();
   ~HeadlessPrintRenderFrameHelperDelegate() override;
 
-  // PrintRenderFrameHelper Delegate implementation.
+ private:
+  // printing::PrintRenderFrameHelper::Delegate:
   bool CancelPrerender(content::RenderFrame* render_frame) override;
   bool IsPrintPreviewEnabled() override;
   bool OverridePrint(blink::WebLocalFrame* frame) override;
-  bool IsAskPrintSettingsEnabled() override;
   blink::WebElement GetPdfElement(blink::WebLocalFrame* frame) override;
 
   DISALLOW_COPY_AND_ASSIGN(HeadlessPrintRenderFrameHelperDelegate);
diff --git a/headless/public/util/generic_url_request_job.cc b/headless/public/util/generic_url_request_job.cc
index 8095d94c..4f727cb 100644
--- a/headless/public/util/generic_url_request_job.cc
+++ b/headless/public/util/generic_url_request_job.cc
@@ -136,12 +136,14 @@
     scoped_refptr<net::HttpResponseHeaders> response_headers,
     const char* body,
     size_t body_size,
-    const net::LoadTimingInfo& load_timing_info) {
+    const net::LoadTimingInfo& load_timing_info,
+    size_t total_received_bytes) {
   DCHECK(origin_task_runner_->RunsTasksInCurrentSequence());
   response_headers_ = response_headers;
   body_ = body;
   body_size_ = body_size;
   load_timing_info_ = load_timing_info;
+  total_received_bytes_ = total_received_bytes;
 
   // Save any cookies from the response.
   if (!(request_->load_flags() & net::LOAD_DO_NOT_SAVE_COOKIES) &&
@@ -216,6 +218,10 @@
   *load_timing_info = load_timing_info_;
 }
 
+int64_t GenericURLRequestJob::GetTotalReceivedBytes() const {
+  return total_received_bytes_;
+}
+
 uint64_t GenericURLRequestJob::GenericURLRequestJob::GetRequestId() const {
   return request_->identifier() +
          (static_cast<uint64_t>(request_->url_chain().size()) << 32);
diff --git a/headless/public/util/generic_url_request_job.h b/headless/public/util/generic_url_request_job.h
index 06c90f7..f9f660ef 100644
--- a/headless/public/util/generic_url_request_job.h
+++ b/headless/public/util/generic_url_request_job.h
@@ -143,6 +143,7 @@
   bool GetMimeType(std::string* mime_type) const override;
   bool GetCharset(std::string* charset) override;
   void GetLoadTimingInfo(net::LoadTimingInfo* load_timing_info) const override;
+  int64_t GetTotalReceivedBytes() const override;
 
   // URLFetcher::ResultListener implementation:
   void OnFetchStartError(net::Error error) override;
@@ -150,7 +151,8 @@
                        scoped_refptr<net::HttpResponseHeaders> response_headers,
                        const char* body,
                        size_t body_size,
-                       const net::LoadTimingInfo& load_timing_info) override;
+                       const net::LoadTimingInfo& load_timing_info,
+                       size_t total_received_bytes) override;
 
  protected:
   // Request implementation:
@@ -187,6 +189,7 @@
   size_t body_size_ = 0;
   size_t read_offset_ = 0;
   net::LoadTimingInfo load_timing_info_;
+  size_t total_received_bytes_ = 0;
 
   base::WeakPtrFactory<GenericURLRequestJob> weak_factory_;
 
diff --git a/headless/public/util/generic_url_request_job_test.cc b/headless/public/util/generic_url_request_job_test.cc
index d1188b54..cb916cbc 100644
--- a/headless/public/util/generic_url_request_job_test.cc
+++ b/headless/public/util/generic_url_request_job_test.cc
@@ -124,9 +124,15 @@
     const base::Value* response_data_value = reply_dictionary->FindKey("data");
     ASSERT_THAT(response_data_value, NotNull());
     response_data_ = response_data_value->GetString();
+    const base::Value* total_received_bytes_value =
+        reply_dictionary->FindKey("total_received_bytes");
+    int total_received_bytes = 0;
+    if (total_received_bytes_value)
+      total_received_bytes = total_received_bytes_value->GetInt();
     result_listener->OnFetchComplete(
         GURL(final_url_value->GetString()), std::move(response_headers),
-        response_data_.c_str(), response_data_.size(), load_timing_info);
+        response_data_.c_str(), response_data_.size(), load_timing_info,
+        total_received_bytes);
   }
 
  private:
@@ -391,7 +397,8 @@
         "data": "Reply",
         "headers": {
           "Content-Type": "text/html; charset=UTF-8"
-        }
+        },
+        "total_received_bytes": 100
       })";
 
   std::unique_ptr<net::URLRequest> request(
@@ -403,6 +410,7 @@
   EXPECT_TRUE(request->Read(buffer.get(), kBufferSize, &bytes_read));
   EXPECT_EQ(5, bytes_read);
   EXPECT_EQ("Reply", std::string(buffer->data(), 5));
+  EXPECT_EQ(100, request->GetTotalReceivedBytes());
 
   net::LoadTimingInfo load_timing_info;
   request->GetLoadTimingInfo(&load_timing_info);
diff --git a/headless/public/util/http_url_fetcher.cc b/headless/public/util/http_url_fetcher.cc
index 7354aa7..b53dee9e 100644
--- a/headless/public/util/http_url_fetcher.cc
+++ b/headless/public/util/http_url_fetcher.cc
@@ -221,9 +221,11 @@
   // TODO(alexclarke) apart from the headers there's a lot of stuff in
   // |request->response_info()| that we drop here.  Find a way to pipe it
   // through.
+  // TODO(jzfeng) fill in the real total received bytes from network.
   result_listener_->OnFetchComplete(
       request->url(), request->response_info().headers,
-      bytes_read_so_far_.c_str(), bytes_read_so_far_.size(), load_timing_info);
+      bytes_read_so_far_.c_str(), bytes_read_so_far_.size(), load_timing_info,
+      0);
 }
 
 HttpURLFetcher::HttpURLFetcher(
diff --git a/headless/public/util/testing/test_in_memory_protocol_handler.cc b/headless/public/util/testing/test_in_memory_protocol_handler.cc
index 769ee3f..f2dbb18 100644
--- a/headless/public/util/testing/test_in_memory_protocol_handler.cc
+++ b/headless/public/util/testing/test_in_memory_protocol_handler.cc
@@ -54,7 +54,8 @@
       net::LoadTimingInfo load_timing_info;
       load_timing_info.receive_headers_end = base::TimeTicks::Now();
       result_listener->OnFetchCompleteExtractHeaders(
-          url, response->data.c_str(), response->data.size(), load_timing_info);
+          url, response->data.c_str(), response->data.size(), load_timing_info,
+          0);
     } else {
       result_listener->OnFetchStartError(net::ERR_FILE_NOT_FOUND);
     }
diff --git a/headless/public/util/url_fetcher.cc b/headless/public/util/url_fetcher.cc
index c9a79f9..9a7bfe81 100644
--- a/headless/public/util/url_fetcher.cc
+++ b/headless/public/util/url_fetcher.cc
@@ -16,7 +16,8 @@
     const GURL& final_url,
     const char* response_data,
     size_t response_data_size,
-    const net::LoadTimingInfo& load_timing_info) {
+    const net::LoadTimingInfo& load_timing_info,
+    size_t total_received_bytes) {
   size_t read_offset = 0;
   int header_size =
       net::HttpUtil::LocateEndOfHeaders(response_data, response_data_size);
@@ -34,7 +35,7 @@
   CHECK_LE(read_offset, response_data_size);
   OnFetchComplete(final_url, std::move(response_headers),
                   response_data + read_offset, response_data_size - read_offset,
-                  load_timing_info);
+                  load_timing_info, total_received_bytes);
 }
 
 }  // namespace headless
diff --git a/headless/public/util/url_fetcher.h b/headless/public/util/url_fetcher.h
index 7dd7558..e7955680 100644
--- a/headless/public/util/url_fetcher.h
+++ b/headless/public/util/url_fetcher.h
@@ -45,7 +45,8 @@
         scoped_refptr<net::HttpResponseHeaders> response_headers,
         const char* body,
         size_t body_size,
-        const net::LoadTimingInfo& load_timing_info) = 0;
+        const net::LoadTimingInfo& load_timing_info,
+        size_t total_received_bytes) = 0;
 
     // Helper function which extracts the headers from |response_data| and calls
     // OnFetchComplete.
@@ -53,7 +54,8 @@
         const GURL& final_url,
         const char* response_data,
         size_t response_data_size,
-        const net::LoadTimingInfo& load_timing_info);
+        const net::LoadTimingInfo& load_timing_info,
+        size_t total_received_bytes);
 
    protected:
     virtual ~ResultListener() {}
diff --git a/ios/chrome/browser/app_launcher/BUILD.gn b/ios/chrome/browser/app_launcher/BUILD.gn
new file mode 100644
index 0000000..476393e
--- /dev/null
+++ b/ios/chrome/browser/app_launcher/BUILD.gn
@@ -0,0 +1,37 @@
+# Copyright 2018 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/config/ios/rules.gni")
+
+source_set("app_launcher") {
+  configs += [ "//build/config/compiler:enable_arc" ]
+  sources = [
+    "app_launcher_tab_helper.h",
+    "app_launcher_tab_helper.mm",
+    "app_launcher_tab_helper_delegate.h",
+  ]
+  deps = [
+    "//base",
+    "//ios/chrome/browser",
+    "//ios/chrome/browser/web:web_internal",
+    "//ios/web/public",
+    "//url",
+  ]
+}
+
+source_set("unit_tests") {
+  configs += [ "//build/config/compiler:enable_arc" ]
+  testonly = true
+  sources = [
+    "app_launcher_tab_helper_unittest.mm",
+  ]
+  deps = [
+    ":app_launcher",
+    "//base",
+    "//ios/chrome/browser/web:web_internal",
+    "//ios/web/public/test/fakes",
+    "//testing/gtest",
+    "//url",
+  ]
+}
diff --git a/ios/chrome/browser/app_launcher/app_launcher_tab_helper.h b/ios/chrome/browser/app_launcher/app_launcher_tab_helper.h
new file mode 100644
index 0000000..cf742edb
--- /dev/null
+++ b/ios/chrome/browser/app_launcher/app_launcher_tab_helper.h
@@ -0,0 +1,64 @@
+// 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.
+
+#ifndef IOS_CHROME_BROWSER_APP_LAUNCHER_APP_LAUNCHER_TAB_HELPER_H_
+#define IOS_CHROME_BROWSER_APP_LAUNCHER_APP_LAUNCHER_TAB_HELPER_H_
+
+#include "base/macros.h"
+#import "ios/web/public/web_state/web_state_user_data.h"
+
+@protocol AppLauncherTabHelperDelegate;
+@class ExternalAppsLaunchPolicyDecider;
+class GURL;
+
+// A tab helper that handles requests to launch another application.
+class AppLauncherTabHelper
+    : public web::WebStateUserData<AppLauncherTabHelper> {
+ public:
+  ~AppLauncherTabHelper() override;
+
+  // Creates AppLauncherTabHelper and attaches to |web_state|. |web_state| must
+  // not be null. |policy_decider| provides policy for launching apps.
+  // |delegate| can launch applications and present UI and is not retained by
+  // TabHelper.
+  static void CreateForWebState(web::WebState* web_state,
+                                ExternalAppsLaunchPolicyDecider* policy_decider,
+                                id<AppLauncherTabHelperDelegate> delegate);
+
+  // Requests to open the application with |url|.
+  // The method checks if the application for |url| has been opened repeatedly
+  // by the |source_page_url| page in a short time frame, in that case a prompt
+  // will appear to the user with an option to block the application from
+  // launching. Then the method also checks for user interaction and for schemes
+  // that require special handling (eg. facetime, mailto) and may present the
+  // user with a confirmation dialog to open the application. If there is no
+  // such application available or it's not possible to open the application the
+  // method returns NO.
+  bool RequestToLaunchApp(const GURL& url,
+                          const GURL& source_page_url,
+                          bool link_tapped);
+
+ private:
+  // Constructor for AppLauncherTabHelper. |policy_decider| provides policy for
+  // launching apps. |delegate| can launch applications and present UI and is
+  // not retained by TabHelper.
+  AppLauncherTabHelper(ExternalAppsLaunchPolicyDecider* policy_decider,
+                       id<AppLauncherTabHelperDelegate> delegate);
+
+  // Used to check for repeated launches and provide policy for launching apps.
+  ExternalAppsLaunchPolicyDecider* policy_decider_ = nil;
+
+  // Used to launch apps and present UI.
+  __weak id<AppLauncherTabHelperDelegate> delegate_ = nil;
+
+  // Returns whether there is a prompt shown by |RequestToOpenUrl| or not.
+  bool is_prompt_active_ = false;
+
+  // Must be last member to ensure it is destroyed last.
+  base::WeakPtrFactory<AppLauncherTabHelper> weak_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(AppLauncherTabHelper);
+};
+
+#endif  // IOS_CHROME_BROWSER_APP_LAUNCHER_APP_LAUNCHER_TAB_HELPER_H_
diff --git a/ios/chrome/browser/app_launcher/app_launcher_tab_helper.mm b/ios/chrome/browser/app_launcher/app_launcher_tab_helper.mm
new file mode 100644
index 0000000..4c7d0c9
--- /dev/null
+++ b/ios/chrome/browser/app_launcher/app_launcher_tab_helper.mm
@@ -0,0 +1,97 @@
+// 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.
+
+#import "ios/chrome/browser/app_launcher/app_launcher_tab_helper.h"
+
+#import <UIKit/UIKit.h>
+
+#include "base/memory/ptr_util.h"
+#import "ios/chrome/browser/app_launcher/app_launcher_tab_helper_delegate.h"
+#import "ios/chrome/browser/web/external_apps_launch_policy_decider.h"
+#include "url/gurl.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+DEFINE_WEB_STATE_USER_DATA_KEY(AppLauncherTabHelper);
+
+void AppLauncherTabHelper::CreateForWebState(
+    web::WebState* web_state,
+    ExternalAppsLaunchPolicyDecider* policy_decider,
+    id<AppLauncherTabHelperDelegate> delegate) {
+  DCHECK(web_state);
+  if (!FromWebState(web_state)) {
+    web_state->SetUserData(
+        UserDataKey(),
+        base::WrapUnique(new AppLauncherTabHelper(policy_decider, delegate)));
+  }
+}
+
+AppLauncherTabHelper::AppLauncherTabHelper(
+    ExternalAppsLaunchPolicyDecider* policy_decider,
+    id<AppLauncherTabHelperDelegate> delegate)
+    : policy_decider_(policy_decider),
+      delegate_(delegate),
+      weak_factory_(this) {}
+
+AppLauncherTabHelper::~AppLauncherTabHelper() = default;
+
+bool AppLauncherTabHelper::RequestToLaunchApp(const GURL& url,
+                                              const GURL& source_page_url,
+                                              bool link_tapped) {
+  if (!url.is_valid() || !url.has_scheme())
+    return false;
+
+  // Don't open external application if chrome is not active.
+  if ([[UIApplication sharedApplication] applicationState] !=
+      UIApplicationStateActive) {
+    return false;
+  }
+
+  // Don't try to open external application if a prompt is already active.
+  if (is_prompt_active_)
+    return false;
+
+  [policy_decider_ didRequestLaunchExternalAppURL:url
+                                fromSourcePageURL:source_page_url];
+  ExternalAppLaunchPolicy policy =
+      [policy_decider_ launchPolicyForURL:url
+                        fromSourcePageURL:source_page_url];
+  switch (policy) {
+    case ExternalAppLaunchPolicyBlock: {
+      return false;
+    }
+    case ExternalAppLaunchPolicyAllow: {
+      return [delegate_ appLauncherTabHelper:this
+                            launchAppWithURL:url
+                                  linkTapped:link_tapped];
+    }
+    case ExternalAppLaunchPolicyPrompt: {
+      is_prompt_active_ = true;
+      base::WeakPtr<AppLauncherTabHelper> weak_this =
+          weak_factory_.GetWeakPtr();
+      [delegate_ appLauncherTabHelper:this
+          showAlertOfRepeatedLaunchesWithCompletionHandler:^(
+              BOOL user_allowed) {
+            if (!weak_this.get())
+              return;
+            if (user_allowed) {
+              // By confirming that user wants to launch the application, there
+              // is no need to check for |link_tapped|.
+              [delegate_ appLauncherTabHelper:weak_this.get()
+                             launchAppWithURL:url
+                                   linkTapped:YES];
+            } else {
+              // TODO(crbug.com/674649): Once non modal dialogs are implemented,
+              // update this to always prompt instead of blocking the app.
+              [policy_decider_ blockLaunchingAppURL:url
+                                  fromSourcePageURL:source_page_url];
+            }
+            is_prompt_active_ = false;
+          }];
+      return true;
+    }
+  }
+}
diff --git a/ios/chrome/browser/app_launcher/app_launcher_tab_helper_delegate.h b/ios/chrome/browser/app_launcher/app_launcher_tab_helper_delegate.h
new file mode 100644
index 0000000..8461f12
--- /dev/null
+++ b/ios/chrome/browser/app_launcher/app_launcher_tab_helper_delegate.h
@@ -0,0 +1,33 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_CHROME_BROWSER_APP_LAUNCHER_APP_LAUNCHER_TAB_HELPER_DELEGATE_H_
+#define IOS_CHROME_BROWSER_APP_LAUNCHER_APP_LAUNCHER_TAB_HELPER_DELEGATE_H_
+
+#include "ios/chrome/browser/procedural_block_types.h"
+
+class AppLauncherTabHelper;
+class GURL;
+
+// Protocol for handling application launching and presenting related UI.
+@protocol AppLauncherTabHelperDelegate
+
+// Launches application that has |URL| if possible (optionally after confirming
+// via dialog in case the user didn't interact using |linkTapped| or if the
+// application is facetime). Returns NO if there is no such application
+// available.
+- (BOOL)appLauncherTabHelper:(AppLauncherTabHelper*)tabHelper
+            launchAppWithURL:(const GURL&)URL
+                  linkTapped:(BOOL)linkTapped;
+
+// Alerts the user that there have been repeated attempts to launch
+// the application. |completionHandler| is called with the user's
+// response on whether to launch the application.
+- (void)appLauncherTabHelper:(AppLauncherTabHelper*)tabHelper
+    showAlertOfRepeatedLaunchesWithCompletionHandler:
+        (ProceduralBlockWithBool)completionHandler;
+
+@end
+
+#endif  // IOS_CHROME_BROWSER_APP_LAUNCHER_APP_LAUNCHER_TAB_HELPER_DELEGATE_H_
diff --git a/ios/chrome/browser/app_launcher/app_launcher_tab_helper_unittest.mm b/ios/chrome/browser/app_launcher/app_launcher_tab_helper_unittest.mm
new file mode 100644
index 0000000..35c9a12
--- /dev/null
+++ b/ios/chrome/browser/app_launcher/app_launcher_tab_helper_unittest.mm
@@ -0,0 +1,137 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/chrome/browser/app_launcher/app_launcher_tab_helper.h"
+
+#include <memory>
+
+#import "ios/chrome/browser/app_launcher/app_launcher_tab_helper_delegate.h"
+#import "ios/chrome/browser/web/external_apps_launch_policy_decider.h"
+#import "ios/web/public/test/fakes/test_web_state.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#import "testing/gtest_mac.h"
+#include "testing/platform_test.h"
+#include "url/gurl.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+// An object that conforms to AppLauncherTabHelperDelegate for testing.
+@interface FakeAppLauncherTabHelperDelegate
+    : NSObject<AppLauncherTabHelperDelegate>
+// URL of the last launched application.
+@property(nonatomic, assign) GURL lastLaunchedAppURL;
+// Number of times an app was launched.
+@property(nonatomic, assign) NSUInteger countOfAppsLaunched;
+// Number of times the repeated launches alert has been shown.
+@property(nonatomic, assign) NSUInteger countOfAlertsShown;
+// Simulates the user tapping the accept button when prompted via
+// |-appLauncherTabHelper:showAlertOfRepeatedLaunchesWithCompletionHandler|.
+@property(nonatomic, assign) BOOL simulateUserAcceptingPrompt;
+@end
+
+@implementation FakeAppLauncherTabHelperDelegate
+@synthesize lastLaunchedAppURL = _lastLaunchedAppURL;
+@synthesize countOfAppsLaunched = _countOfAppsLaunched;
+@synthesize countOfAlertsShown = _countOfAlertsShown;
+@synthesize simulateUserAcceptingPrompt = _simulateUserAcceptingPrompt;
+- (BOOL)appLauncherTabHelper:(AppLauncherTabHelper*)tabHelper
+            launchAppWithURL:(const GURL&)URL
+                  linkTapped:(BOOL)linkTapped {
+  self.countOfAppsLaunched++;
+  self.lastLaunchedAppURL = URL;
+  return YES;
+}
+- (void)appLauncherTabHelper:(AppLauncherTabHelper*)tabHelper
+    showAlertOfRepeatedLaunchesWithCompletionHandler:
+        (ProceduralBlockWithBool)completionHandler {
+  self.countOfAlertsShown++;
+  completionHandler(self.simulateUserAcceptingPrompt);
+}
+@end
+
+// An ExternalAppsLaunchPolicyDecider for testing.
+@interface FakeExternalAppsLaunchPolicyDecider : ExternalAppsLaunchPolicyDecider
+@property(nonatomic, assign) ExternalAppLaunchPolicy policy;
+@end
+
+@implementation FakeExternalAppsLaunchPolicyDecider
+@synthesize policy = _policy;
+- (ExternalAppLaunchPolicy)launchPolicyForURL:(const GURL&)URL
+                            fromSourcePageURL:(const GURL&)sourcePageURL {
+  return self.policy;
+}
+@end
+
+// Test fixture for AppLauncherTabHelper class.
+class AppLauncherTabHelperTest : public PlatformTest {
+ protected:
+  AppLauncherTabHelperTest()
+      : policy_decider_([[FakeExternalAppsLaunchPolicyDecider alloc] init]),
+        delegate_([[FakeAppLauncherTabHelperDelegate alloc] init]) {
+    AppLauncherTabHelper::CreateForWebState(&web_state_, policy_decider_,
+                                            delegate_);
+    tab_helper_ = AppLauncherTabHelper::FromWebState(&web_state_);
+  }
+
+  web::TestWebState web_state_;
+  FakeExternalAppsLaunchPolicyDecider* policy_decider_ = nil;
+  FakeAppLauncherTabHelperDelegate* delegate_ = nil;
+  AppLauncherTabHelper* tab_helper_;
+};
+
+// Tests that an empty URL does not show alert or launch app.
+TEST_F(AppLauncherTabHelperTest, EmptyUrl) {
+  tab_helper_->RequestToLaunchApp(GURL::EmptyGURL(), GURL::EmptyGURL(), false);
+  EXPECT_EQ(0U, delegate_.countOfAlertsShown);
+  EXPECT_EQ(0U, delegate_.countOfAppsLaunched);
+}
+
+// Tests that an invalid URL does not show alert or launch app.
+TEST_F(AppLauncherTabHelperTest, InvalidUrl) {
+  tab_helper_->RequestToLaunchApp(GURL("invalid"), GURL::EmptyGURL(), false);
+  EXPECT_EQ(0U, delegate_.countOfAlertsShown);
+  EXPECT_EQ(0U, delegate_.countOfAppsLaunched);
+}
+
+// Tests that a valid URL does launch app.
+TEST_F(AppLauncherTabHelperTest, ValidUrl) {
+  policy_decider_.policy = ExternalAppLaunchPolicyAllow;
+  tab_helper_->RequestToLaunchApp(GURL("valid://1234"), GURL::EmptyGURL(),
+                                  false);
+  EXPECT_EQ(1U, delegate_.countOfAppsLaunched);
+  EXPECT_EQ(GURL("valid://1234"), delegate_.lastLaunchedAppURL);
+}
+
+// Tests that a valid URL does not launch app when launch policy is to block.
+TEST_F(AppLauncherTabHelperTest, ValidUrlBlocked) {
+  policy_decider_.policy = ExternalAppLaunchPolicyBlock;
+  tab_helper_->RequestToLaunchApp(GURL("valid://1234"), GURL::EmptyGURL(),
+                                  false);
+  EXPECT_EQ(0U, delegate_.countOfAlertsShown);
+  EXPECT_EQ(0U, delegate_.countOfAppsLaunched);
+}
+
+// Tests that a valid URL shows an alert and launches app when launch policy is
+// to prompt and user accepts.
+TEST_F(AppLauncherTabHelperTest, ValidUrlPromptUserAccepts) {
+  policy_decider_.policy = ExternalAppLaunchPolicyPrompt;
+  delegate_.simulateUserAcceptingPrompt = YES;
+  tab_helper_->RequestToLaunchApp(GURL("valid://1234"), GURL::EmptyGURL(),
+                                  false);
+  EXPECT_EQ(1U, delegate_.countOfAlertsShown);
+  EXPECT_EQ(1U, delegate_.countOfAppsLaunched);
+  EXPECT_EQ(GURL("valid://1234"), delegate_.lastLaunchedAppURL);
+}
+
+// Tests that a valid URL does not launch app when launch policy is to prompt
+// and user rejects.
+TEST_F(AppLauncherTabHelperTest, ValidUrlPromptUserRejects) {
+  policy_decider_.policy = ExternalAppLaunchPolicyPrompt;
+  delegate_.simulateUserAcceptingPrompt = NO;
+  tab_helper_->RequestToLaunchApp(GURL("valid://1234"), GURL::EmptyGURL(),
+                                  false);
+  EXPECT_EQ(0U, delegate_.countOfAppsLaunched);
+}
diff --git a/ios/chrome/browser/tabs/BUILD.gn b/ios/chrome/browser/tabs/BUILD.gn
index 6a4f703e..18f15ea 100644
--- a/ios/chrome/browser/tabs/BUILD.gn
+++ b/ios/chrome/browser/tabs/BUILD.gn
@@ -86,6 +86,7 @@
     "//components/url_formatter",
     "//ios/chrome/app/strings",
     "//ios/chrome/browser",
+    "//ios/chrome/browser/app_launcher",
     "//ios/chrome/browser/autofill",
     "//ios/chrome/browser/autofill:autofill_internal",
     "//ios/chrome/browser/bookmarks",
diff --git a/ios/chrome/browser/tabs/tab.mm b/ios/chrome/browser/tabs/tab.mm
index a86360a..bc86765 100644
--- a/ios/chrome/browser/tabs/tab.mm
+++ b/ios/chrome/browser/tabs/tab.mm
@@ -40,6 +40,7 @@
 #include "components/search_engines/template_url_service.h"
 #include "components/strings/grit/components_strings.h"
 #include "components/url_formatter/url_formatter.h"
+#import "ios/chrome/browser/app_launcher/app_launcher_tab_helper.h"
 #include "ios/chrome/browser/application_context.h"
 #import "ios/chrome/browser/autofill/form_input_accessory_view_controller.h"
 #import "ios/chrome/browser/autofill/form_suggestion_tab_helper.h"
@@ -82,7 +83,6 @@
 #import "ios/chrome/browser/ui/overscroll_actions/overscroll_actions_controller.h"
 #include "ios/chrome/browser/ui/ui_util.h"
 #import "ios/chrome/browser/voice/voice_search_navigations_tab_helper.h"
-#import "ios/chrome/browser/web/external_app_launcher_tab_helper.h"
 #import "ios/chrome/browser/web/navigation_manager_util.h"
 #import "ios/chrome/browser/web/page_placeholder_tab_helper.h"
 #import "ios/chrome/browser/web/passkit_dialog_provider.h"
@@ -471,10 +471,10 @@
       return NO;
   }
 
-  ExternalAppLauncherTabHelper* externalAppLauncherTabHelper =
-      ExternalAppLauncherTabHelper::FromWebState(self.webState);
-  if (externalAppLauncherTabHelper->RequestToOpenUrl(finalURL, sourceURL,
-                                                     linkClicked)) {
+  AppLauncherTabHelper* appLauncherTabHelper =
+      AppLauncherTabHelper::FromWebState(self.webState);
+  if (appLauncherTabHelper->RequestToLaunchApp(finalURL, sourceURL,
+                                               linkClicked)) {
     // Clears pending navigation history after successfully launching the
     // external app.
     DCHECK([self navigationManager]);
diff --git a/ios/chrome/browser/tabs/tab_helper_util.mm b/ios/chrome/browser/tabs/tab_helper_util.mm
index 2c5d351c..a65bd4e 100644
--- a/ios/chrome/browser/tabs/tab_helper_util.mm
+++ b/ios/chrome/browser/tabs/tab_helper_util.mm
@@ -38,7 +38,6 @@
 #import "ios/chrome/browser/translate/chrome_ios_translate_client.h"
 #import "ios/chrome/browser/voice/voice_search_navigations_tab_helper.h"
 #import "ios/chrome/browser/web/blocked_popup_tab_helper.h"
-#import "ios/chrome/browser/web/external_app_launcher_tab_helper.h"
 #import "ios/chrome/browser/web/load_timing_tab_helper.h"
 #import "ios/chrome/browser/web/network_activity_indicator_tab_helper.h"
 #import "ios/chrome/browser/web/page_placeholder_tab_helper.h"
@@ -111,7 +110,6 @@
   ]);
 
   InsecureInputTabHelper::CreateForWebState(web_state);
-  ExternalAppLauncherTabHelper::CreateForWebState(web_state);
 
   // TODO(crbug.com/794115): pre-rendered WebState have lots of unnecessary
   // tab helpers for historical reasons. For the moment, AttachTabHelpers
diff --git a/ios/chrome/browser/ui/BUILD.gn b/ios/chrome/browser/ui/BUILD.gn
index 91366e8e..bd62258 100644
--- a/ios/chrome/browser/ui/BUILD.gn
+++ b/ios/chrome/browser/ui/BUILD.gn
@@ -272,6 +272,7 @@
     "//ios/chrome/app:tests_hook",
     "//ios/chrome/app/strings",
     "//ios/chrome/browser",
+    "//ios/chrome/browser/app_launcher",
     "//ios/chrome/browser/bookmarks",
     "//ios/chrome/browser/browser_state",
     "//ios/chrome/browser/download",
@@ -300,6 +301,7 @@
     "//ios/chrome/browser/ui/activity_services:coordinator",
     "//ios/chrome/browser/ui/activity_services/requirements",
     "//ios/chrome/browser/ui/alert_coordinator",
+    "//ios/chrome/browser/ui/app_launcher",
     "//ios/chrome/browser/ui/authentication",
     "//ios/chrome/browser/ui/bookmarks",
     "//ios/chrome/browser/ui/bubble",
diff --git a/ios/chrome/browser/ui/app_launcher/BUILD.gn b/ios/chrome/browser/ui/app_launcher/BUILD.gn
new file mode 100644
index 0000000..bd25e18f
--- /dev/null
+++ b/ios/chrome/browser/ui/app_launcher/BUILD.gn
@@ -0,0 +1,54 @@
+# Copyright 2018 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/config/ios/rules.gni")
+
+source_set("app_launcher") {
+  configs += [ "//build/config/compiler:enable_arc" ]
+  sources = [
+    "app_launcher_coordinator.h",
+    "app_launcher_coordinator.mm",
+    "app_launcher_util.h",
+    "app_launcher_util.mm",
+    "open_mail_handler_view_controller.h",
+    "open_mail_handler_view_controller.mm",
+  ]
+  deps = [
+    "//base",
+    "//components/strings:components_strings_grit",
+    "//ios/chrome/app/strings:ios_strings_grit",
+    "//ios/chrome/browser",
+    "//ios/chrome/browser/app_launcher",
+    "//ios/chrome/browser/ui/collection_view",
+    "//ios/chrome/browser/web",
+    "//ios/third_party/material_components_ios",
+    "//net",
+    "//ui/base",
+    "//url",
+  ]
+}
+
+source_set("unit_tests") {
+  configs += [ "//build/config/compiler:enable_arc" ]
+  testonly = true
+  sources = [
+    "app_launcher_coordinator_unittest.mm",
+    "app_launcher_util_unittest.mm",
+    "open_mail_handler_view_controller_unittest.mm",
+  ]
+  deps = [
+    ":app_launcher",
+    "//base",
+    "//ios/chrome/app/strings:ios_strings_grit",
+    "//ios/chrome/browser/ui/collection_view:test_support",
+    "//ios/chrome/browser/ui/collection_view/cells",
+    "//ios/chrome/browser/web",
+    "//ios/chrome/test:test_support",
+    "//ios/web/public/test/fakes",
+    "//testing/gtest",
+    "//third_party/ocmock",
+    "//ui/base",
+    "//url",
+  ]
+}
diff --git a/ios/chrome/browser/ui/app_launcher/app_launcher_coordinator.h b/ios/chrome/browser/ui/app_launcher/app_launcher_coordinator.h
new file mode 100644
index 0000000..324dd52b
--- /dev/null
+++ b/ios/chrome/browser/ui/app_launcher/app_launcher_coordinator.h
@@ -0,0 +1,25 @@
+// 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.
+
+#ifndef IOS_CHROME_BROWSER_UI_APP_LAUNCHER_APP_LAUNCHER_COORDINATOR_H_
+#define IOS_CHROME_BROWSER_UI_APP_LAUNCHER_APP_LAUNCHER_COORDINATOR_H_
+
+#import <UIKit/UIKit.h>
+
+#import "ios/chrome/browser/app_launcher/app_launcher_tab_helper_delegate.h"
+
+// A coordinator that handles UI related to launching apps.
+@interface AppLauncherCoordinator : NSObject<AppLauncherTabHelperDelegate>
+
+// Initializes the coordinator with the |baseViewController|, from which to
+// present UI.
+- (instancetype)initWithBaseViewController:(UIViewController*)baseViewController
+    NS_DESIGNATED_INITIALIZER;
+
+// Default designated initializer is unavailable.
+- (instancetype)init NS_UNAVAILABLE;
+
+@end
+
+#endif  // IOS_CHROME_BROWSER_UI_APP_LAUNCHER_APP_LAUNCHER_COORDINATOR_H_
diff --git a/ios/chrome/browser/ui/app_launcher/app_launcher_coordinator.mm b/ios/chrome/browser/ui/app_launcher/app_launcher_coordinator.mm
new file mode 100644
index 0000000..4b5bbc7
--- /dev/null
+++ b/ios/chrome/browser/ui/app_launcher/app_launcher_coordinator.mm
@@ -0,0 +1,236 @@
+// 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.
+
+#import "ios/chrome/browser/ui/app_launcher/app_launcher_coordinator.h"
+
+#import <UIKit/UIKit.h>
+
+#include "base/logging.h"
+#include "base/metrics/histogram_macros.h"
+#include "components/strings/grit/components_strings.h"
+#include "ios/chrome/browser/procedural_block_types.h"
+#import "ios/chrome/browser/ui/app_launcher/app_launcher_util.h"
+#import "ios/chrome/browser/ui/app_launcher/open_mail_handler_view_controller.h"
+#import "ios/chrome/browser/web/mailto_handler.h"
+#import "ios/chrome/browser/web/mailto_handler_manager.h"
+#include "ios/chrome/grit/ios_strings.h"
+#include "ios/third_party/material_components_ios/src/components/BottomSheet/src/MDCBottomSheetController.h"
+#import "net/base/mac/url_conversions.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "url/gurl.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+namespace {
+
+// Launches the mail client app represented by |handler| and records metrics.
+void LaunchMailClientApp(const GURL& url, MailtoHandler* handler) {
+  NSString* launch_url = [handler rewriteMailtoURL:url];
+  UMA_HISTOGRAM_BOOLEAN("IOS.MailtoURLRewritten", launch_url != nil);
+  NSURL* url_to_open = launch_url.length ? [NSURL URLWithString:launch_url]
+                                         : net::NSURLWithGURL(url);
+  [[UIApplication sharedApplication] openURL:url_to_open
+                                     options:@{}
+                           completionHandler:nil];
+}
+
+// Records histogram metric on the user's response when prompted to open another
+// application. |user_accepted| should be YES if the user accepted the prompt to
+// launch another application. This call is extracted to a separate function to
+// reduce macro code expansion.
+void RecordUserAcceptedAppLaunchMetric(BOOL user_accepted) {
+  UMA_HISTOGRAM_BOOLEAN("Tab.ExternalApplicationOpened", user_accepted);
+}
+
+}  // namespace
+
+@interface AppLauncherCoordinator ()
+// The base view controller from which to present UI.
+@property(nonatomic, weak) UIViewController* baseViewController;
+@end
+
+@implementation AppLauncherCoordinator
+@synthesize baseViewController = _baseViewController;
+
+- (instancetype)initWithBaseViewController:
+    (UIViewController*)baseViewController {
+  if (self = [super init]) {
+    _baseViewController = baseViewController;
+  }
+  return self;
+}
+
+#pragma mark - Private methods
+
+// Alerts the user with |message| and buttons with titles
+// |acceptActionTitle| and |rejectActionTitle|. |completionHandler| is called
+// with a BOOL indicating whether the user has tapped the accept button.
+- (void)showAlertWithMessage:(NSString*)message
+           acceptActionTitle:(NSString*)acceptActionTitle
+           rejectActionTitle:(NSString*)rejectActionTitle
+           completionHandler:(ProceduralBlockWithBool)completionHandler {
+  UIAlertController* alertController =
+      [UIAlertController alertControllerWithTitle:nil
+                                          message:message
+                                   preferredStyle:UIAlertControllerStyleAlert];
+  UIAlertAction* acceptAction =
+      [UIAlertAction actionWithTitle:acceptActionTitle
+                               style:UIAlertActionStyleDefault
+                             handler:^(UIAlertAction* action) {
+                               completionHandler(YES);
+                             }];
+  UIAlertAction* rejectAction =
+      [UIAlertAction actionWithTitle:rejectActionTitle
+                               style:UIAlertActionStyleCancel
+                             handler:^(UIAlertAction* action) {
+                               completionHandler(NO);
+                             }];
+  [alertController addAction:rejectAction];
+  [alertController addAction:acceptAction];
+
+  [self.baseViewController presentViewController:alertController
+                                        animated:YES
+                                      completion:nil];
+}
+
+// Shows an alert that the app will open in another application. If the user
+// accepts, the |URL| is launched.
+- (void)showAlertAndLaunchAppStoreURL:(const GURL&)URL {
+  DCHECK(UrlHasAppStoreScheme(URL));
+  NSString* prompt = l10n_util::GetNSString(IDS_IOS_OPEN_IN_ANOTHER_APP);
+  NSString* openLabel =
+      l10n_util::GetNSString(IDS_IOS_APP_LAUNCHER_OPEN_APP_BUTTON_LABEL);
+  NSString* cancelLabel = l10n_util::GetNSString(IDS_CANCEL);
+  NSURL* copiedURL = net::NSURLWithGURL(URL);
+  [self showAlertWithMessage:prompt
+           acceptActionTitle:openLabel
+           rejectActionTitle:cancelLabel
+           completionHandler:^(BOOL userAccepted) {
+             RecordUserAcceptedAppLaunchMetric(userAccepted);
+             if (userAccepted) {
+               [[UIApplication sharedApplication] openURL:copiedURL
+                                                  options:@{}
+                                        completionHandler:nil];
+             }
+           }];
+}
+
+// Shows an alert to launch a phone call or Facetime. The |URL| is launched if
+// the user accepts.
+- (void)showAlertAndLaunchPhoneCallOrFacetimeURL:(const GURL&)URL {
+  DCHECK(UrlHasPhoneCallScheme(URL));
+  NSURL* phoneCallOrFacetimeURL = net::NSURLWithGURL(URL);
+  NSString* prompt =
+      GetFormattedAbsoluteUrlWithSchemeRemoved(phoneCallOrFacetimeURL);
+  NSString* openLabel = GetPromptActionString(phoneCallOrFacetimeURL.scheme);
+  NSString* cancelLabel = l10n_util::GetNSString(IDS_CANCEL);
+  [self showAlertWithMessage:prompt
+           acceptActionTitle:openLabel
+           rejectActionTitle:cancelLabel
+           completionHandler:^(BOOL userAccepted) {
+             RecordUserAcceptedAppLaunchMetric(userAccepted);
+             if (userAccepted) {
+               [[UIApplication sharedApplication] openURL:phoneCallOrFacetimeURL
+                                                  options:@{}
+                                        completionHandler:nil];
+             }
+           }];
+}
+
+// Launches |URL| in a mailto handler. If a default mailto handler does not
+// exist, then a mail handler chooser is launched before the mailto handler
+// is launched.
+- (void)showAlertIfNeededAndLaunchMailtoURL:(const GURL&)URL {
+  DCHECK(URL.SchemeIs(url::kMailToScheme));
+  MailtoHandlerManager* manager =
+      [MailtoHandlerManager mailtoHandlerManagerWithStandardHandlers];
+  NSString* handlerID = manager.defaultHandlerID;
+  if (handlerID) {
+    MailtoHandler* handler = [manager defaultHandlerByID:handlerID];
+    LaunchMailClientApp(URL, handler);
+    return;
+  }
+  GURL copiedURLToOpen = URL;
+  OpenMailHandlerViewController* mailHandlerChooser =
+      [[OpenMailHandlerViewController alloc]
+          initWithManager:manager
+          selectedHandler:^(MailtoHandler* _Nonnull handler) {
+            LaunchMailClientApp(copiedURLToOpen, handler);
+          }];
+  MDCBottomSheetController* bottomSheet = [[MDCBottomSheetController alloc]
+      initWithContentViewController:mailHandlerChooser];
+  [self.baseViewController presentViewController:bottomSheet
+                                        animated:YES
+                                      completion:nil];
+}
+
+#pragma mark - AppLauncherTabHelperDelegate
+
+- (BOOL)appLauncherTabHelper:(AppLauncherTabHelper*)tabHelper
+            launchAppWithURL:(const GURL&)URL
+                  linkTapped:(BOOL)linkTapped {
+  // Don't open application if chrome is not active.
+  if ([[UIApplication sharedApplication] applicationState] !=
+      UIApplicationStateActive) {
+    return NO;
+  }
+  if (@available(iOS 10.3, *)) {
+    if (UrlHasAppStoreScheme(URL)) {
+      [self showAlertAndLaunchAppStoreURL:URL];
+      return YES;
+    }
+  } else {
+    // Prior to iOS 10.3, iOS does not prompt user when facetime: and
+    // facetime-audio: URL schemes are opened, so Chrome needs to present an
+    // alert before placing a phone call.
+    if (UrlHasPhoneCallScheme(URL)) {
+      [self showAlertAndLaunchPhoneCallOrFacetimeURL:URL];
+      return YES;
+    }
+    // Prior to iOS 10.3, Chrome prompts user with an alert before opening
+    // App Store when user did not tap on any links and an iTunes app URL is
+    // opened. This maintains parity with Safari in pre-10.3 environment.
+    if (!linkTapped && UrlHasAppStoreScheme(URL)) {
+      [self showAlertAndLaunchAppStoreURL:URL];
+      return YES;
+    }
+  }
+  // Replaces |URL| with a rewritten URL if it is of mailto: scheme.
+  if (URL.SchemeIs(url::kMailToScheme)) {
+    [self showAlertIfNeededAndLaunchMailtoURL:URL];
+    return true;
+  }
+// If the following call returns YES, an application is about to be
+// launched and Chrome will go into the background now.
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+  // TODO(crbug.com/774736): This method needs to be converted to an
+  // asynchronous call so that the call below can be replaced with
+  // |openURL:options:completionHandler:|.
+  return [[UIApplication sharedApplication] openURL:net::NSURLWithGURL(URL)];
+#pragma clang diagnostic pop
+}
+
+- (void)appLauncherTabHelper:(AppLauncherTabHelper*)tabHelper
+    showAlertOfRepeatedLaunchesWithCompletionHandler:
+        (ProceduralBlockWithBool)completionHandler {
+  NSString* message =
+      l10n_util::GetNSString(IDS_IOS_OPEN_REPEATEDLY_ANOTHER_APP);
+  NSString* allowLaunchTitle =
+      l10n_util::GetNSString(IDS_IOS_OPEN_REPEATEDLY_ANOTHER_APP_ALLOW);
+  NSString* blockLaunchTitle =
+      l10n_util::GetNSString(IDS_IOS_OPEN_REPEATEDLY_ANOTHER_APP_BLOCK);
+  [self showAlertWithMessage:message
+           acceptActionTitle:allowLaunchTitle
+           rejectActionTitle:blockLaunchTitle
+           completionHandler:^(BOOL userAllowed) {
+             UMA_HISTOGRAM_BOOLEAN("IOS.RepeatedExternalAppPromptResponse",
+                                   userAllowed);
+             completionHandler(userAllowed);
+           }];
+}
+
+@end
diff --git a/ios/chrome/browser/ui/app_launcher/app_launcher_coordinator_unittest.mm b/ios/chrome/browser/ui/app_launcher/app_launcher_coordinator_unittest.mm
new file mode 100644
index 0000000..59fc639
--- /dev/null
+++ b/ios/chrome/browser/ui/app_launcher/app_launcher_coordinator_unittest.mm
@@ -0,0 +1,100 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/chrome/browser/ui/app_launcher/app_launcher_coordinator.h"
+
+#import <UIKit/UIKit.h>
+
+#include "base/mac/foundation_util.h"
+#include "ios/chrome/grit/ios_strings.h"
+#import "ios/chrome/test/scoped_key_window.h"
+#import "ios/web/public/test/fakes/test_web_state.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#import "testing/gtest_mac.h"
+#include "testing/platform_test.h"
+#import "third_party/ocmock/OCMock/OCMock.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "url/gurl.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+// Test fixture for AppLauncherCoordinator class.
+class AppLauncherCoordinatorTest : public PlatformTest {
+ protected:
+  AppLauncherCoordinatorTest() {
+    base_view_controller_ = [[UIViewController alloc] init];
+    [scoped_key_window_.Get() setRootViewController:base_view_controller_];
+    coordinator_ = [[AppLauncherCoordinator alloc]
+        initWithBaseViewController:base_view_controller_];
+    application_ = OCMClassMock([UIApplication class]);
+    OCMStub([application_ sharedApplication]).andReturn(application_);
+  }
+
+  UIViewController* base_view_controller_ = nil;
+  ScopedKeyWindow scoped_key_window_;
+  AppLauncherCoordinator* coordinator_ = nil;
+  id application_ = nil;
+};
+
+// Tests that an empty URL does not prompt user and does not launch application.
+TEST_F(AppLauncherCoordinatorTest, EmptyUrl) {
+  BOOL app_exists = [coordinator_ appLauncherTabHelper:nullptr
+                                      launchAppWithURL:GURL::EmptyGURL()
+                                            linkTapped:NO];
+  EXPECT_FALSE(app_exists);
+  EXPECT_EQ(nil, base_view_controller_.presentedViewController);
+}
+
+// Tests that an invalid URL does not launch application.
+TEST_F(AppLauncherCoordinatorTest, InvalidUrl) {
+  BOOL app_exists = [coordinator_ appLauncherTabHelper:nullptr
+                                      launchAppWithURL:GURL("invalid")
+                                            linkTapped:NO];
+  EXPECT_FALSE(app_exists);
+}
+
+// Tests that an itunes URL shows an alert.
+TEST_F(AppLauncherCoordinatorTest, ItmsUrlShowsAlert) {
+  BOOL app_exists = [coordinator_ appLauncherTabHelper:nullptr
+                                      launchAppWithURL:GURL("itms://1234")
+                                            linkTapped:NO];
+  EXPECT_TRUE(app_exists);
+  EXPECT_TRUE([base_view_controller_.presentedViewController
+      isKindOfClass:[UIAlertController class]]);
+  UIAlertController* alert_controller =
+      base::mac::ObjCCastStrict<UIAlertController>(
+          base_view_controller_.presentedViewController);
+  EXPECT_NSEQ(l10n_util::GetNSString(IDS_IOS_OPEN_IN_ANOTHER_APP),
+              alert_controller.message);
+}
+
+// Tests that an app URL attempts to launch the application.
+TEST_F(AppLauncherCoordinatorTest, AppUrlLaunchesApp) {
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+  OCMExpect([application_ openURL:[NSURL URLWithString:@"some-app://1234"]]);
+#pragma clang diagnostic pop
+  [coordinator_ appLauncherTabHelper:nullptr
+                    launchAppWithURL:GURL("some-app://1234")
+                          linkTapped:NO];
+  [application_ verify];
+}
+
+// Tests that |-appLauncherTabHelper:launchAppWithURL:linkTapped:| returns NO
+// if there is no application that corresponds to a given URL.
+TEST_F(AppLauncherCoordinatorTest, NoApplicationForUrl) {
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+  OCMStub(
+      [application_ openURL:[NSURL URLWithString:@"no-app-installed://1234"]])
+      .andReturn(NO);
+#pragma clang diagnostic pop
+  BOOL app_exists =
+      [coordinator_ appLauncherTabHelper:nullptr
+                        launchAppWithURL:GURL("no-app-installed://1234")
+                              linkTapped:NO];
+  EXPECT_FALSE(app_exists);
+}
diff --git a/ios/chrome/browser/web/external_app_launcher_util.h b/ios/chrome/browser/ui/app_launcher/app_launcher_util.h
similarity index 81%
rename from ios/chrome/browser/web/external_app_launcher_util.h
rename to ios/chrome/browser/ui/app_launcher/app_launcher_util.h
index ad7adb4..6e17b1f 100644
--- a/ios/chrome/browser/web/external_app_launcher_util.h
+++ b/ios/chrome/browser/ui/app_launcher/app_launcher_util.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 IOS_CHROME_BROWSER_WEB_EXTERNAL_APP_LAUNCHER_UTIL_H_
-#define IOS_CHROME_BROWSER_WEB_EXTERNAL_APP_LAUNCHER_UTIL_H_
+#ifndef IOS_CHROME_BROWSER_UI_APP_LAUNCHER_APP_LAUNCHER_UTIL_H_
+#define IOS_CHROME_BROWSER_UI_APP_LAUNCHER_APP_LAUNCHER_UTIL_H_
 
 #import <Foundation/Foundation.h>
 
@@ -25,4 +25,4 @@
 // Returns a string to be used as the label for the prompt's action button.
 NSString* GetPromptActionString(NSString* scheme);
 
-#endif  // IOS_CHROME_BROWSER_WEB_EXTERNAL_APP_LAUNCHER_UTIL_H_
+#endif  // IOS_CHROME_BROWSER_UI_APP_LAUNCHER_APP_LAUNCHER_UTIL_H_
diff --git a/ios/chrome/browser/web/external_app_launcher_util.mm b/ios/chrome/browser/ui/app_launcher/app_launcher_util.mm
similarity index 96%
rename from ios/chrome/browser/web/external_app_launcher_util.mm
rename to ios/chrome/browser/ui/app_launcher/app_launcher_util.mm
index 814615e..2dc3ffa1 100644
--- a/ios/chrome/browser/web/external_app_launcher_util.mm
+++ b/ios/chrome/browser/ui/app_launcher/app_launcher_util.mm
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#import "ios/chrome/browser/web/external_app_launcher_util.h"
+#import "ios/chrome/browser/ui/app_launcher/app_launcher_util.h"
 
 #include "base/strings/sys_string_conversions.h"
 #include "ios/chrome/grit/ios_strings.h"
diff --git a/ios/chrome/browser/web/external_app_launcher_util_unittest.mm b/ios/chrome/browser/ui/app_launcher/app_launcher_util_unittest.mm
similarity index 95%
rename from ios/chrome/browser/web/external_app_launcher_util_unittest.mm
rename to ios/chrome/browser/ui/app_launcher/app_launcher_util_unittest.mm
index 329fcd0e..5c51d691 100644
--- a/ios/chrome/browser/web/external_app_launcher_util_unittest.mm
+++ b/ios/chrome/browser/ui/app_launcher/app_launcher_util_unittest.mm
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#import "ios/chrome/browser/web/external_app_launcher_util.h"
+#import "ios/chrome/browser/ui/app_launcher/app_launcher_util.h"
 
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/gtest_mac.h"
diff --git a/ios/chrome/browser/ui/external_app/open_mail_handler_view_controller.h b/ios/chrome/browser/ui/app_launcher/open_mail_handler_view_controller.h
similarity index 87%
rename from ios/chrome/browser/ui/external_app/open_mail_handler_view_controller.h
rename to ios/chrome/browser/ui/app_launcher/open_mail_handler_view_controller.h
index 19ed893..77626377 100644
--- a/ios/chrome/browser/ui/external_app/open_mail_handler_view_controller.h
+++ b/ios/chrome/browser/ui/app_launcher/open_mail_handler_view_controller.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 IOS_CHROME_BROWSER_UI_EXTERNAL_APP_OPEN_MAIL_HANDLER_VIEW_CONTROLLER_H_
-#define IOS_CHROME_BROWSER_UI_EXTERNAL_APP_OPEN_MAIL_HANDLER_VIEW_CONTROLLER_H_
+#ifndef IOS_CHROME_BROWSER_UI_APP_LAUNCHER_OPEN_MAIL_HANDLER_VIEW_CONTROLLER_H_
+#define IOS_CHROME_BROWSER_UI_APP_LAUNCHER_OPEN_MAIL_HANDLER_VIEW_CONTROLLER_H_
 
 #include "ios/chrome/browser/ui/collection_view/collection_view_controller.h"
 
@@ -34,4 +34,4 @@
 
 @end
 
-#endif  // IOS_CHROME_BROWSER_UI_EXTERNAL_APP_OPEN_MAIL_HANDLER_VIEW_CONTROLLER_H_
+#endif  // IOS_CHROME_BROWSER_UI_APP_LAUNCHER_OPEN_MAIL_HANDLER_VIEW_CONTROLLER_H_
diff --git a/ios/chrome/browser/ui/external_app/open_mail_handler_view_controller.mm b/ios/chrome/browser/ui/app_launcher/open_mail_handler_view_controller.mm
similarity index 98%
rename from ios/chrome/browser/ui/external_app/open_mail_handler_view_controller.mm
rename to ios/chrome/browser/ui/app_launcher/open_mail_handler_view_controller.mm
index f5014a9..6ebb3db 100644
--- a/ios/chrome/browser/ui/external_app/open_mail_handler_view_controller.mm
+++ b/ios/chrome/browser/ui/app_launcher/open_mail_handler_view_controller.mm
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#import "ios/chrome/browser/ui/external_app/open_mail_handler_view_controller.h"
+#import "ios/chrome/browser/ui/app_launcher/open_mail_handler_view_controller.h"
 
 #import <UIKit/UIKit.h>
 
diff --git a/ios/chrome/browser/ui/external_app/open_mail_handler_view_controller_unittest.mm b/ios/chrome/browser/ui/app_launcher/open_mail_handler_view_controller_unittest.mm
similarity index 98%
rename from ios/chrome/browser/ui/external_app/open_mail_handler_view_controller_unittest.mm
rename to ios/chrome/browser/ui/app_launcher/open_mail_handler_view_controller_unittest.mm
index d9c2f1c..7970b35d 100644
--- a/ios/chrome/browser/ui/external_app/open_mail_handler_view_controller_unittest.mm
+++ b/ios/chrome/browser/ui/app_launcher/open_mail_handler_view_controller_unittest.mm
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#import "ios/chrome/browser/ui/external_app/open_mail_handler_view_controller.h"
+#import "ios/chrome/browser/ui/app_launcher/open_mail_handler_view_controller.h"
 
 #include "base/mac/foundation_util.h"
 #import "ios/chrome/browser/ui/collection_view/cells/collection_view_switch_item.h"
diff --git a/ios/chrome/browser/ui/browser_view_controller.mm b/ios/chrome/browser/ui/browser_view_controller.mm
index 1b3c59c..82900c6e 100644
--- a/ios/chrome/browser/ui/browser_view_controller.mm
+++ b/ios/chrome/browser/ui/browser_view_controller.mm
@@ -55,6 +55,7 @@
 #include "components/strings/grit/components_strings.h"
 #include "components/toolbar/toolbar_model_impl.h"
 #include "ios/chrome/app/tests_hook.h"
+#import "ios/chrome/browser/app_launcher/app_launcher_tab_helper.h"
 #include "ios/chrome/browser/bookmarks/bookmark_model_factory.h"
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
 #include "ios/chrome/browser/chrome_url_constants.h"
@@ -114,6 +115,7 @@
 #import "ios/chrome/browser/ui/activity_services/requirements/activity_service_presentation.h"
 #import "ios/chrome/browser/ui/alert_coordinator/alert_coordinator.h"
 #import "ios/chrome/browser/ui/alert_coordinator/repost_form_coordinator.h"
+#import "ios/chrome/browser/ui/app_launcher/app_launcher_coordinator.h"
 #import "ios/chrome/browser/ui/authentication/re_signin_infobar_delegate.h"
 #import "ios/chrome/browser/ui/background_generator.h"
 #import "ios/chrome/browser/ui/bookmarks/bookmark_interaction_controller.h"
@@ -216,6 +218,7 @@
 #include "ios/chrome/browser/upgrade/upgrade_center.h"
 #import "ios/chrome/browser/web/blocked_popup_tab_helper.h"
 #import "ios/chrome/browser/web/error_page_content.h"
+#import "ios/chrome/browser/web/external_apps_launch_policy_decider.h"
 #import "ios/chrome/browser/web/load_timing_tab_helper.h"
 #import "ios/chrome/browser/web/page_placeholder_tab_helper.h"
 #import "ios/chrome/browser/web/passkit_dialog_provider.h"
@@ -604,6 +607,9 @@
   // Coordinator for the PassKit UI presentation.
   PassKitCoordinator* _passKitCoordinator;
 
+  // Coordinator for UI related to launching external apps.
+  AppLauncherCoordinator* _appLauncherCoordinator;
+
   // Fake status bar view used to blend the toolbar into the status bar.
   UIView* _fakeStatusBarView;
 
@@ -987,6 +993,9 @@
     _passKitCoordinator =
         [[PassKitCoordinator alloc] initWithBaseViewController:self];
 
+    _appLauncherCoordinator =
+        [[AppLauncherCoordinator alloc] initWithBaseViewController:self];
+
     _javaScriptDialogPresenter.reset(
         new JavaScriptDialogPresenterImpl(_dialogPresenter));
     _webStateDelegate.reset(new web::WebStateDelegateBridge(self));
@@ -2859,6 +2868,9 @@
   NetExportTabHelper::CreateForWebState(tab.webState, self);
   CaptivePortalDetectorTabHelper::CreateForWebState(tab.webState, self);
   PassKitTabHelper::CreateForWebState(tab.webState, _passKitCoordinator);
+  AppLauncherTabHelper::CreateForWebState(
+      tab.webState, [[ExternalAppsLaunchPolicyDecider alloc] init],
+      _appLauncherCoordinator);
 
   // The language detection helper accepts a callback from the translate
   // client, so must be created after it.
diff --git a/ios/chrome/browser/ui/external_app/BUILD.gn b/ios/chrome/browser/ui/external_app/BUILD.gn
deleted file mode 100644
index 9a6c36e..0000000
--- a/ios/chrome/browser/ui/external_app/BUILD.gn
+++ /dev/null
@@ -1,40 +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.
-
-import("//build/config/ios/rules.gni")
-
-source_set("external_app") {
-  configs += [ "//build/config/compiler:enable_arc" ]
-  sources = [
-    "open_mail_handler_view_controller.h",
-    "open_mail_handler_view_controller.mm",
-  ]
-  deps = [
-    "//base",
-    "//ios/chrome/app/strings:ios_strings_grit",
-    "//ios/chrome/browser/ui/collection_view:collection_view",
-    "//ios/chrome/browser/web",
-    "//ui/base:base",
-    "//url:url",
-  ]
-}
-
-source_set("unit_tests") {
-  configs += [ "//build/config/compiler:enable_arc" ]
-  testonly = true
-  sources = [
-    "open_mail_handler_view_controller_unittest.mm",
-  ]
-  deps = [
-    ":external_app",
-    "//base",
-    "//ios/chrome/app/strings:ios_strings_grit",
-    "//ios/chrome/browser/ui/collection_view:test_support",
-    "//ios/chrome/browser/ui/collection_view/cells:cells",
-    "//ios/chrome/browser/web",
-    "//ios/third_party/material_components_ios:material_components_ios",
-    "//testing/gtest",
-    "//third_party/ocmock",
-  ]
-}
diff --git a/ios/chrome/browser/web/BUILD.gn b/ios/chrome/browser/web/BUILD.gn
index bc34096..06b9523 100644
--- a/ios/chrome/browser/web/BUILD.gn
+++ b/ios/chrome/browser/web/BUILD.gn
@@ -146,10 +146,6 @@
     "error_page_content.mm",
     "error_page_generator.h",
     "error_page_generator.mm",
-    "external_app_launcher_tab_helper.h",
-    "external_app_launcher_tab_helper.mm",
-    "external_app_launcher_util.h",
-    "external_app_launcher_util.mm",
     "external_app_launching_state.h",
     "external_app_launching_state.mm",
     "external_apps_launch_policy_decider.h",
@@ -184,12 +180,10 @@
     "//ios/chrome/browser/tabs",
     "//ios/chrome/browser/ui:ui_util",
     "//ios/chrome/browser/ui/commands",
-    "//ios/chrome/browser/ui/external_app",
     "//ios/chrome/browser/ui/static_content",
     "//ios/chrome/browser/web",
     "//ios/public/provider/chrome/browser",
     "//ios/public/provider/chrome/browser/voice",
-    "//ios/third_party/material_components_ios",
     "//ios/web",
     "//ios/web/public",
     "//net",
@@ -232,7 +226,6 @@
     "blocked_popup_tab_helper_unittest.mm",
     "chrome_web_client_unittest.mm",
     "error_page_generator_unittest.mm",
-    "external_app_launcher_util_unittest.mm",
     "external_app_launching_state_unittest.mm",
     "external_apps_launch_policy_decider_unittest.mm",
   ]
diff --git a/ios/chrome/browser/web/external_app_launcher_tab_helper.h b/ios/chrome/browser/web/external_app_launcher_tab_helper.h
deleted file mode 100644
index a08b3ca..0000000
--- a/ios/chrome/browser/web/external_app_launcher_tab_helper.h
+++ /dev/null
@@ -1,57 +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.
-
-#ifndef IOS_CHROME_BROWSER_WEB_EXTERNAL_APP_LAUNCHER_TAB_HELPER_H_
-#define IOS_CHROME_BROWSER_WEB_EXTERNAL_APP_LAUNCHER_TAB_HELPER_H_
-
-#include "base/macros.h"
-#import "ios/web/public/web_state/web_state_user_data.h"
-
-@class ExternalAppsLaunchPolicyDecider;
-class GURL;
-
-// A customized external app launcher that optionally shows a modal
-// confirmation dialog before switching context to an external application.
-class ExternalAppLauncherTabHelper
-    : public web::WebStateUserData<ExternalAppLauncherTabHelper> {
- public:
-  ~ExternalAppLauncherTabHelper() override;
-
-  // Requests to open URL in an external application.
-  // The method checks if the application for |url| has been opened repeatedly
-  // by the |source_page_url| page in a short time frame, in that case a prompt
-  // will appear to the user with an option to block the application from
-  // launching. Then the method also checks for user interaction and for schemes
-  // that require special handling (eg. facetime, mailto) and may present the
-  // user with a confirmation dialog to open the application. If there is no
-  // such application available or it's not possible to open the application the
-  // method returns NO.
-  bool RequestToOpenUrl(const GURL& url,
-                        const GURL& source_page_url,
-                        bool link_clicked);
-
- private:
-  friend class web::WebStateUserData<ExternalAppLauncherTabHelper>;
-  explicit ExternalAppLauncherTabHelper(web::WebState* web_state);
-
-  // Handles launching an external app for |url| when there are repeated
-  // attempts by |source_page_url|. |allowed| indicates whether the user has
-  // explicitly allowed the external app to launch.
-  void HandleRepeatedAttemptsToLaunch(const GURL& url,
-                                      const GURL& source_page_url,
-                                      bool allowed);
-
-  // Used to check for repeated launches and provide policy for launching apps.
-  ExternalAppsLaunchPolicyDecider* policy_decider_ = nil;
-
-  // Returns whether there is a prompt shown by |RequestToOpenUrl| or not.
-  bool is_prompt_active_ = false;
-
-  // Must be last member to ensure it is destroyed last.
-  base::WeakPtrFactory<ExternalAppLauncherTabHelper> weak_factory_;
-
-  DISALLOW_COPY_AND_ASSIGN(ExternalAppLauncherTabHelper);
-};
-
-#endif  // IOS_CHROME_BROWSER_WEB_EXTERNAL_APP_LAUNCHER_TAB_HELPER_H_
diff --git a/ios/chrome/browser/web/external_app_launcher_tab_helper.mm b/ios/chrome/browser/web/external_app_launcher_tab_helper.mm
deleted file mode 100644
index ab5ff97..0000000
--- a/ios/chrome/browser/web/external_app_launcher_tab_helper.mm
+++ /dev/null
@@ -1,264 +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.
-
-#import "ios/chrome/browser/web/external_app_launcher_tab_helper.h"
-
-#include "base/callback.h"
-#include "base/logging.h"
-#include "base/metrics/histogram_macros.h"
-#include "components/strings/grit/components_strings.h"
-#import "ios/chrome/browser/ui/external_app/open_mail_handler_view_controller.h"
-#import "ios/chrome/browser/web/external_app_launcher_util.h"
-#import "ios/chrome/browser/web/external_apps_launch_policy_decider.h"
-#import "ios/chrome/browser/web/mailto_handler.h"
-#import "ios/chrome/browser/web/mailto_handler_manager.h"
-#include "ios/chrome/grit/ios_strings.h"
-#include "ios/third_party/material_components_ios/src/components/BottomSheet/src/MDCBottomSheetController.h"
-#import "net/base/mac/url_conversions.h"
-#include "ui/base/l10n/l10n_util.h"
-#include "url/gurl.h"
-#include "url/url_constants.h"
-
-#if !defined(__has_feature) || !__has_feature(objc_arc)
-#error "This file requires ARC support."
-#endif
-
-DEFINE_WEB_STATE_USER_DATA_KEY(ExternalAppLauncherTabHelper);
-
-namespace {
-
-// Launches the mail client app represented by |handler| and records metrics.
-void LaunchMailClientApp(const GURL& url, MailtoHandler* handler) {
-  NSString* launch_url = [handler rewriteMailtoURL:url];
-  UMA_HISTOGRAM_BOOLEAN("IOS.MailtoURLRewritten", launch_url != nil);
-  NSURL* url_to_open = launch_url.length ? [NSURL URLWithString:launch_url]
-                                         : net::NSURLWithGURL(url);
-  if (@available(iOS 10, *)) {
-    [[UIApplication sharedApplication] openURL:url_to_open
-                                       options:@{}
-                             completionHandler:nil];
-  }
-#if !defined(__IPHONE_10_0) || __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_10_0
-  else {
-    [[UIApplication sharedApplication] openURL:url_to_open];
-  }
-#endif
-}
-
-// Shows a prompt for the user to choose which mail client app to use to handle
-// a mailto:// URL.
-void PromptForMailClientWithUrl(const GURL& url,
-                                MailtoHandlerManager* manager) {
-  GURL copied_url_to_open = url;
-  OpenMailHandlerViewController* mail_handler_chooser =
-      [[OpenMailHandlerViewController alloc]
-          initWithManager:manager
-          selectedHandler:^(MailtoHandler* _Nonnull handler) {
-            LaunchMailClientApp(copied_url_to_open, handler);
-          }];
-  MDCBottomSheetController* bottom_sheet = [[MDCBottomSheetController alloc]
-      initWithContentViewController:mail_handler_chooser];
-  [[[[UIApplication sharedApplication] keyWindow] rootViewController]
-      presentViewController:bottom_sheet
-                   animated:YES
-                 completion:nil];
-}
-
-// Presents an alert controller on the root view controller with |prompt| as
-// body text, |accept label| and |reject label| as button labels, and
-// a non null |responseHandler| that takes a boolean to handle user response.
-void ShowExternalAppLauncherPrompt(NSString* prompt,
-                                   NSString* accept_label,
-                                   NSString* reject_label,
-                                   base::OnceCallback<void(bool)> callback) {
-  __block base::OnceCallback<void(bool)> block_callback = std::move(callback);
-  UIAlertController* alert_controller =
-      [UIAlertController alertControllerWithTitle:nil
-                                          message:prompt
-                                   preferredStyle:UIAlertControllerStyleAlert];
-  UIAlertAction* accept_action =
-      [UIAlertAction actionWithTitle:accept_label
-                               style:UIAlertActionStyleDefault
-                             handler:^(UIAlertAction* action) {
-                               std::move(block_callback).Run(true);
-                             }];
-  UIAlertAction* reject_action =
-      [UIAlertAction actionWithTitle:reject_label
-                               style:UIAlertActionStyleCancel
-                             handler:^(UIAlertAction* action) {
-                               std::move(block_callback).Run(false);
-                             }];
-  [alert_controller addAction:reject_action];
-  [alert_controller addAction:accept_action];
-
-  [[[[UIApplication sharedApplication] keyWindow] rootViewController]
-      presentViewController:alert_controller
-                   animated:YES
-                 completion:nil];
-}
-
-// Launches external app identified by |url| if |accept| is true.
-void LaunchExternalApp(NSURL* url, bool accept) {
-  UMA_HISTOGRAM_BOOLEAN("Tab.ExternalApplicationOpened", accept);
-  if (accept) {
-    [[UIApplication sharedApplication] openURL:url
-                                       options:@{}
-                             completionHandler:nil];
-  }
-}
-
-// Presents an alert controller with |prompt| and |open_label| as button label
-// on the root view controller before launching an external app identified by
-// |url|.
-void OpenExternalAppWithUrl(NSURL* url,
-                            NSString* prompt,
-                            NSString* open_label) {
-  ShowExternalAppLauncherPrompt(
-      prompt, /*accept_label=*/open_label,
-      /*reject_label=*/l10n_util::GetNSString(IDS_CANCEL),
-      base::BindOnce(&LaunchExternalApp, url));
-}
-
-// Opens URL in an external application if possible (optionally after
-// confirming via dialog in case that user didn't interact using
-// |link_clicked| or if the external application is face time) or returns NO
-// if there is no such application available.
-bool OpenUrl(const GURL& gurl, bool link_clicked) {
-  // Don't open external application if chrome is not active.
-  if ([[UIApplication sharedApplication] applicationState] !=
-      UIApplicationStateActive) {
-    return NO;
-  }
-
-  NSURL* url = net::NSURLWithGURL(gurl);
-  if (@available(iOS 10.3, *)) {
-    if (UrlHasAppStoreScheme(gurl)) {
-      NSString* prompt = l10n_util::GetNSString(IDS_IOS_OPEN_IN_ANOTHER_APP);
-      NSString* open_label =
-          l10n_util::GetNSString(IDS_IOS_APP_LAUNCHER_OPEN_APP_BUTTON_LABEL);
-      OpenExternalAppWithUrl(url, prompt, open_label);
-      return true;
-    }
-  } else {
-    // Prior to iOS 10.3, iOS does not prompt user when facetime: and
-    // facetime-audio: URL schemes are opened, so Chrome needs to present an
-    // alert before placing a phone call.
-    if (UrlHasPhoneCallScheme(gurl)) {
-      OpenExternalAppWithUrl(
-          url, /*prompt=*/GetFormattedAbsoluteUrlWithSchemeRemoved(url),
-          /*open_label=*/GetPromptActionString(url.scheme));
-      return true;
-    }
-    // Prior to iOS 10.3, Chrome prompts user with an alert before opening
-    // App Store when user did not tap on any links and an iTunes app URL is
-    // opened. This maintains parity with Safari in pre-10.3 environment.
-    if (!link_clicked && UrlHasAppStoreScheme(gurl)) {
-      NSString* prompt = l10n_util::GetNSString(IDS_IOS_OPEN_IN_ANOTHER_APP);
-      NSString* open_label =
-          l10n_util::GetNSString(IDS_IOS_APP_LAUNCHER_OPEN_APP_BUTTON_LABEL);
-      OpenExternalAppWithUrl(url, prompt, open_label);
-      return true;
-    }
-  }
-
-  // Replaces |url| with a rewritten URL if it is of mailto: scheme.
-  if (gurl.SchemeIs(url::kMailToScheme)) {
-    MailtoHandlerManager* manager =
-        [MailtoHandlerManager mailtoHandlerManagerWithStandardHandlers];
-    NSString* handler_id = manager.defaultHandlerID;
-    if (!handler_id) {
-      PromptForMailClientWithUrl(gurl, manager);
-      return true;
-    }
-    MailtoHandler* handler = [manager defaultHandlerByID:handler_id];
-    LaunchMailClientApp(gurl, handler);
-    return true;
-  }
-
-// If the following call returns YES, an external application is about to be
-// launched and Chrome will go into the background now.
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wdeprecated-declarations"
-  // TODO(crbug.com/774736): This call still needs to be
-  // updated. It's heavily nested so some refactoring is needed.
-  return [[UIApplication sharedApplication] openURL:url];
-#pragma clang diagnostic pop
-}
-
-}  // namespace
-
-ExternalAppLauncherTabHelper::ExternalAppLauncherTabHelper(
-    web::WebState* web_state)
-    : policy_decider_([[ExternalAppsLaunchPolicyDecider alloc] init]),
-      weak_factory_(this) {}
-
-ExternalAppLauncherTabHelper::~ExternalAppLauncherTabHelper() = default;
-
-void ExternalAppLauncherTabHelper::HandleRepeatedAttemptsToLaunch(
-    const GURL& url,
-    const GURL& source_page_url,
-    bool allowed) {
-  if (allowed) {
-    // By confirming that user wants to launch the
-    // application, there is no need to check for
-    // |link_clicked|.
-    OpenUrl(url, /*link_clicked=*/true);
-  } else {
-    // TODO(crbug.com/674649): Once non modal
-    // dialogs are implemented, update this to
-    // always prompt instead of blocking the app.
-    [policy_decider_ blockLaunchingAppURL:url
-                        fromSourcePageURL:source_page_url];
-  }
-  UMA_HISTOGRAM_BOOLEAN("IOS.RepeatedExternalAppPromptResponse", allowed);
-  is_prompt_active_ = false;
-}
-
-bool ExternalAppLauncherTabHelper::RequestToOpenUrl(const GURL& url,
-                                                    const GURL& source_page_url,
-                                                    bool link_clicked) {
-  if (!url.is_valid() || !url.has_scheme())
-    return false;
-
-  // Don't open external application if chrome is not active.
-  if ([[UIApplication sharedApplication] applicationState] !=
-      UIApplicationStateActive) {
-    return false;
-  }
-
-  // Don't try to open external application if a prompt is already active.
-  if (is_prompt_active_)
-    return false;
-
-  [policy_decider_ didRequestLaunchExternalAppURL:url
-                                fromSourcePageURL:source_page_url];
-  ExternalAppLaunchPolicy policy =
-      [policy_decider_ launchPolicyForURL:url
-                        fromSourcePageURL:source_page_url];
-  switch (policy) {
-    case ExternalAppLaunchPolicyBlock: {
-      return false;
-    }
-    case ExternalAppLaunchPolicyAllow: {
-      return OpenUrl(url, link_clicked);
-    }
-    case ExternalAppLaunchPolicyPrompt: {
-      is_prompt_active_ = true;
-      NSString* prompt_body =
-          l10n_util::GetNSString(IDS_IOS_OPEN_REPEATEDLY_ANOTHER_APP);
-      NSString* allow_label =
-          l10n_util::GetNSString(IDS_IOS_OPEN_REPEATEDLY_ANOTHER_APP_ALLOW);
-      NSString* block_label =
-          l10n_util::GetNSString(IDS_IOS_OPEN_REPEATEDLY_ANOTHER_APP_BLOCK);
-
-      base::OnceCallback<void(bool)> callback = base::BindOnce(
-          &ExternalAppLauncherTabHelper::HandleRepeatedAttemptsToLaunch,
-          weak_factory_.GetWeakPtr(), url, source_page_url);
-
-      ShowExternalAppLauncherPrompt(prompt_body, allow_label, block_label,
-                                    std::move(callback));
-      return true;
-    }
-  }
-}
diff --git a/ios/chrome/test/BUILD.gn b/ios/chrome/test/BUILD.gn
index 5195beb..dd83e2c 100644
--- a/ios/chrome/test/BUILD.gn
+++ b/ios/chrome/test/BUILD.gn
@@ -135,6 +135,7 @@
     "//ios/chrome/app/spotlight:unit_tests",
     "//ios/chrome/app/startup:unit_tests",
     "//ios/chrome/browser:unit_tests",
+    "//ios/chrome/browser/app_launcher:unit_tests",
     "//ios/chrome/browser/autofill:unit_tests",
     "//ios/chrome/browser/browser_state:unit_tests",
     "//ios/chrome/browser/browsing_data:unit_tests",
@@ -169,6 +170,7 @@
     "//ios/chrome/browser/ui:unit_tests",
     "//ios/chrome/browser/ui/activity_services:unit_tests",
     "//ios/chrome/browser/ui/alert_coordinator:unit_tests",
+    "//ios/chrome/browser/ui/app_launcher:unit_tests",
     "//ios/chrome/browser/ui/authentication:unit_tests",
     "//ios/chrome/browser/ui/autofill/cells:unit_tests",
     "//ios/chrome/browser/ui/bookmarks:unit_tests",
@@ -189,7 +191,6 @@
     "//ios/chrome/browser/ui/dialogs:unit_tests_internal",
     "//ios/chrome/browser/ui/download:unit_tests",
     "//ios/chrome/browser/ui/elements:unit_tests",
-    "//ios/chrome/browser/ui/external_app:unit_tests",
     "//ios/chrome/browser/ui/external_search:unit_tests",
     "//ios/chrome/browser/ui/fancy_ui:unit_tests",
     "//ios/chrome/browser/ui/first_run:unit_tests",
diff --git a/media/base/android/stream_texture_wrapper.h b/media/base/android/stream_texture_wrapper.h
index ee092cd1..78ac8388 100644
--- a/media/base/android/stream_texture_wrapper.h
+++ b/media/base/android/stream_texture_wrapper.h
@@ -41,6 +41,10 @@
   virtual void ForwardStreamTextureForSurfaceRequest(
       const base::UnguessableToken& request_token) = 0;
 
+  // Clears the |received_frame_cb| passed in Initialize().
+  // Should be safe to call from any thread.
+  virtual void ClearReceivedFrameCBOnAnyThread() = 0;
+
   struct Deleter {
     inline void operator()(StreamTextureWrapper* ptr) const { ptr->Destroy(); }
   };
diff --git a/net/http/transport_security_state_static.json b/net/http/transport_security_state_static.json
index 26d8c0d..5a6fea7 100644
--- a/net/http/transport_security_state_static.json
+++ b/net/http/transport_security_state_static.json
@@ -44254,6 +44254,7 @@
     { "name": "www.hyatt.com", "policy": "custom", "mode": "force-https", "include_subdomains": true },
     { "name": "connect.facebook.net", "policy": "custom", "mode": "force-https", "include_subdomains": true },
     { "name": "bing.com", "policy": "custom", "mode": "force-https", "include_subdomains": true },
+    { "name": "fan.gov", "policy": "custom", "mode": "force-https", "include_subdomains": true },
     // No subdomains
     { "name": "wordpress.com", "policy": "custom", "mode": "force-https", "include_subdomains": false },
     { "name": "www.wordpress.com", "policy": "custom", "mode": "force-https", "include_subdomains": false },
@@ -44267,6 +44268,7 @@
     // be handled automatically: github.com/chromium/hstspreload.org/issues/43
     // IPv6
     { "name": "ipv6only.network", "policy": "custom", "mode": "force-https", "include_subdomains": true },
+    { "name": "trinity.fr.eu.org", "policy": "custom", "mode": "force-https", "include_subdomains": true },
     // Expect-CT/Expect-Staple
     {
       "name": "crt.sh", "policy": "custom",
@@ -44454,6 +44456,7 @@
     { "name": "safecar.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
     { "name": "famep.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
     { "name": "nationalmall.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
+    { "name": "mytuleap.com", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
     // END OF ETLD-OWNER REQUESTED ENTRIES
 
     // To avoid trailing comma changes from showing up in diffs, we place a
diff --git a/net/quic/core/quic_framer.cc b/net/quic/core/quic_framer.cc
index 624f1f6..6df508b7 100644
--- a/net/quic/core/quic_framer.cc
+++ b/net/quic/core/quic_framer.cc
@@ -65,34 +65,34 @@
 
 // Masks to determine if the frame type is a special use
 // and for specific special frame types.
-const uint8_t kQuicFrameTypeSpecialMask = 0xE0;  // 0b 11100000
-const uint8_t kQuicFrameTypeStreamMask_Pre40 = 0x80;
-const uint8_t kQuicFrameTypeStreamMask = 0xC0;
-const uint8_t kQuicFrameTypeAckMask_Pre40 = 0x40;
-const uint8_t kQuicFrameTypeAckMask = 0xA0;
+const uint8_t kQuicFrameTypeSpecialMask = 0b11100000;
+const uint8_t kQuicFrameTypeStreamMask_Pre40 = 0b10000000;
+const uint8_t kQuicFrameTypeStreamMask = 0b11000000;
+const uint8_t kQuicFrameTypeAckMask_Pre40 = 0b01000000;
+const uint8_t kQuicFrameTypeAckMask = 0b10100000;
 
 // Stream type format is 11FSSOOD.
 // Stream frame relative shifts and masks for interpreting the stream flags.
 // StreamID may be 1, 2, 3, or 4 bytes.
 const uint8_t kQuicStreamIdShift_Pre40 = 2;
-const uint8_t kQuicStreamIDLengthMask_Pre40 = 0x03;
+const uint8_t kQuicStreamIDLengthMask_Pre40 = 0b00000011;
 const uint8_t kQuicStreamIDLengthShift = 3;
 const uint8_t kQuicStreamIDLengthNumBits = 2;
 
 // Offset may be 0, 2, 4, or 8 bytes.
 const uint8_t kQuicStreamShift_Pre40 = 3;
-const uint8_t kQuicStreamOffsetMask_Pre40 = 0x07;
+const uint8_t kQuicStreamOffsetMask_Pre40 = 0b00000111;
 const uint8_t kQuicStreamOffsetNumBits = 2;
 const uint8_t kQuicStreamOffsetShift = 1;
 
 // Data length may be 0 or 2 bytes.
 const uint8_t kQuicStreamDataLengthShift_Pre40 = 1;
-const uint8_t kQuicStreamDataLengthMask_Pre40 = 0x01;
+const uint8_t kQuicStreamDataLengthMask_Pre40 = 0b00000001;
 const uint8_t kQuicStreamDataLengthShift = 0;
 
 // Fin bit may be set or not.
 const uint8_t kQuicStreamFinShift_Pre40 = 1;
-const uint8_t kQuicStreamFinMask_Pre40 = 0x01;
+const uint8_t kQuicStreamFinMask_Pre40 = 0b00000001;
 const uint8_t kQuicStreamFinShift = 5;
 
 // packet number size shift used in AckFrames.
diff --git a/net/traffic_annotation/network_traffic_annotation.h b/net/traffic_annotation/network_traffic_annotation.h
index 15f1aea..f912e6da 100644
--- a/net/traffic_annotation/network_traffic_annotation.h
+++ b/net/traffic_annotation/network_traffic_annotation.h
@@ -206,7 +206,7 @@
 //   }
 // }
 
-// Do not use this unless net-serialization is required.
+// Please do not use this unless uninitialized annotations are required.
 // Mojo interfaces for this class and the next one are defined in
 // '/services/network/public/interfaces'.
 struct MutableNetworkTrafficAnnotationTag {
diff --git a/services/identity/public/cpp/identity_test_environment.cc b/services/identity/public/cpp/identity_test_environment.cc
index 2a6f28f..954bab7 100644
--- a/services/identity/public/cpp/identity_test_environment.cc
+++ b/services/identity/public/cpp/identity_test_environment.cc
@@ -109,6 +109,14 @@
       grant);
 }
 
+void IdentityTestEnvironment::WaitForAccessTokenRequestAndRespondWithToken(
+    const std::string& token,
+    const base::Time& expiration) {
+  WaitForAccessTokenRequest();
+  internals_->token_service()->IssueTokenForAllPendingRequests(token,
+                                                               expiration);
+}
+
 void IdentityTestEnvironment::WaitForAccessTokenRequestAndRespondWithError(
     const GoogleServiceAuthError& error) {
   WaitForAccessTokenRequest();
diff --git a/services/identity/public/cpp/identity_test_environment.h b/services/identity/public/cpp/identity_test_environment.h
index 355029b..b48a1080 100644
--- a/services/identity/public/cpp/identity_test_environment.h
+++ b/services/identity/public/cpp/identity_test_environment.h
@@ -32,6 +32,14 @@
   // an access token value of "access_token".
   void SetAutomaticIssueOfAccessTokens(bool grant);
 
+  // Waits for an access token request to occur and issues |token| in response.
+  // NOTE: The implementation currently issues tokens in response to *all*
+  // pending access token requests. If you need finer granularity, contact
+  // blundell@chromium.org
+  void WaitForAccessTokenRequestAndRespondWithToken(
+      const std::string& token,
+      const base::Time& expiration);
+
   // Waits for an access token request to occur and issues |error| in response.
   // NOTE: The implementation currently issues errors in response to *all*
   // pending access token requests. If you need finer granularity, contact
diff --git a/services/network/public/cpp/network_switches.cc b/services/network/public/cpp/network_switches.cc
index acb3964..136c517 100644
--- a/services/network/public/cpp/network_switches.cc
+++ b/services/network/public/cpp/network_switches.cc
@@ -8,6 +8,14 @@
 
 namespace switches {
 
+// These mappings only apply to the host resolver.
+const char kHostResolverRules[] = "host-resolver-rules";
+
+// Enables saving net log events to a file. If a value is given, it used as the
+// path the the file, otherwise the file is named netlog.json and placed in the
+// user data directory.
+const char kLogNetLog[] = "log-net-log";
+
 // Don't send HTTP-Referer headers.
 const char kNoReferrers[] = "no-referrers";
 
diff --git a/services/network/public/cpp/network_switches.h b/services/network/public/cpp/network_switches.h
index f43d851..4c2c5644 100644
--- a/services/network/public/cpp/network_switches.h
+++ b/services/network/public/cpp/network_switches.h
@@ -9,8 +9,11 @@
 
 namespace switches {
 
+extern const char kHostResolverRules[];
+extern const char kLogNetLog[];
 extern const char kNoReferrers[];
-}
+
+}  // namespace switches
 
 }  // namespace network
 
diff --git a/services/network/public/interfaces/network_service.mojom b/services/network/public/interfaces/network_service.mojom
index e9f0fa7..01843bc 100644
--- a/services/network/public/interfaces/network_service.mojom
+++ b/services/network/public/interfaces/network_service.mojom
@@ -20,6 +20,9 @@
   // Name used by memory tools to identify the context.
   string? context_name;
 
+  // The user agent string.
+  string user_agent;
+
   // Whether Brotli content-encoding should be enabled for HTTPS responses.
   bool enable_brotli = true;
 
diff --git a/storage/browser/blob/blob_data_handle.cc b/storage/browser/blob/blob_data_handle.cc
index fd92efa..ab13572 100644
--- a/storage/browser/blob/blob_data_handle.cc
+++ b/storage/browser/blob/blob_data_handle.cc
@@ -101,22 +101,22 @@
   return shared_->context_->GetBlobStatus(shared_->uuid_);
 }
 
-void BlobDataHandle::RunOnConstructionComplete(const BlobStatusCallback& done) {
+void BlobDataHandle::RunOnConstructionComplete(BlobStatusCallback done) {
   DCHECK(io_task_runner_->RunsTasksInCurrentSequence());
   if (!shared_->context_.get()) {
-    done.Run(BlobStatus::ERR_INVALID_CONSTRUCTION_ARGUMENTS);
+    std::move(done).Run(BlobStatus::ERR_INVALID_CONSTRUCTION_ARGUMENTS);
     return;
   }
-  shared_->context_->RunOnConstructionComplete(shared_->uuid_, done);
+  shared_->context_->RunOnConstructionComplete(shared_->uuid_, std::move(done));
 }
 
-void BlobDataHandle::RunOnConstructionBegin(const BlobStatusCallback& done) {
+void BlobDataHandle::RunOnConstructionBegin(BlobStatusCallback done) {
   DCHECK(io_task_runner_->RunsTasksInCurrentSequence());
   if (!shared_->context_.get()) {
-    done.Run(BlobStatus::ERR_INVALID_CONSTRUCTION_ARGUMENTS);
+    std::move(done).Run(BlobStatus::ERR_INVALID_CONSTRUCTION_ARGUMENTS);
     return;
   }
-  shared_->context_->RunOnConstructionBegin(shared_->uuid_, done);
+  shared_->context_->RunOnConstructionBegin(shared_->uuid_, std::move(done));
 }
 
 std::unique_ptr<BlobDataSnapshot> BlobDataHandle::CreateSnapshot() const {
diff --git a/storage/browser/blob/blob_data_handle.h b/storage/browser/blob/blob_data_handle.h
index a1f1521..5290b904 100644
--- a/storage/browser/blob/blob_data_handle.h
+++ b/storage/browser/blob/blob_data_handle.h
@@ -67,7 +67,7 @@
   // Must be called on IO thread.
   // Calling this multiple times results in registering multiple
   // completion callbacks.
-  void RunOnConstructionComplete(const BlobStatusCallback& done);
+  void RunOnConstructionComplete(BlobStatusCallback done);
 
   // The callback will be run on the IO thread when construction of the blob
   // has began. If construction has already began (or has finished already),
@@ -76,7 +76,7 @@
   // Must be called on IO thread.
   // Calling this multiple times results in registering multiple
   // callbacks.
-  void RunOnConstructionBegin(const BlobStatusCallback& done);
+  void RunOnConstructionBegin(BlobStatusCallback done);
 
   // A BlobReader is used to read the data from the blob.  This object is
   // intended to be transient and should not be stored for any extended period
diff --git a/storage/browser/blob/blob_entry.cc b/storage/browser/blob/blob_entry.cc
index 8a26dcf..a396e11 100644
--- a/storage/browser/blob/blob_entry.cc
+++ b/storage/browser/blob/blob_entry.cc
@@ -33,7 +33,7 @@
     TransportAllowedCallback transport_allowed_callback,
     size_t num_building_dependent_blobs)
     : transport_items_present(transport_items_present),
-      transport_allowed_callback(transport_allowed_callback),
+      transport_allowed_callback(std::move(transport_allowed_callback)),
       num_building_dependent_blobs(num_building_dependent_blobs) {}
 
 BlobEntry::BuildingState::~BuildingState() {
diff --git a/storage/browser/blob/blob_entry.h b/storage/browser/blob/blob_entry.h
index cc514308..310f676a 100644
--- a/storage/browser/blob/blob_entry.h
+++ b/storage/browser/blob/blob_entry.h
@@ -26,9 +26,8 @@
 // Represents a blob in BlobStorageRegistry. Exported only for unit tests.
 class STORAGE_EXPORT BlobEntry {
  public:
-  using TransportAllowedCallback =
-      base::Callback<void(BlobStatus,
-                          std::vector<BlobMemoryController::FileCreationInfo>)>;
+  using TransportAllowedCallback = base::OnceCallback<
+      void(BlobStatus, std::vector<BlobMemoryController::FileCreationInfo>)>;
 
   // Records a copy from a referenced blob. Copies happen after referenced blobs
   // are complete & quota for the copies is granted.
diff --git a/storage/browser/blob/blob_registry_impl.cc b/storage/browser/blob/blob_registry_impl.cc
index a89a4c58..784f4dea0 100644
--- a/storage/browser/blob/blob_registry_impl.cc
+++ b/storage/browser/blob/blob_registry_impl.cc
@@ -374,9 +374,9 @@
     }
   }
 
-  BlobStorageContext::TransportAllowedCallback callback =
-      base::Bind(&BlobUnderConstruction::OnReadyForTransport,
-                 weak_ptr_factory_.GetWeakPtr());
+  auto callback =
+      base::BindRepeating(&BlobUnderConstruction::OnReadyForTransport,
+                          weak_ptr_factory_.GetWeakPtr());
 
   // OnReadyForTransport can be called synchronously, which can call
   // MarkAsFinishedAndDeleteSelf synchronously, so don't access any members
diff --git a/storage/browser/blob/blob_storage_context.cc b/storage/browser/blob/blob_storage_context.cc
index 3d3a9a4a..0b45e874 100644
--- a/storage/browser/blob/blob_storage_context.cc
+++ b/storage/browser/blob/blob_storage_context.cc
@@ -475,30 +475,32 @@
 
 std::unique_ptr<BlobDataHandle> BlobStorageContext::BuildPreregisteredBlob(
     const BlobDataBuilder& content,
-    const TransportAllowedCallback& transport_allowed_callback) {
+    TransportAllowedCallback transport_allowed_callback) {
   BlobEntry* entry = registry_.GetEntry(content.uuid());
   DCHECK(entry);
   DCHECK_EQ(BlobStatus::PENDING_CONSTRUCTION, entry->status());
   entry->set_size(0);
 
-  return BuildBlobInternal(entry, content, transport_allowed_callback);
+  return BuildBlobInternal(entry, content,
+                           std::move(transport_allowed_callback));
 }
 
 std::unique_ptr<BlobDataHandle> BlobStorageContext::BuildBlob(
     const BlobDataBuilder& content,
-    const TransportAllowedCallback& transport_allowed_callback) {
+    TransportAllowedCallback transport_allowed_callback) {
   DCHECK(!registry_.HasEntry(content.uuid_));
 
   BlobEntry* entry = registry_.CreateEntry(
       content.uuid(), content.content_type_, content.content_disposition_);
 
-  return BuildBlobInternal(entry, content, transport_allowed_callback);
+  return BuildBlobInternal(entry, content,
+                           std::move(transport_allowed_callback));
 }
 
 std::unique_ptr<BlobDataHandle> BlobStorageContext::BuildBlobInternal(
     BlobEntry* entry,
     const BlobDataBuilder& content,
-    const TransportAllowedCallback& transport_allowed_callback) {
+    TransportAllowedCallback transport_allowed_callback) {
   // This flattens all blob references in the transportion content out and
   // stores the complete item representation in the internal data.
   BlobFlattener flattener(content, entry, &registry_);
@@ -547,8 +549,8 @@
 
   auto previous_building_state = std::move(entry->building_state_);
   entry->set_building_state(std::make_unique<BlobEntry::BuildingState>(
-      !flattener.pending_transport_items.empty(), transport_allowed_callback,
-      num_building_dependent_blobs));
+      !flattener.pending_transport_items.empty(),
+      std::move(transport_allowed_callback), num_building_dependent_blobs));
   BlobEntry::BuildingState* building_state = entry->building_state_.get();
   std::swap(building_state->copies, flattener.copies);
   std::swap(building_state->dependent_blobs, dependent_blobs);
@@ -562,9 +564,9 @@
     std::swap(building_state->build_completion_callbacks,
               previous_building_state->build_completion_callbacks);
     auto runner = base::ThreadTaskRunnerHandle::Get();
-    for (const auto& callback :
-         previous_building_state->build_started_callbacks)
-      runner->PostTask(FROM_HERE, base::BindOnce(callback, entry->status()));
+    for (auto& callback : previous_building_state->build_started_callbacks)
+      runner->PostTask(FROM_HERE,
+                       base::BindOnce(std::move(callback), entry->status()));
   }
 
   // Break ourselves if we have an error. BuildingState must be set first so the
@@ -683,28 +685,27 @@
   return entry->status();
 }
 
-void BlobStorageContext::RunOnConstructionComplete(
-    const std::string& uuid,
-    const BlobStatusCallback& done) {
+void BlobStorageContext::RunOnConstructionComplete(const std::string& uuid,
+                                                   BlobStatusCallback done) {
   BlobEntry* entry = registry_.GetEntry(uuid);
   DCHECK(entry);
   if (BlobStatusIsPending(entry->status())) {
-    entry->building_state_->build_completion_callbacks.push_back(done);
+    entry->building_state_->build_completion_callbacks.push_back(
+        std::move(done));
     return;
   }
-  done.Run(entry->status());
+  std::move(done).Run(entry->status());
 }
 
-void BlobStorageContext::RunOnConstructionBegin(
-    const std::string& uuid,
-    const BlobStatusCallback& done) {
+void BlobStorageContext::RunOnConstructionBegin(const std::string& uuid,
+                                                BlobStatusCallback done) {
   BlobEntry* entry = registry_.GetEntry(uuid);
   DCHECK(entry);
   if (entry->status() == BlobStatus::PENDING_CONSTRUCTION) {
-    entry->building_state_->build_started_callbacks.push_back(done);
+    entry->building_state_->build_started_callbacks.push_back(std::move(done));
     return;
   }
-  done.Run(entry->status());
+  std::move(done).Run(entry->status());
 }
 
 std::unique_ptr<BlobDataHandle> BlobStorageContext::CreateHandle(
@@ -735,20 +736,19 @@
   if (entry->building_state_ &&
       entry->building_state_->transport_allowed_callback) {
     transport_allowed_callback =
-        entry->building_state_->transport_allowed_callback;
-    entry->building_state_->transport_allowed_callback.Reset();
+        std::move(entry->building_state_->transport_allowed_callback);
   }
   if (entry->building_state_ &&
       entry->status() == BlobStatus::PENDING_CONSTRUCTION) {
     auto runner = base::ThreadTaskRunnerHandle::Get();
-    for (const auto& callback : entry->building_state_->build_started_callbacks)
-      runner->PostTask(FROM_HERE, base::BindOnce(callback, reason));
+    for (auto& callback : entry->building_state_->build_started_callbacks)
+      runner->PostTask(FROM_HERE, base::BindOnce(std::move(callback), reason));
   }
   ClearAndFreeMemory(entry);
   entry->set_status(reason);
   if (transport_allowed_callback) {
-    transport_allowed_callback.Run(
-        reason, std::vector<BlobMemoryController::FileCreationInfo>());
+    std::move(transport_allowed_callback)
+        .Run(reason, std::vector<BlobMemoryController::FileCreationInfo>());
   }
   FinishBuilding(entry);
 }
@@ -825,8 +825,9 @@
   memory_controller_.NotifyMemoryItemsUsed(entry->items());
 
   auto runner = base::ThreadTaskRunnerHandle::Get();
-  for (const auto& callback : callbacks)
-    runner->PostTask(FROM_HERE, base::Bind(callback, entry->status()));
+  for (auto& callback : callbacks)
+    runner->PostTask(FROM_HERE,
+                     base::BindOnce(std::move(callback), entry->status()));
 
   for (const auto& shareable_item : entry->items()) {
     DCHECK_NE(network::DataElement::TYPE_BYTES_DESCRIPTION,
diff --git a/storage/browser/blob/blob_storage_context.h b/storage/browser/blob/blob_storage_context.h
index abe2ca4..b6c3485 100644
--- a/storage/browser/blob/blob_storage_context.h
+++ b/storage/browser/blob/blob_storage_context.h
@@ -99,7 +99,7 @@
   //   referencing ourself.
   std::unique_ptr<BlobDataHandle> BuildBlob(
       const BlobDataBuilder& input_builder,
-      const TransportAllowedCallback& transport_allowed_callback);
+      TransportAllowedCallback transport_allowed_callback);
 
   // Similar to BuildBlob, but this merely registers a blob that will be built
   // in the future. The caller must later call either BuildPreregisteredBlob
@@ -118,7 +118,7 @@
   // AddFutureBlob.
   std::unique_ptr<BlobDataHandle> BuildPreregisteredBlob(
       const BlobDataBuilder& input_builder,
-      const TransportAllowedCallback& transport_allowed_callback);
+      TransportAllowedCallback transport_allowed_callback);
 
   // This breaks a blob that is currently being built by using the BuildBlob
   // method above. Any callbacks waiting on this blob, including the
@@ -243,12 +243,12 @@
 
   // Runs |done| when construction completes with the final status of the blob.
   void RunOnConstructionComplete(const std::string& uuid,
-                                 const BlobStatusCallback& done_callback);
+                                 BlobStatusCallback done_callback);
 
   // Runs |done| when construction begins (when the blob is no longer
   // PENDING_CONSTRUCTION) with the new status of the blob.
   void RunOnConstructionBegin(const std::string& uuid,
-                              const BlobStatusCallback& done_callback);
+                              BlobStatusCallback done_callback);
 
   BlobStorageRegistry* mutable_registry() { return &registry_; }
 
@@ -260,7 +260,7 @@
   std::unique_ptr<BlobDataHandle> BuildBlobInternal(
       BlobEntry* entry,
       const BlobDataBuilder& input_builder,
-      const TransportAllowedCallback& transport_allowed_callback);
+      TransportAllowedCallback transport_allowed_callback);
 
   std::unique_ptr<BlobDataHandle> CreateHandle(const std::string& uuid,
                                                BlobEntry* entry);
diff --git a/storage/common/blob_storage/blob_storage_constants.h b/storage/common/blob_storage/blob_storage_constants.h
index f83ea53d..17697f2 100644
--- a/storage/common/blob_storage/blob_storage_constants.h
+++ b/storage/common/blob_storage/blob_storage_constants.h
@@ -131,7 +131,7 @@
   LAST = LAST_PENDING
 };
 
-using BlobStatusCallback = base::Callback<void(BlobStatus)>;
+using BlobStatusCallback = base::OnceCallback<void(BlobStatus)>;
 
 // Returns if the status is an error code.
 STORAGE_COMMON_EXPORT bool BlobStatusIsError(BlobStatus status);
diff --git a/styleguide/c++/c++11.html b/styleguide/c++/c++11.html
index 6f8ed951..84b2e0d 100644
--- a/styleguide/c++/c++11.html
+++ b/styleguide/c++/c++11.html
@@ -377,14 +377,6 @@
 </tr>
 
 <tr>
-<td>Number literal separators</td>
-<td><code>float f = 1'000'000.000'1;</code></td>
-<td><code>'</code>s anywhere in int or float literals are ignored</td>
-<td><a href="http://en.cppreference.com/w/cpp/language/integer_literal">Integer literals</a>, <a href="http://en.cppreference.com/w/cpp/language/floating_literal">Floating point literals</a></td>
-<td><a href="https://groups.google.com/a/chromium.org/d/topic/cxx/exS1aGs1wes/discussion">Discussion thread</a></td>
-</tr>
-
-<tr>
 <td>Aggregate member initialization</td>
 <td><code>struct Point { int x, y, z = 0; };<br>Point p = {2, 3};</code></td>
 <td>Allows classes with default member initializers to be initialized with aggregate initialization, optionally omitting data members with such initializers.</td>
@@ -393,6 +385,22 @@
 </tr>
 
 <tr>
+<td>Binary literals</td>
+<td><code>int i = 0b1001;</code></td>
+<td>Allows defining literals in base two.</td>
+<td><a href="http://en.cppreference.com/w/cpp/language/integer_literal">Integer literals</a></td>
+<td><a href="https://groups.google.com/a/chromium.org/d/topic/cxx/zsGhgaKLmIk/discussion">Discussion thread</a></td>
+</tr>
+
+<tr>
+<td>Number literal separators</td>
+<td><code>float f = 1'000'000.000'1;</code></td>
+<td><code>'</code>s anywhere in int or float literals are ignored</td>
+<td><a href="http://en.cppreference.com/w/cpp/language/integer_literal">Integer literals</a>, <a href="http://en.cppreference.com/w/cpp/language/floating_literal">Floating point literals</a></td>
+<td><a href="https://groups.google.com/a/chromium.org/d/topic/cxx/exS1aGs1wes/discussion">Discussion thread</a></td>
+</tr>
+
+<tr>
 <td>Relaxed constant expressions</td>
 <td><code>constexpr int Factorial(int n) {<br>&nbsp;&nbsp;int result = 1;<br>&nbsp;&nbsp;while (n > 0)<br>&nbsp;&nbsp;&nbsp;&nbsp;result *= n--;<br>&nbsp;&nbsp;return result;<br>}</code></td>
 <td>Allows use of more declarations, conditional statements and loops inside <code>constexpr</code> functions.</td>
@@ -977,15 +985,6 @@
 </tr>
 
 <tr>
-<td>Binary literals</td>
-<td><code>int i = 0b1001;</code></td>
-<td>Allows defining literals in base two.</td>
-<td><a href="http://en.cppreference.com/w/cpp/language/integer_literal">Integer literals</a></td>
-<td>Might confuse syntax highlighting in editors. No standard library support
-for printing or reading in this format. Still seems useful in minor ways.</td>
-</tr>
-
-<tr>
 <td><code>decltype(auto)</code> variable declarations</td>
 <td><code>decltype(auto) x = 42;</code></td>
 <td>Allows deducing the type of a variable using <code>decltype</code> rules.</td>
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json
index ba13ef47..c92d657 100644
--- a/testing/buildbot/chromium.fyi.json
+++ b/testing/buildbot/chromium.fyi.json
@@ -4425,11 +4425,46 @@
       {
         "args": [
           "--enable-features=NetworkService",
-          "--test-launcher-filter-file=../../testing/buildbot/filters/mojo.fyi.network_content_browsertests.filter"
+          "--test-launcher-filter-file=../../testing/buildbot/filters/mojo.fyi.network_content_browsertests.filter",
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices"
         ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "network_service_content_browsertests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
         "name": "network_service_content_browsertests",
         "swarming": {
-          "can_use_on_swarming_builders": true
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "device_os": "MMB29Q",
+              "device_type": "bullhead"
+            }
+          ],
+          "hard_timeout": 960,
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ]
         },
         "test": "content_browsertests"
       }
diff --git a/testing/buildbot/filters/mojo.fyi.network_browser_tests.filter b/testing/buildbot/filters/mojo.fyi.network_browser_tests.filter
index 669d00a..c1bfe883 100644
--- a/testing/buildbot/filters/mojo.fyi.network_browser_tests.filter
+++ b/testing/buildbot/filters/mojo.fyi.network_browser_tests.filter
@@ -34,10 +34,9 @@
 -DiceBrowserTest.SignoutSecondaryAccount
 -DiceFixAuthErrorsBrowserTest.ReauthFixAuthError
 -DiceFixAuthErrorsBrowserTest.SigninAccountMismatch
--DicePrepareMigrationBrowserTest.Signin
+-DicePrepareMigrationBrowserTest.EnableSyncAfterToken
+-DicePrepareMigrationBrowserTest.EnableSyncBeforeToken
 -DicePrepareMigrationBrowserTest.Signout
--DicePrepareMigrationChromeSynEndpointBrowserTest.EnableSyncAfterToken
--DicePrepareMigrationChromeSynEndpointBrowserTest.EnableSyncBeforeToken
 -DisabledSignInIsolationBrowserTest.SyntheticTrial
 # DnsProbeBrowserTests that are flaky.
 -DnsProbeBrowserTest.CorrectionsLoadStopped
@@ -180,13 +179,16 @@
 -WebViewTests/WebViewTest.WebViewInBackgroundPage/0
 -WebViewTests/WebViewTest.WebViewInBackgroundPage/1
 
-# crbug.com/776589 Intercepting requests with net::URLRequestFilter.
--ClientHintsBrowserTest.ClientHintsLifetimeNotAttachedCookiesBlocked
+# Need support for blocking cookies via content settings:
+# https://crbug.com/803452.
 -ContentSettingsTest.AllowCookiesForASessionUsingExceptions
 -ContentSettingsTest.BasicCookies
 -ContentSettingsTest.BasicCookiesHttps
 -ContentSettingsTest.RedirectCrossOrigin
 -ContentSettingsTest.RedirectLoopCookies
+
+# crbug.com/776589 Intercepting requests with net::URLRequestFilter.
+-ClientHintsBrowserTest.ClientHintsLifetimeNotAttachedCookiesBlocked
 -ContinueWhereILeftOffTest.CookiesClearedOnExit
 -DevToolsSanityTest.TestNetworkPushTime
 -DnsProbeBrowserTest.NxdomainProbeResultWithWorkingCorrections
@@ -470,13 +472,6 @@
 -ExtensionRequestLimitingThrottleBrowserTest.ThrottleRequest_RedirectCached
 -ExtensionRequestLimitingThrottleCommandLineBrowserTest.ThrottleRequestDisabled
 
-# Redirect responses using NavigationThrottle or by hooking
-# NavigationURLLoaderNetworkService::URLLoaderRequestController
-# instead of net::URLRequestInterceptor.
--NewTabPageInterceptorTest.204Interception
--NewTabPageInterceptorTest.404Interception
--NewTabPageInterceptorTest.FailedRequestInterception
-
 # This requires that InterceptNetworkTransactions works
 -ErrorPageNavigationCorrectionsFailTest.StaleCacheStatusFailedCorrections
 
diff --git a/testing/buildbot/waterfalls.pyl b/testing/buildbot/waterfalls.pyl
index ebb827c..915b129f 100644
--- a/testing/buildbot/waterfalls.pyl
+++ b/testing/buildbot/waterfalls.pyl
@@ -1118,6 +1118,16 @@
         },
       },
       'Mojo Android': {
+        'swarming': {
+          'dimension_sets': [
+            {
+              'device_os': 'MMB29Q',
+              'device_type': 'bullhead',
+            },
+          ],
+          'hard_timeout': 960,
+        },
+        'os_type': 'android',
         'test_suites': {
           'gtest_tests': 'mojo_android_gtests',
         },
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
index 03aa12ba4..e8961a3 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
@@ -173,9 +173,12 @@
 crbug.com/591099 compositing/geometry/transformed-abs-position-inside-composited.html [ Failure ]
 crbug.com/591099 compositing/geometry/transfrom-origin-on-zero-size-layer.html [ Failure ]
 crbug.com/591099 compositing/geometry/video-opacity-overlay.html [ Failure ]
+crbug.com/714962 compositing/gestures/gesture-tapHighlight-1-iframe-composited-scrolled-late-composite.html [ Failure ]
 crbug.com/714962 compositing/gestures/gesture-tapHighlight-1-iframe-composited-scrolled-late-noncomposite.html [ Failure ]
 crbug.com/714962 compositing/gestures/gesture-tapHighlight-1-iframe-composited-scrolled.html [ Failure ]
 crbug.com/714962 compositing/gestures/gesture-tapHighlight-1-iframe-composited.html [ Failure ]
+crbug.com/714962 compositing/gestures/gesture-tapHighlight-1-iframe-scrolled.html [ Failure ]
+crbug.com/714962 compositing/gestures/gesture-tapHighlight-1-iframe.html [ Failure ]
 crbug.com/714962 compositing/gestures/gesture-tapHighlight-1-overflow-div-composited-scroll-clip.html [ Failure ]
 crbug.com/714962 compositing/gestures/gesture-tapHighlight-1-overflow-div-composited-scrolled.html [ Failure ]
 crbug.com/714962 compositing/gestures/gesture-tapHighlight-1-overflow-div-composited.html [ Failure ]
@@ -185,9 +188,16 @@
 crbug.com/714962 compositing/gestures/gesture-tapHighlight-1-overflow-div-scrolled-late-noncomposite.html [ Failure ]
 crbug.com/714962 compositing/gestures/gesture-tapHighlight-1-overflow-div-scrolled.html [ Failure ]
 crbug.com/714962 compositing/gestures/gesture-tapHighlight-1-overflow-div.html [ Failure ]
+crbug.com/714962 compositing/gestures/gesture-tapHighlight-2-iframe-composited-inner.html [ Failure ]
+crbug.com/714962 compositing/gestures/gesture-tapHighlight-2-iframe-composited-outer.html [ Failure ]
+crbug.com/714962 compositing/gestures/gesture-tapHighlight-2-iframe-scrolled-inner-late-composite.html [ Failure ]
+crbug.com/714962 compositing/gestures/gesture-tapHighlight-2-iframe-scrolled-inner.html [ Failure ]
+crbug.com/714962 compositing/gestures/gesture-tapHighlight-2-iframe-scrolled-outer-late-composite.html [ Failure ]
+crbug.com/714962 compositing/gestures/gesture-tapHighlight-2-iframe-scrolled-outer.html [ Failure ]
+crbug.com/714962 compositing/gestures/gesture-tapHighlight-2-iframe.html [ Failure ]
 crbug.com/714962 compositing/gestures/gesture-tapHighlight-2-overflow-div-composited-inner-scroll-inner.html [ Failure ]
-crbug.com/714962 compositing/gestures/gesture-tapHighlight-2-overflow-div-composited-inner-scroll-outer.html [ Pass ]
-crbug.com/714962 compositing/gestures/gesture-tapHighlight-2-overflow-div-composited-inner.html [ Pass ]
+crbug.com/714962 compositing/gestures/gesture-tapHighlight-2-overflow-div-composited-inner-scroll-outer.html [ Failure ]
+crbug.com/714962 compositing/gestures/gesture-tapHighlight-2-overflow-div-composited-inner.html [ Failure ]
 crbug.com/714962 compositing/gestures/gesture-tapHighlight-2-overflow-div-composited-outer-scroll-inner.html [ Failure ]
 crbug.com/714962 compositing/gestures/gesture-tapHighlight-2-overflow-div-composited-outer-scroll-outer.html [ Failure ]
 crbug.com/714962 compositing/gestures/gesture-tapHighlight-2-overflow-div-composited-outer.html [ Failure ]
@@ -205,8 +215,9 @@
 crbug.com/714962 compositing/gestures/gesture-tapHighlight-shadow-tree.html [ Failure ]
 crbug.com/714962 compositing/gestures/gesture-tapHighlight-simple-multi-line.html [ Pass ]
 crbug.com/714962 compositing/gestures/gesture-tapHighlight-simple-scaled-document.html [ Failure ]
+crbug.com/591099 compositing/gestures/gesture-tapHighlight-simple-scaledX.html [ Failure ]
 crbug.com/714962 compositing/gestures/gesture-tapHighlight-simple-scaledY.html [ Failure ]
-crbug.com/714962 compositing/gestures/gesture-tapHighlight-simple-window-scroll.html [ Pass ]
+crbug.com/714962 compositing/gestures/gesture-tapHighlight-simple-window-scroll.html [ Failure ]
 crbug.com/714962 compositing/gestures/gesture-tapHighlight-with-box-shadow.html [ Failure ]
 crbug.com/714962 compositing/gestures/gesture-tapHighlight-with-squashing.html [ Pass ]
 crbug.com/591099 compositing/iframes/composited-iframe-alignment.html [ Failure ]
@@ -2335,6 +2346,7 @@
 crbug.com/714962 external/wpt/html/rendering/the-css-user-agent-style-sheet-and-presentational-hints/body-bgcolor-attribute-change.html [ Failure ]
 crbug.com/591099 external/wpt/html/semantics/document-metadata/the-link-element/stylesheet-change-href.html [ Failure ]
 crbug.com/714962 external/wpt/html/semantics/embedded-content/media-elements/track/track-element/track-cue-rendering-transformed-video.html [ Failure Pass ]
+crbug.com/591099 external/wpt/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-non-snap-to-lines.html [ Failure ]
 crbug.com/591099 external/wpt/html/semantics/forms/the-form-element/form-elements-filter.html [ Crash ]
 crbug.com/591099 external/wpt/html/semantics/forms/the-form-element/form-nameditem.html [ Crash ]
 crbug.com/591099 external/wpt/html/semantics/grouping-content/the-li-element/grouping-li-reftest-002.html [ Failure ]
@@ -3652,6 +3664,7 @@
 crbug.com/591099 fast/forms/encoding-test.html [ Failure ]
 crbug.com/591099 fast/forms/fieldset/fieldset-crash.html [ Failure ]
 crbug.com/591099 fast/forms/fieldset/fieldset-elements.html [ Crash ]
+crbug.com/591099 fast/forms/fieldset/fieldset-form-collection-radionode-list.html [ Crash ]
 crbug.com/591099 fast/forms/fieldset/fieldset-with-float.html [ Failure ]
 crbug.com/591099 fast/forms/fieldset/float-before-fieldset.html [ Failure ]
 crbug.com/714962 fast/forms/file/file-cloneNode.html [ Timeout ]
@@ -4254,6 +4267,9 @@
 crbug.com/591099 fast/lists/remove-listmarker-and-make-anonblock-empty-2.html [ Failure ]
 crbug.com/591099 fast/lists/remove-listmarker-from-anonblock-with-continuation-crash.html [ Crash ]
 crbug.com/591099 fast/loader/child-frame-add-after-back-forward.html [ Timeout ]
+crbug.com/591099 fast/loader/document-with-fragment-url-1.html [ Timeout ]
+crbug.com/591099 fast/loader/document-with-fragment-url-3.html [ Timeout ]
+crbug.com/591099 fast/loader/document-with-fragment-url-4.html [ Timeout ]
 crbug.com/591099 fast/loader/frame-creation-removal.html [ Failure ]
 crbug.com/591099 fast/loader/javascript-url-iframe-crash.html [ Crash ]
 crbug.com/591099 fast/loader/local-CSS-from-local.html [ Failure ]
@@ -5287,6 +5303,7 @@
 crbug.com/714962 fast/text/selection/shaping-selection-rect.html [ Failure ]
 crbug.com/714962 fast/text/selection/thai-offsetForPosition-inside-character.html [ Failure ]
 crbug.com/714962 fast/text/stroking-decorations.html [ Failure ]
+crbug.com/591099 fast/text/sub-pixel/text-scaling-pixel.html [ Failure ]
 crbug.com/714962 fast/text/tab-min-size.html [ Failure ]
 crbug.com/714962 fast/text/text-range-bounds.html [ Failure ]
 crbug.com/591099 fast/text/textIteratorNilRenderer.html [ Failure Pass ]
@@ -6102,7 +6119,6 @@
 crbug.com/591099 media/media-document-audio-repaint.html [ Failure ]
 crbug.com/714962 media/track/track-cue-rendering-position-auto-rtl.html [ Failure Pass ]
 crbug.com/714962 media/track/track-cue-rendering-position-auto.html [ Failure Pass ]
-crbug.com/591099 media/track/track-webvtt-non-snap-to-lines.html [ Failure ]
 crbug.com/591099 media/video-aspect-ratio.html [ Failure ]
 crbug.com/591099 media/video-canvas-alpha.html [ Failure ]
 crbug.com/591099 media/video-colorspace-yuv420.html [ Failure ]
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index 137eb5d..8e19b6c 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -681,11 +681,11 @@
 crbug.com/776656 virtual/incremental-shadow-dom/external/wpt/shadow-dom/untriaged/elements-and-dom-objects/extensions-to-event-interface/event-path-001.html [ Failure ]
 crbug.com/776656 virtual/incremental-shadow-dom/external/wpt/shadow-dom/untriaged/styles/test-003.html [ Failure ]
 crbug.com/776656 virtual/incremental-shadow-dom/fast/dom/shadow/shadow-dom-event-dispatching-details-summary.html [ Failure ]
-crbug.com/776656 virtual/incremental-shadow-dom/fast/dom/shadow/user-modify-inheritance.html [ Failure ]
-crbug.com/776656 virtual/incremental-shadow-dom/shadow-dom/css-style-inherit.html [ Failure ]
 
 # ====== IncrementalShadowDOM-only failures until here ======
 
+crbug.com/776656 shadow-dom/css-style-inherit.html [ Failure ]
+
 crbug.com/667560 [ Debug ] http/tests/devtools/elements/styles-3/styles-change-node-while-editing.js [ Pass Failure ]
 crbug.com/778515 http/tests/devtools/elements/styles-3/styles-add-new-rule.js [ Pass Failure ]
 
@@ -2000,10 +2000,7 @@
 crbug.com/626703 external/wpt/webaudio/the-audio-api/the-audioparam-interface/retrospective-setValueAtTime.html [ Timeout ]
 crbug.com/626703 external/wpt/webaudio/the-audio-api/the-audioparam-interface/retrospective-setValueCurveAtTime.html [ Timeout ]
 crbug.com/626703 external/wpt/webaudio/the-audio-api/the-mediaelementaudiosourcenode-interface/mediaElementAudioSourceToScriptProcessorTest.html [ Timeout ]
-crbug.com/626703 external/wpt/webauthn/interfaces.https.html [ Timeout ]
-crbug.com/626703 external/wpt/webauthn/makecredential-badargs-accountinformation.https.html [ Timeout ]
-crbug.com/626703 external/wpt/webauthn/makecredential-badargs-attestationchallenge.https.html [ Timeout ]
-crbug.com/626703 external/wpt/webauthn/makecredential-badargs-cryptoparameters.https.html [ Timeout ]
+crbug.com/626703 [ Mac10.13 ] external/wpt/webauthn/interfaces.https.html [ Timeout ]
 crbug.com/626703 external/wpt/webrtc/RTCPeerConnection-setLocalDescription-rollback.html [ Timeout ]
 crbug.com/626703 external/wpt/webrtc/RTCPeerConnection-setRemoteDescription.html [ Timeout ]
 crbug.com/626703 external/wpt/webrtc/RTCPeerConnection-setRemoteDescription-rollback.html [ Timeout ]
@@ -2405,6 +2402,22 @@
 crbug.com/707359 [ Mac ] fast/css-grid-layout/grid-self-baseline-vertical-rl-04.html [ Failure ]
 crbug.com/707359 [ Mac ] fast/css-grid-layout/grid-self-baseline-vertical-rl-05.html [ Failure ]
 
+# [css-align]
+crbug.com/726148 external/wpt/css/css-align/default-alignment/parse-justify-items-002.html [ Failure ]
+crbug.com/726147 external/wpt/css/css-align/default-alignment/parse-justify-items-004.html [ Failure ]
+crbug.com/803275 external/wpt/css/css-align/default-alignment/parse-justify-items-001.html [ Failure ]
+crbug.com/803275 external/wpt/css/css-align/default-alignment/parse-justify-items-003.html [ Failure ]
+crbug.com/803275 external/wpt/css/css-align/default-alignment/parse-align-items-001.html [ Failure ]
+crbug.com/803275 external/wpt/css/css-align/default-alignment/parse-align-items-003.html [ Failure ]
+crbug.com/803275 external/wpt/css/css-align/self-alignment/parse-justify-self-001.html [ Failure ]
+crbug.com/803275 external/wpt/css/css-align/self-alignment/parse-justify-self-003.html [ Failure ]
+crbug.com/803275 external/wpt/css/css-align/self-alignment/parse-align-self-001.html [ Failure ]
+crbug.com/803275 external/wpt/css/css-align/self-alignment/parse-align-self-003.html [ Failure ]
+crbug.com/803275 external/wpt/css/css-align/content-distribution/parse-justify-content-001.html [ Failure ]
+crbug.com/803275 external/wpt/css/css-align/content-distribution/parse-justify-content-003.html [ Failure ]
+crbug.com/803275 external/wpt/css/css-align/content-distribution/parse-align-content-001.html [ Failure ]
+crbug.com/803275 external/wpt/css/css-align/content-distribution/parse-align-content-003.html [ Failure ]
+
 # [selectors-4]
 crbug.com/706118 external/wpt/css/selectors/focus-within-004.html [ Failure ]
 crbug.com/576815 external/wpt/css/selectors/selectors-dir-selector-ltr-001.html [ Failure ]
diff --git a/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json b/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
index 496057b..1c7de3e 100644
--- a/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
+++ b/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
@@ -45643,18 +45643,6 @@
      {}
     ]
    ],
-   "css/css-position/position-sticky-bottom.html": [
-    [
-     "/css/css-position/position-sticky-bottom.html",
-     [
-      [
-       "/css/css-position/position-sticky-bottom-ref.html",
-       "=="
-      ]
-     ],
-     {}
-    ]
-   ],
    "css/css-position/position-sticky-flexbox.html": [
     [
      "/css/css-position/position-sticky-flexbox.html",
@@ -45703,18 +45691,6 @@
      {}
     ]
    ],
-   "css/css-position/position-sticky-left.html": [
-    [
-     "/css/css-position/position-sticky-left.html",
-     [
-      [
-       "/css/css-position/position-sticky-left-ref.html",
-       "=="
-      ]
-     ],
-     {}
-    ]
-   ],
    "css/css-position/position-sticky-margins.html": [
     [
      "/css/css-position/position-sticky-margins.html",
@@ -45811,12 +45787,12 @@
      {}
     ]
    ],
-   "css/css-position/position-sticky-right.html": [
+   "css/css-position/position-sticky-rendering.html": [
     [
-     "/css/css-position/position-sticky-right.html",
+     "/css/css-position/position-sticky-rendering.html",
      [
       [
-       "/css/css-position/position-sticky-right-ref.html",
+       "/css/css-position/position-sticky-rendering-ref.html",
        "=="
       ]
      ],
@@ -45955,18 +45931,6 @@
      {}
     ]
    ],
-   "css/css-position/position-sticky-top.html": [
-    [
-     "/css/css-position/position-sticky-top.html",
-     [
-      [
-       "/css/css-position/position-sticky-top-ref.html",
-       "=="
-      ]
-     ],
-     {}
-    ]
-   ],
    "css/css-position/position-sticky-transforms-translate.html": [
     [
      "/css/css-position/position-sticky-transforms-translate.html",
@@ -111295,11 +111259,6 @@
      {}
     ]
    ],
-   "css/css-position/position-sticky-bottom-ref.html": [
-    [
-     {}
-    ]
-   ],
    "css/css-position/position-sticky-flexbox-ref.html": [
     [
      {}
@@ -111320,11 +111279,6 @@
      {}
     ]
    ],
-   "css/css-position/position-sticky-left-ref.html": [
-    [
-     {}
-    ]
-   ],
    "css/css-position/position-sticky-margins-ref.html": [
     [
      {}
@@ -111365,7 +111319,7 @@
      {}
     ]
    ],
-   "css/css-position/position-sticky-right-ref.html": [
+   "css/css-position/position-sticky-rendering-ref.html": [
     [
      {}
     ]
@@ -111425,11 +111379,6 @@
      {}
     ]
    ],
-   "css/css-position/position-sticky-top-ref.html": [
-    [
-     {}
-    ]
-   ],
    "css/css-position/position-sticky-transforms-ref.html": [
     [
      {}
@@ -111445,6 +111394,11 @@
      {}
     ]
    ],
+   "css/css-position/resources/sticky-util.js": [
+    [
+     {}
+    ]
+   ],
    "css/css-rhythm/OWNERS": [
     [
      {}
@@ -116435,6 +116389,21 @@
      {}
     ]
    ],
+   "css/css-typed-om/stylevalue-subclasses/cssVariableReferenceValue.tentative-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "css/css-typed-om/stylevalue-subclasses/numeric-objects/cssUnitValue.tentative-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "css/css-typed-om/stylevalue-subclasses/numeric-objects/numeric-factory.tentative-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "css/css-typed-om/the-stylepropertymap/computed/computed.tentative-expected.txt": [
     [
      {}
@@ -140700,16 +140669,46 @@
      {}
     ]
    ],
+   "html/syntax/parsing/html5lib_menuitem-element_run_type=write-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "html/syntax/parsing/html5lib_template-expected.txt": [
     [
      {}
     ]
    ],
+   "html/syntax/parsing/html5lib_template_run_type=uri-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "html/syntax/parsing/html5lib_template_run_type=write-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "html/syntax/parsing/html5lib_template_run_type=write_single-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "html/syntax/parsing/html5lib_tests11-expected.txt": [
     [
      {}
     ]
    ],
+   "html/syntax/parsing/html5lib_tests11_run_type=uri-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "html/syntax/parsing/html5lib_tests11_run_type=write-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "html/syntax/parsing/html5lib_tests19-expected.txt": [
     [
      {}
@@ -140725,6 +140724,31 @@
      {}
     ]
    ],
+   "html/syntax/parsing/html5lib_tests25_run_type=uri-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "html/syntax/parsing/html5lib_tests25_run_type=write-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "html/syntax/parsing/html5lib_tests25_run_type=write_single-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "html/syntax/parsing/html5lib_webkit02_run_type=write-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "html/syntax/parsing/html5lib_webkit02_run_type=write_single-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "html/syntax/parsing/named-character-references-data.js": [
     [
      {}
@@ -151600,16 +151624,41 @@
      {}
     ]
    ],
+   "webauthn/createcredential-badargs-rp.https-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "webauthn/createcredential-passing.https-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "webauthn/getcredential-passing.https-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "webauthn/helpers.js": [
     [
      {}
     ]
    ],
+   "webauthn/interfaces.https-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "webauthn/interfaces.idl": [
     [
      {}
     ]
    ],
+   "webauthn/securecontext.http-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "webmessaging/MessageEvent-trusted-worker.js": [
     [
      {}
@@ -152155,6 +152204,26 @@
      {}
     ]
    ],
+   "websockets/constructor/002-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "websockets/constructor/002_wss-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "websockets/cookies/007-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "websockets/cookies/007_wss-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "websockets/cookies/support/set-cookie.py": [
     [
      {}
@@ -152275,6 +152344,36 @@
      {}
     ]
    ],
+   "websockets/interfaces/WebSocket/close/close-connecting-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "websockets/interfaces/WebSocket/close/close-connecting_wss-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "websockets/interfaces/WebSocket/close/close-nested-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "websockets/interfaces/WebSocket/close/close-nested_wss-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "websockets/interfaces/WebSocket/readyState/003-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "websockets/interfaces/WebSocket/readyState/003_wss-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "websockets/multi-globals/support/incumbent.sub.html": [
     [
      {}
@@ -152310,6 +152409,16 @@
      {}
     ]
    ],
+   "websockets/unload-a-document/002-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "websockets/unload-a-document/002_wss-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "websockets/unload-a-document/004-expected.txt": [
     [
      {}
@@ -169505,6 +169614,12 @@
      {}
     ]
    ],
+   "css/css-position/position-sticky-bottom.html": [
+    [
+     "/css/css-position/position-sticky-bottom.html",
+     {}
+    ]
+   ],
    "css/css-position/position-sticky-get-bounding-client-rect.html": [
     [
      "/css/css-position/position-sticky-get-bounding-client-rect.html",
@@ -169517,6 +169632,12 @@
      {}
     ]
    ],
+   "css/css-position/position-sticky-left.html": [
+    [
+     "/css/css-position/position-sticky-left.html",
+     {}
+    ]
+   ],
    "css/css-position/position-sticky-offset-overflow.html": [
     [
      "/css/css-position/position-sticky-offset-overflow.html",
@@ -169535,6 +169656,18 @@
      {}
     ]
    ],
+   "css/css-position/position-sticky-right.html": [
+    [
+     "/css/css-position/position-sticky-right.html",
+     {}
+    ]
+   ],
+   "css/css-position/position-sticky-top.html": [
+    [
+     "/css/css-position/position-sticky-top.html",
+     {}
+    ]
+   ],
    "css/css-rhythm/line-height-step-dynamic-001.html": [
     [
      "/css/css-rhythm/line-height-step-dynamic-001.html",
@@ -171719,12 +171852,132 @@
      {}
     ]
    ],
+   "css/css-typed-om/stylevalue-subclasses/cssMatrixComponent.tentative.html": [
+    [
+     "/css/css-typed-om/stylevalue-subclasses/cssMatrixComponent.tentative.html",
+     {}
+    ]
+   ],
+   "css/css-typed-om/stylevalue-subclasses/cssPerspective.tentative.html": [
+    [
+     "/css/css-typed-om/stylevalue-subclasses/cssPerspective.tentative.html",
+     {}
+    ]
+   ],
    "css/css-typed-om/stylevalue-subclasses/cssPositionValue-interface.html": [
     [
      "/css/css-typed-om/stylevalue-subclasses/cssPositionValue-interface.html",
      {}
     ]
    ],
+   "css/css-typed-om/stylevalue-subclasses/cssPositionValue.tentative.html": [
+    [
+     "/css/css-typed-om/stylevalue-subclasses/cssPositionValue.tentative.html",
+     {}
+    ]
+   ],
+   "css/css-typed-om/stylevalue-subclasses/cssRotation.tentative.html": [
+    [
+     "/css/css-typed-om/stylevalue-subclasses/cssRotation.tentative.html",
+     {}
+    ]
+   ],
+   "css/css-typed-om/stylevalue-subclasses/cssScale.tentative.html": [
+    [
+     "/css/css-typed-om/stylevalue-subclasses/cssScale.tentative.html",
+     {}
+    ]
+   ],
+   "css/css-typed-om/stylevalue-subclasses/cssSkew.tentative.html": [
+    [
+     "/css/css-typed-om/stylevalue-subclasses/cssSkew.tentative.html",
+     {}
+    ]
+   ],
+   "css/css-typed-om/stylevalue-subclasses/cssTransformValue.tentative.html": [
+    [
+     "/css/css-typed-om/stylevalue-subclasses/cssTransformValue.tentative.html",
+     {}
+    ]
+   ],
+   "css/css-typed-om/stylevalue-subclasses/cssTranslation.tentative.html": [
+    [
+     "/css/css-typed-om/stylevalue-subclasses/cssTranslation.tentative.html",
+     {}
+    ]
+   ],
+   "css/css-typed-om/stylevalue-subclasses/cssUnparsedValue.tentative.html": [
+    [
+     "/css/css-typed-om/stylevalue-subclasses/cssUnparsedValue.tentative.html",
+     {}
+    ]
+   ],
+   "css/css-typed-om/stylevalue-subclasses/cssUrlImageValue.tentative.html": [
+    [
+     "/css/css-typed-om/stylevalue-subclasses/cssUrlImageValue.tentative.html",
+     {}
+    ]
+   ],
+   "css/css-typed-om/stylevalue-subclasses/cssVariableReferenceValue.tentative.html": [
+    [
+     "/css/css-typed-om/stylevalue-subclasses/cssVariableReferenceValue.tentative.html",
+     {}
+    ]
+   ],
+   "css/css-typed-om/stylevalue-subclasses/numeric-objects/arithmetic.tentative.html": [
+    [
+     "/css/css-typed-om/stylevalue-subclasses/numeric-objects/arithmetic.tentative.html",
+     {}
+    ]
+   ],
+   "css/css-typed-om/stylevalue-subclasses/numeric-objects/cssMathValue.tentative.html": [
+    [
+     "/css/css-typed-om/stylevalue-subclasses/numeric-objects/cssMathValue.tentative.html",
+     {}
+    ]
+   ],
+   "css/css-typed-om/stylevalue-subclasses/numeric-objects/cssUnitValue.tentative.html": [
+    [
+     "/css/css-typed-om/stylevalue-subclasses/numeric-objects/cssUnitValue.tentative.html",
+     {}
+    ]
+   ],
+   "css/css-typed-om/stylevalue-subclasses/numeric-objects/equals.tentative.html": [
+    [
+     "/css/css-typed-om/stylevalue-subclasses/numeric-objects/equals.tentative.html",
+     {}
+    ]
+   ],
+   "css/css-typed-om/stylevalue-subclasses/numeric-objects/numeric-factory.tentative.html": [
+    [
+     "/css/css-typed-om/stylevalue-subclasses/numeric-objects/numeric-factory.tentative.html",
+     {}
+    ]
+   ],
+   "css/css-typed-om/stylevalue-subclasses/numeric-objects/numeric-typing.tentative.html": [
+    [
+     "/css/css-typed-om/stylevalue-subclasses/numeric-objects/numeric-typing.tentative.html",
+     {}
+    ]
+   ],
+   "css/css-typed-om/stylevalue-subclasses/numeric-objects/parse.tentative.html": [
+    [
+     "/css/css-typed-om/stylevalue-subclasses/numeric-objects/parse.tentative.html",
+     {}
+    ]
+   ],
+   "css/css-typed-om/stylevalue-subclasses/numeric-objects/to.tentative.html": [
+    [
+     "/css/css-typed-om/stylevalue-subclasses/numeric-objects/to.tentative.html",
+     {}
+    ]
+   ],
+   "css/css-typed-om/stylevalue-subclasses/numeric-objects/toSum.tentative.html": [
+    [
+     "/css/css-typed-om/stylevalue-subclasses/numeric-objects/toSum.tentative.html",
+     {}
+    ]
+   ],
    "css/css-typed-om/the-stylepropertymap/computed/computed.tentative.html": [
     [
      "/css/css-typed-om/the-stylepropertymap/computed/computed.tentative.html",
@@ -217373,27 +217626,39 @@
      {}
     ]
    ],
+   "webauthn/createcredential-badargs-rp.https.html": [
+    [
+     "/webauthn/createcredential-badargs-rp.https.html",
+     {}
+    ]
+   ],
+   "webauthn/createcredential-passing.https.html": [
+    [
+     "/webauthn/createcredential-passing.https.html",
+     {}
+    ]
+   ],
+   "webauthn/getcredential-passing.https.html": [
+    [
+     "/webauthn/getcredential-passing.https.html",
+     {}
+    ]
+   ],
    "webauthn/interfaces.https.html": [
     [
      "/webauthn/interfaces.https.html",
      {}
     ]
    ],
-   "webauthn/makecredential-badargs-accountinformation.https.html": [
+   "webauthn/securecontext.http.html": [
     [
-     "/webauthn/makecredential-badargs-accountinformation.https.html",
+     "/webauthn/securecontext.http.html",
      {}
     ]
    ],
-   "webauthn/makecredential-badargs-attestationchallenge.https.html": [
+   "webauthn/securecontext.https.html": [
     [
-     "/webauthn/makecredential-badargs-attestationchallenge.https.html",
-     {}
-    ]
-   ],
-   "webauthn/makecredential-badargs-cryptoparameters.https.html": [
-    [
-     "/webauthn/makecredential-badargs-cryptoparameters.https.html",
+     "/webauthn/securecontext.https.html",
      {}
     ]
    ],
@@ -272476,13 +272741,9 @@
    "873882f22e341bba957eb142ba90fc54c1ceae2f",
    "reftest"
   ],
-  "css/css-position/position-sticky-bottom-ref.html": [
-   "726d6e927d84669e9355701ccd948349d377e6fd",
-   "support"
-  ],
   "css/css-position/position-sticky-bottom.html": [
-   "2a908e60a635dbf765987c0f93d0f33c8ea85de6",
-   "reftest"
+   "b6e687068b26e8660397dfd0d6a501b76739200b",
+   "testharness"
   ],
   "css/css-position/position-sticky-flexbox-ref.html": [
    "f8dedb4a637ea3f4bf79eb621f52a8c4622f8c75",
@@ -272524,13 +272785,9 @@
    "6580451dddfd6f8865925326c170f630f343fbcd",
    "testharness"
   ],
-  "css/css-position/position-sticky-left-ref.html": [
-   "9de7a8ba6019395d729b32e514cc3bd9fee25d2b",
-   "support"
-  ],
   "css/css-position/position-sticky-left.html": [
-   "5151bca08dff652ea728cb8bccbb6b7c6d364dd8",
-   "reftest"
+   "2a04672cdac818a6887eac7d6824ea85d3d0559d",
+   "testharness"
   ],
   "css/css-position/position-sticky-margins-ref.html": [
    "0cdb788c913f47a121114ac5b8e6a140bb08c1ff",
@@ -272608,14 +272865,18 @@
    "224bc984bc6eb4a55931461cf7e51f7b04d219f4",
    "testharness"
   ],
-  "css/css-position/position-sticky-right-ref.html": [
-   "9a4a11b22cb0ea13f38a7dded8469f4848550ed4",
+  "css/css-position/position-sticky-rendering-ref.html": [
+   "589f876752911544957aaa600c5c1559efbf1357",
    "support"
   ],
-  "css/css-position/position-sticky-right.html": [
-   "f79c0e3e99085e483652950b141fe15c3c4d01d8",
+  "css/css-position/position-sticky-rendering.html": [
+   "7b85b2f81d9748bf87f6e21fec60b6159d36b020",
    "reftest"
   ],
+  "css/css-position/position-sticky-right.html": [
+   "80caf6fb1e6c84dbf3e371a11166ac5b71bba687",
+   "testharness"
+  ],
   "css/css-position/position-sticky-root-scroller-ref.html": [
    "b66947a9f1b39c6c489267477d0122eeaeac7341",
    "support"
@@ -272704,13 +272965,9 @@
    "7a030d17358067b78c879bf17171b60d1dc3acd9",
    "reftest"
   ],
-  "css/css-position/position-sticky-top-ref.html": [
-   "e5a05c21494a2e2923d1ed37050ec75db7ab55cd",
-   "support"
-  ],
   "css/css-position/position-sticky-top.html": [
-   "30c0c00c6313a747b51c8b6d4f1301056af56560",
-   "reftest"
+   "bfd49209889fc14cae5af8d7c5e7990fbde451ec",
+   "testharness"
   ],
   "css/css-position/position-sticky-transforms-ref.html": [
    "b01ae263ac6b712912ba2af06edbaeaf75ba0215",
@@ -272736,6 +272993,10 @@
    "b6d16a38b73d4c107e587194818a542fee9d0716",
    "reftest"
   ],
+  "css/css-position/resources/sticky-util.js": [
+   "c7b441a3a07276cad9528dd3ef7d82844d06e2d8",
+   "support"
+  ],
   "css/css-rhythm/OWNERS": [
    "994580f1689c31bd7009470d8c78814509a9e24d",
    "support"
@@ -284928,10 +285189,102 @@
    "236520d8ac6199066d1e082b9860f2381ff61be6",
    "testharness"
   ],
+  "css/css-typed-om/stylevalue-subclasses/cssMatrixComponent.tentative.html": [
+   "4de186a7eb54631bb95662c9d585ea7429bb9498",
+   "testharness"
+  ],
+  "css/css-typed-om/stylevalue-subclasses/cssPerspective.tentative.html": [
+   "95faef2381452acfdaa8b200fb91d0f4f70bfd92",
+   "testharness"
+  ],
   "css/css-typed-om/stylevalue-subclasses/cssPositionValue-interface.html": [
    "dc32e826e1f840c99f3b4bad4f03bd0f9573ce4e",
    "testharness"
   ],
+  "css/css-typed-om/stylevalue-subclasses/cssPositionValue.tentative.html": [
+   "445aa6e5e61d34add060b6870891309bf9e7f71f",
+   "testharness"
+  ],
+  "css/css-typed-om/stylevalue-subclasses/cssRotation.tentative.html": [
+   "e96dd183a70beaae8ce9a24d35ac36362fff13b5",
+   "testharness"
+  ],
+  "css/css-typed-om/stylevalue-subclasses/cssScale.tentative.html": [
+   "779c99a24057f5a2c33fcda77f5897c142659518",
+   "testharness"
+  ],
+  "css/css-typed-om/stylevalue-subclasses/cssSkew.tentative.html": [
+   "91ff825d12373156b3c3b23d23bf866220ef1386",
+   "testharness"
+  ],
+  "css/css-typed-om/stylevalue-subclasses/cssTransformValue.tentative.html": [
+   "4dbec3e781758e19b3a7befb9cef8dfd396ae2fb",
+   "testharness"
+  ],
+  "css/css-typed-om/stylevalue-subclasses/cssTranslation.tentative.html": [
+   "87faf447cd03773e35eb52df213898d0ab765d01",
+   "testharness"
+  ],
+  "css/css-typed-om/stylevalue-subclasses/cssUnparsedValue.tentative.html": [
+   "8fe7703ce860a16e6d2f236c3c178fd03c0299d0",
+   "testharness"
+  ],
+  "css/css-typed-om/stylevalue-subclasses/cssUrlImageValue.tentative.html": [
+   "292ae5c272bbe9eee02ab7da2a465c7e941ab562",
+   "testharness"
+  ],
+  "css/css-typed-om/stylevalue-subclasses/cssVariableReferenceValue.tentative-expected.txt": [
+   "798c1fd86037f28a0e6e098c3262371670189537",
+   "support"
+  ],
+  "css/css-typed-om/stylevalue-subclasses/cssVariableReferenceValue.tentative.html": [
+   "e7fa9d59d1625df70c52a6c0b08c685a64e6c25b",
+   "testharness"
+  ],
+  "css/css-typed-om/stylevalue-subclasses/numeric-objects/arithmetic.tentative.html": [
+   "3d527c8633229d53635adff6e425a8af2b56302e",
+   "testharness"
+  ],
+  "css/css-typed-om/stylevalue-subclasses/numeric-objects/cssMathValue.tentative.html": [
+   "e2779a78b3bdfd83911bede7cba2a88bb589b80d",
+   "testharness"
+  ],
+  "css/css-typed-om/stylevalue-subclasses/numeric-objects/cssUnitValue.tentative-expected.txt": [
+   "8e53477ac61f0ed6e8fcc1134d8f9cb1668b9271",
+   "support"
+  ],
+  "css/css-typed-om/stylevalue-subclasses/numeric-objects/cssUnitValue.tentative.html": [
+   "a46c2ff1bf221cd52b4546f7c07af90849d3096f",
+   "testharness"
+  ],
+  "css/css-typed-om/stylevalue-subclasses/numeric-objects/equals.tentative.html": [
+   "466d97791b5fbec3dd52406bd8da3d277ae5ccdc",
+   "testharness"
+  ],
+  "css/css-typed-om/stylevalue-subclasses/numeric-objects/numeric-factory.tentative-expected.txt": [
+   "d620dfe7fe5597e188486ecf82936fd9f56ac084",
+   "support"
+  ],
+  "css/css-typed-om/stylevalue-subclasses/numeric-objects/numeric-factory.tentative.html": [
+   "5f478898d6923264f94b26be23bda160b8e119eb",
+   "testharness"
+  ],
+  "css/css-typed-om/stylevalue-subclasses/numeric-objects/numeric-typing.tentative.html": [
+   "98c6a0919c36a1ac2c2ed6edd9eb47b9d0a8b618",
+   "testharness"
+  ],
+  "css/css-typed-om/stylevalue-subclasses/numeric-objects/parse.tentative.html": [
+   "a17c4fdc29c474edb1ef3f94d5282d2603dd7227",
+   "testharness"
+  ],
+  "css/css-typed-om/stylevalue-subclasses/numeric-objects/to.tentative.html": [
+   "9216fee77d3666464ed55992fc7df739d85d5667",
+   "testharness"
+  ],
+  "css/css-typed-om/stylevalue-subclasses/numeric-objects/toSum.tentative.html": [
+   "6240dbd450965b33ed5da87f554acc54a32b6ad4",
+   "testharness"
+  ],
   "css/css-typed-om/the-stylepropertymap/computed/computed.tentative-expected.txt": [
    "a43179e472e5881281be2951f11a69f66c87d4c7",
    "support"
@@ -311197,7 +311550,7 @@
    "testharness"
   ],
   "html/dom/usvstring-reflection.html": [
-   "353c2ad8b640e34a8bc71d5fe1b5be3c101a4dc2",
+   "a48e32b268a8117ed803c8ede806a879e1556d76",
    "testharness"
   ],
   "html/editing/.gitkeep": [
@@ -324592,6 +324945,10 @@
    "57cdb7dd7f3f7876b045661b8187beb14de67ea9",
    "testharness"
   ],
+  "html/syntax/parsing/html5lib_menuitem-element_run_type=write-expected.txt": [
+   "ff6613c2491929c73ba5e746519a19a683a5bb46",
+   "support"
+  ],
   "html/syntax/parsing/html5lib_namespace-sensitivity.html": [
    "527963e681efad54c64cddfceac31448079d1517",
    "testharness"
@@ -324640,6 +324997,18 @@
    "022886883adbc6ec84d32eb50e0202c2f3f0bd7c",
    "testharness"
   ],
+  "html/syntax/parsing/html5lib_template_run_type=uri-expected.txt": [
+   "b8e02d39f2c2b67ec726b1310ab46fcf05db1f0b",
+   "support"
+  ],
+  "html/syntax/parsing/html5lib_template_run_type=write-expected.txt": [
+   "b8e02d39f2c2b67ec726b1310ab46fcf05db1f0b",
+   "support"
+  ],
+  "html/syntax/parsing/html5lib_template_run_type=write_single-expected.txt": [
+   "b8e02d39f2c2b67ec726b1310ab46fcf05db1f0b",
+   "support"
+  ],
   "html/syntax/parsing/html5lib_tests1.html": [
    "ba8d3374c33a5aa566751e1890f03af1a5ea01f9",
    "testharness"
@@ -324656,6 +325025,14 @@
    "543ccbd05dad7a59c4f6bbb1ab52e2dfce58c08f",
    "testharness"
   ],
+  "html/syntax/parsing/html5lib_tests11_run_type=uri-expected.txt": [
+   "a595d947220e8089907f05b6ccbd4b3b6301ad92",
+   "support"
+  ],
+  "html/syntax/parsing/html5lib_tests11_run_type=write-expected.txt": [
+   "a595d947220e8089907f05b6ccbd4b3b6301ad92",
+   "support"
+  ],
   "html/syntax/parsing/html5lib_tests12.html": [
    "50958869e795af40beba5d227705c9d3aba1e0b6",
    "testharness"
@@ -324724,6 +325101,18 @@
    "4018d80aea8cd572e40c10c21c991126d15a7e29",
    "testharness"
   ],
+  "html/syntax/parsing/html5lib_tests25_run_type=uri-expected.txt": [
+   "0a200d34e3677c3e968214d4453983dbe0227c5f",
+   "support"
+  ],
+  "html/syntax/parsing/html5lib_tests25_run_type=write-expected.txt": [
+   "0a200d34e3677c3e968214d4453983dbe0227c5f",
+   "support"
+  ],
+  "html/syntax/parsing/html5lib_tests25_run_type=write_single-expected.txt": [
+   "0a200d34e3677c3e968214d4453983dbe0227c5f",
+   "support"
+  ],
   "html/syntax/parsing/html5lib_tests26.html": [
    "0b5511eb578fd6c32702e9712ac9b1986f1dc928",
    "testharness"
@@ -324764,6 +325153,14 @@
    "1373d5b587b45c8ec0a48bc16d46fec852c1c441",
    "testharness"
   ],
+  "html/syntax/parsing/html5lib_webkit02_run_type=write-expected.txt": [
+   "8c50ccfd9b8842e9d6fa33a15945cc5dad1fabc6",
+   "support"
+  ],
+  "html/syntax/parsing/html5lib_webkit02_run_type=write_single-expected.txt": [
+   "8c50ccfd9b8842e9d6fa33a15945cc5dad1fabc6",
+   "support"
+  ],
   "html/syntax/parsing/math-parse01.html": [
    "9b670028f08b5fab713e19a443b9505cb9de5fd3",
    "testharness"
@@ -335741,7 +336138,7 @@
    "testharness"
   ],
   "performance-timeline/idlharness.html": [
-   "30e6893af2cda301efb45fa7cfe16cec04701445",
+   "d6ce8e5c21b42843caea8e61c1637d75c2e51d64",
    "testharness"
   ],
   "performance-timeline/performanceentry-tojson.html": [
@@ -352296,8 +352693,36 @@
    "832fb99e215923e9d102f48f2a0cd06ea11ff86b",
    "support"
   ],
+  "webauthn/createcredential-badargs-rp.https-expected.txt": [
+   "6b8193f882d66d96ace82fbd997eb624d90b19e7",
+   "support"
+  ],
+  "webauthn/createcredential-badargs-rp.https.html": [
+   "941a9bda02e22b7d54855e3a4714a49d8392fa9d",
+   "testharness"
+  ],
+  "webauthn/createcredential-passing.https-expected.txt": [
+   "586ba28e10447e23c641a068fe56a209afaf1fe3",
+   "support"
+  ],
+  "webauthn/createcredential-passing.https.html": [
+   "32a6ac38f91ec6b887e9e57519eb1603b4abcdbb",
+   "testharness"
+  ],
+  "webauthn/getcredential-passing.https-expected.txt": [
+   "4fb84877a79a861b6172b81b2e3a78c90fd88920",
+   "support"
+  ],
+  "webauthn/getcredential-passing.https.html": [
+   "6272128ea3af65ecb4fc40055b062a678bfbb2fd",
+   "testharness"
+  ],
   "webauthn/helpers.js": [
-   "bc38559e447710f701bc5392b0d02704ae97e970",
+   "e6224e8e2be8657e2e312f4197cbe0225c819cea",
+   "support"
+  ],
+  "webauthn/interfaces.https-expected.txt": [
+   "3634a280bf7fb91332ae9510d383f1da4d88eb86",
    "support"
   ],
   "webauthn/interfaces.https.html": [
@@ -352305,19 +352730,19 @@
    "testharness"
   ],
   "webauthn/interfaces.idl": [
-   "78cdd63fc1b0e3eff699976b67b72d46cf108ed2",
+   "77076f0828383c0f48f36131a81b25186622b3a3",
    "support"
   ],
-  "webauthn/makecredential-badargs-accountinformation.https.html": [
-   "7f81446a152ab31223b79e3089eb29505a8b603d",
+  "webauthn/securecontext.http-expected.txt": [
+   "956293f274c2c7102d8b20b6ee26edbd3795d174",
+   "support"
+  ],
+  "webauthn/securecontext.http.html": [
+   "afc1492723d140e34027a3bdbf0d1e09843ef5d6",
    "testharness"
   ],
-  "webauthn/makecredential-badargs-attestationchallenge.https.html": [
-   "26fbc55b0c313be854ddd59469baf6dcdd5d21c6",
-   "testharness"
-  ],
-  "webauthn/makecredential-badargs-cryptoparameters.https.html": [
-   "9e2cbb2a667cf57f979c3e67516fb63fedd18d46",
+  "webauthn/securecontext.https.html": [
+   "7f7a7aba32b9e049c618203121fae0884936643a",
    "testharness"
   ],
   "webmessaging/Channel_postMessage_Blob.htm": [
@@ -353804,10 +354229,18 @@
    "04a3ceb6f0f0ee9cc8e58b298a9c086faf432fcd",
    "testharness"
   ],
+  "websockets/constructor/002-expected.txt": [
+   "a210de901c91ef10d02e126feb821a59fbc69b8d",
+   "support"
+  ],
   "websockets/constructor/002.html": [
    "4288a4cfc4ae73afb9b93b2c2c8e05c182a6a5e1",
    "testharness"
   ],
+  "websockets/constructor/002_wss-expected.txt": [
+   "a210de901c91ef10d02e126feb821a59fbc69b8d",
+   "support"
+  ],
   "websockets/constructor/004.html": [
    "4d2986bb16eb72796627a6552461d80c29c444e4",
    "testharness"
@@ -353904,10 +354337,18 @@
    "676deb52c3b881fe96e12198a7f068d1392f63cf",
    "testharness"
   ],
+  "websockets/cookies/007-expected.txt": [
+   "921b5ace8914e605c5dc77780cebf05057d32fc6",
+   "support"
+  ],
   "websockets/cookies/007.html": [
    "770db52470c5b18b6d92384763568d1dd859eb89",
    "testharness"
   ],
+  "websockets/cookies/007_wss-expected.txt": [
+   "921b5ace8914e605c5dc77780cebf05057d32fc6",
+   "support"
+  ],
   "websockets/cookies/support/set-cookie.py": [
    "4975c1735e1140a7528056c954c34a63227c3180",
    "support"
@@ -354068,18 +354509,34 @@
    "7b66ec99cd13c7a919fceab5e4254d1e33250874",
    "testharness"
   ],
+  "websockets/interfaces/WebSocket/close/close-connecting-expected.txt": [
+   "4899ceb5c7be7ac207b4d0d15351b5eb8a099129",
+   "support"
+  ],
   "websockets/interfaces/WebSocket/close/close-connecting.html": [
    "74319c41269f449f54f2405705c84a908d5609c9",
    "testharness"
   ],
+  "websockets/interfaces/WebSocket/close/close-connecting_wss-expected.txt": [
+   "4899ceb5c7be7ac207b4d0d15351b5eb8a099129",
+   "support"
+  ],
   "websockets/interfaces/WebSocket/close/close-multiple.html": [
    "9b58c23715dbfb53f5a3a8a8d00fc176976cc94c",
    "testharness"
   ],
+  "websockets/interfaces/WebSocket/close/close-nested-expected.txt": [
+   "4febbdf65a1100c430aca09a796fc10fcf7ac389",
+   "support"
+  ],
   "websockets/interfaces/WebSocket/close/close-nested.html": [
    "a9e476bfe195cee756dd8da46f88924116757afe",
    "testharness"
   ],
+  "websockets/interfaces/WebSocket/close/close-nested_wss-expected.txt": [
+   "4febbdf65a1100c430aca09a796fc10fcf7ac389",
+   "support"
+  ],
   "websockets/interfaces/WebSocket/close/close-replace.html": [
    "f97a87a3dc08346a4f5443fc1a6b50b2ab85e840",
    "testharness"
@@ -354204,10 +354661,18 @@
    "33c9eded70c36a50d05c72ce9806862aa91d270c",
    "testharness"
   ],
+  "websockets/interfaces/WebSocket/readyState/003-expected.txt": [
+   "7a2a909d51eafdc1d59f71182be7cbacfce7ccf7",
+   "support"
+  ],
   "websockets/interfaces/WebSocket/readyState/003.html": [
    "e41609436a7a4de147e48dfc8a9b0261f23a665b",
    "testharness"
   ],
+  "websockets/interfaces/WebSocket/readyState/003_wss-expected.txt": [
+   "7a2a909d51eafdc1d59f71182be7cbacfce7ccf7",
+   "support"
+  ],
   "websockets/interfaces/WebSocket/readyState/004.html": [
    "da71ca7b7aa2aed5995365530764c8d13f6fe655",
    "testharness"
@@ -354376,10 +354841,18 @@
    "e689149429d1e29775d7c7f6f5ad6afdde0a1b39",
    "support"
   ],
+  "websockets/unload-a-document/002-expected.txt": [
+   "9d655a41fb3f030f0c8dc7e1b9cd19dd89c550fd",
+   "support"
+  ],
   "websockets/unload-a-document/002.html": [
    "aaf934be13d0c9df63a1ff5da6d90cb290855b11",
    "testharness"
   ],
+  "websockets/unload-a-document/002_wss-expected.txt": [
+   "9d655a41fb3f030f0c8dc7e1b9cd19dd89c550fd",
+   "support"
+  ],
   "websockets/unload-a-document/003.html": [
    "3d1861da30072c3e73f9f1e656f836b8cec7c150",
    "testharness"
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-align/content-distribution/parse-align-content-001.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-align/content-distribution/parse-align-content-001.html
new file mode 100644
index 0000000..15a5cda2
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-align/content-distribution/parse-align-content-001.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Content Distribution: align-content - setting values via CSS</title>
+<link rel="author" title="Javier Fernandez" href="mailto:jfernandez@igalia.com" />
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#content-distribution" />
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#propdef-align-content" />
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#typedef-content-position" />
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#typedef-content-distribution" />
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#typedef-baseline-position" />
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#typedef-overflow-position" />
+<link rel="stylesheet" href="../../support/alignment.css" >
+<meta name="assert" content="Check that the computed value is the specified value and the JS value is empty."/>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/css-align/resources/alignment-parsing-utils.js"></script>
+<div id="log"></div>
+<script>
+    let classes = Object.assign({"Normal":"normal"}, contentPositionClasses, distributionClasses,
+                                baselineClasses, overflowClasses);
+
+    for (var key in classes) {
+        let specifiedValue = classes[key];
+        element = document.createElement("div");
+        element.className = "alignContent" + key;
+        document.body.appendChild(element);
+        test(function() {
+            let computedValue = specifiedValue;
+            if (specifiedValue === "baseline")
+                computedValue = "first baseline";
+            checkValues(element, "alignContent", "align-content", "", computedValue);
+        }, "Checking align-content: " + specifiedValue);
+    }
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-align/content-distribution/parse-align-content-002.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-align/content-distribution/parse-align-content-002.html
new file mode 100644
index 0000000..9f4272e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-align/content-distribution/parse-align-content-002.html
@@ -0,0 +1,57 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Content Distribution: align-content - 'initial' value</title>
+<link rel="author" title="Javier Fernandez" href="mailto:jfernandez@igalia.com" />
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#content-distribution" />
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#propdef-align-content" />
+<link rel="help" href="https://drafts.csswg.org/css-cascade/#initial-values" />
+<meta name="assert" content="Check the 'initial' value in diferent scenarios."/>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/css-align/resources/alignment-parsing-utils.js"></script>
+<div id="log"></div>
+<script>
+container = document.createElement("div");
+element = document.createElement("div");
+container.appendChild(element);
+document.body.appendChild(container);
+
+test(function() {
+    element = document.createElement("div");
+    document.body.appendChild(element);
+    checkValues(element, "alignContent", "align-content", "", "normal");
+}, "Test 'initial' value when nothing is specified");
+
+test(function() {
+    container.style.display = "";
+    checkInitialValues(element, "alignContent", "align-content", "center", "normal");
+}, "Test align-content: 'initial'");
+
+test(function() {
+    container.style.display = "grid";
+    checkInitialValues(element, "alignContent", "align-content", "safe left", "normal");
+}, "Test grid items align-content: 'initial'");
+
+test(function() {
+    container.style.display = "flex";
+    checkInitialValues(element, "alignContent", "align-content", "unsafe right", "normal");
+}, "Test flex items align-content: 'initial'");
+
+test(function() {
+    container.style.display = "";
+    element.style.position = "absolute";
+    checkInitialValues(element, "alignContent", "align-content", "left", "normal");
+}, "Test absolute positioned elements align-content: 'initial'");
+
+test(function() {
+    container.style.display = "grid";
+    element.style.position = "absolute";
+    checkInitialValues(element, "alignContent", "align-content", "right", "normal");
+}, "Test absolute positioned grid items align-content: 'initial'");
+
+test(function() {
+    container.style.display = "flex";
+    element.style.position = "absolute";
+    checkInitialValues(element, "alignContent", "align-content", "end", "normal");
+}, "Test absolute positioned flex items align-content: 'initial'");
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-align/content-distribution/parse-align-content-003.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-align/content-distribution/parse-align-content-003.html
new file mode 100644
index 0000000..4997857
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-align/content-distribution/parse-align-content-003.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Content Disrtribution: align-content - setting values via JS</title>
+<link rel="author" title="Javier Fernandez" href="mailto:jfernandez@igalia.com" />
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#content-distribution" />
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#propdef-align-content" />
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#typedef-content-position" />
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#typedef-content-distribution" />
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#typedef-baseline-position" />
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#typedef-overflow-position" />
+<meta name="assert" content="Check that the computed value is the specified value and the same than the JS value."/>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/css-align/resources/alignment-parsing-utils.js"></script>
+<div id="log"></div>
+<script>
+    element = document.createElement("div");
+    document.body.appendChild(element);
+
+    let classes = Object.assign({"Normal":"normal"}, contentPositionClasses, distributionClasses,
+                                baselineClasses, overflowClasses);
+
+    for (var key in classes) {
+        let specifiedValue = classes[key];
+        test(function() {
+            element.style.alignContent = specifiedValue;
+            let computedValue = specifiedValue;
+            if (specifiedValue === "baseline")
+                computedValue = "first baseline";
+            checkValues(element, "alignContent", "align-content",  specifiedValue, computedValue);
+        }, "Checking align-content: " + specifiedValue);
+    }
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-align/content-distribution/parse-align-content-004.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-align/content-distribution/parse-align-content-004.html
new file mode 100644
index 0000000..f2fc8bd
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-align/content-distribution/parse-align-content-004.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Content Distribution: align-content - invalid values</title>
+<link rel="author" title="Javier Fernandez" href="mailto:jfernandez@igalia.com" />
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#content-distribution" />
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#propdef-align-content" />
+<meta name="assert" content="Check bad combinations of specified values."/>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/css-align/resources/alignment-parsing-utils.js"></script>
+<div id="log"></div>
+<script>
+    element = document.createElement("div");
+    document.body.appendChild(element);
+
+    let values = ["auto", "legacy", "self-start"].concat(invalidPositionValues, invalidDistributionValues);
+
+    values.forEach(function(value) {
+        test(function() {
+            checkBadValues(element, "alignContent", "align-content",  value);
+        }, "Checking invalid combination - align-content: " + value);
+    });
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-align/content-distribution/parse-align-content-005.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-align/content-distribution/parse-align-content-005.html
new file mode 100644
index 0000000..e251911
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-align/content-distribution/parse-align-content-005.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Content Distibution: align-content - inherit value</title>
+<link rel="author" title="Javier Fernandez" href="mailto:jfernandez@igalia.com" />
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#content-distribution" />
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#propdef-align-content" />
+<meta name="assert" content="Check bad cobinations of specified values."/>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/css-align/resources/alignment-parsing-utils.js"></script>
+<div id="log"></div>
+<script>
+test(function() {
+    checkInheritValues("alignContent", "align-content", "end");
+}, "Test the value 'inherit' overrides current value ('end')");
+test(function() {
+    checkInheritValues("alignContent", "align-content", "safe left");
+}, "Test the value 'inherit' overrides current value ('safe left')");
+test(function() {
+    checkInheritValues("alignContent", "align-content", "unsafe center");
+}, "Test the value 'inherit' overrides current value ('unsafe center')");
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-align/content-distribution/parse-justify-content-001.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-align/content-distribution/parse-justify-content-001.html
new file mode 100644
index 0000000..287f2f6
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-align/content-distribution/parse-justify-content-001.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Content Distribution: justify-content - setting values via CSS</title>
+<link rel="author" title="Javier Fernandez" href="mailto:jfernandez@igalia.com" />
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#content-distribution" />
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#propdef-justify-content" />
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#typedef-content-position" />
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#typedef-content-distribution" />
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#typedef-baseline-position" />
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#typedef-overflow-position" />
+<link rel="stylesheet" href="../../support/alignment.css" >
+<meta name="assert" content="Check that the computed value is the specified value and the JS value is empty."/>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/css-align/resources/alignment-parsing-utils.js"></script>
+<div id="log"></div>
+<script>
+    let classes = Object.assign({"Normal":"normal"}, contentPositionClasses, distributionClasses,
+                                baselineClasses, overflowClasses);
+
+    for (var key in classes) {
+        let specifiedValue = classes[key];
+        element = document.createElement("div");
+        element.className = "justifyContent" + key;
+        document.body.appendChild(element);
+        test(function() {
+            let computedValue = specifiedValue;
+            if (specifiedValue === "baseline")
+                computedValue = "first baseline";
+            checkValues(element, "justifyContent", "justify-content", "", computedValue);
+        }, "Checking justify-content: " + specifiedValue);
+    }
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-align/content-distribution/parse-justify-content-002.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-align/content-distribution/parse-justify-content-002.html
new file mode 100644
index 0000000..a551aea
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-align/content-distribution/parse-justify-content-002.html
@@ -0,0 +1,57 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Content Distribution: justify-content - 'initial' value</title>
+<link rel="author" title="Javier Fernandez" href="mailto:jfernandez@igalia.com" />
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#content-distribution" />
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#propdef-justify-content" />
+<link rel="help" href="https://drafts.csswg.org/css-cascade/#initial-values" />
+<meta name="assert" content="Check the 'initial' value in diferent scenarios."/>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/css-align/resources/alignment-parsing-utils.js"></script>
+<div id="log"></div>
+<script>
+container = document.createElement("div");
+element = document.createElement("div");
+container.appendChild(element);
+document.body.appendChild(container);
+
+test(function() {
+    element = document.createElement("div");
+    document.body.appendChild(element);
+    checkValues(element, "justifyContent", "justify-content", "", "normal");
+}, "Test 'initial' value when nothing is specified");
+
+test(function() {
+    container.style.display = "";
+    checkInitialValues(element, "justifyContent", "justify-content", "center", "normal");
+}, "Test justify-content: 'initial'");
+
+test(function() {
+    container.style.display = "grid";
+    checkInitialValues(element, "justifyContent", "justify-content", "safe left", "normal");
+}, "Test grid items justify-content: 'initial'");
+
+test(function() {
+    container.style.display = "flex";
+    checkInitialValues(element, "justifyContent", "justify-content", "unsafe right", "normal");
+}, "Test flex items justify-content: 'initial'");
+
+test(function() {
+    container.style.display = "";
+    element.style.position = "absolute";
+    checkInitialValues(element, "justifyContent", "justify-content", "left", "normal");
+}, "Test absolute positioned elements justify-content: 'initial'");
+
+test(function() {
+    container.style.display = "grid";
+    element.style.position = "absolute";
+    checkInitialValues(element, "justifyContent", "justify-content", "right", "normal");
+}, "Test absolute positioned grid items justify-content: 'initial'");
+
+test(function() {
+    container.style.display = "flex";
+    element.style.position = "absolute";
+    checkInitialValues(element, "justifyContent", "justify-content", "end", "normal");
+}, "Test absolute positioned flex items justify-content: 'initial'");
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-align/content-distribution/parse-justify-content-003.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-align/content-distribution/parse-justify-content-003.html
new file mode 100644
index 0000000..f1445c84
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-align/content-distribution/parse-justify-content-003.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Content Disrtribution: justify-content - setting values via JS</title>
+<link rel="author" title="Javier Fernandez" href="mailto:jfernandez@igalia.com" />
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#content-distribution" />
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#propdef-justify-content" />
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#typedef-content-position" />
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#typedef-content-distribution" />
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#typedef-baseline-position" />
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#typedef-overflow-position" />
+<meta name="assert" content="Check that the computed value is the specified value and the same than the JS value."/>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/css-align/resources/alignment-parsing-utils.js"></script>
+<div id="log"></div>
+<script>
+    element = document.createElement("div");
+    document.body.appendChild(element);
+
+    let classes = Object.assign({"Normal":"normal"}, contentPositionClasses, distributionClasses,
+                                baselineClasses, overflowClasses);
+
+    for (var key in classes) {
+        let specifiedValue = classes[key];
+        test(function() {
+            element.style.justifyContent = specifiedValue;
+            let computedValue = specifiedValue;
+            if (specifiedValue === "baseline")
+                computedValue = "first baseline";
+            checkValues(element, "justifyContent", "justify-content",  specifiedValue, computedValue);
+        }, "Checking justify-content: " + specifiedValue);
+    }
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-align/content-distribution/parse-justify-content-004.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-align/content-distribution/parse-justify-content-004.html
new file mode 100644
index 0000000..6ba6f8b
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-align/content-distribution/parse-justify-content-004.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Content Distribution: justify-content - invalid values</title>
+<link rel="author" title="Javier Fernandez" href="mailto:jfernandez@igalia.com" />
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#content-distribution" />
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#propdef-justify-content" />
+<meta name="assert" content="Check bad combinations of specified values."/>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/css-align/resources/alignment-parsing-utils.js"></script>
+<div id="log"></div>
+<script>
+    element = document.createElement("div");
+    document.body.appendChild(element);
+
+    let values = ["auto", "legacy", "self-start"].concat(invalidPositionValues, invalidDistributionValues);
+
+    values.forEach(function(value) {
+        test(function() {
+            checkBadValues(element, "justifyContent", "justify-content",  value);
+        }, "Checking invalid combination - justify-content: " + value);
+    });
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-align/content-distribution/parse-justify-content-005.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-align/content-distribution/parse-justify-content-005.html
new file mode 100644
index 0000000..32949e88
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-align/content-distribution/parse-justify-content-005.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Content Distibution: justify-content - inherit value</title>
+<link rel="author" title="Javier Fernandez" href="mailto:jfernandez@igalia.com" />
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#content-distribution" />
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#propdef-justify-content" />
+<meta name="assert" content="Check bad cobinations of specified values."/>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/css-align/resources/alignment-parsing-utils.js"></script>
+<div id="log"></div>
+<script>
+test(function() {
+    checkInheritValues("justifyContent", "justify-content", "end");
+}, "Test the value 'inherit' overrides current value ('end')");
+test(function() {
+    checkInheritValues("justifyContent", "justify-content", "safe left");
+}, "Test the value 'inherit' overrides current value ('safe left')");
+test(function() {
+    checkInheritValues("justifyContent", "justify-content", "unsafe center");
+}, "Test the value 'inherit' overrides current value ('unsafe center')");
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-align/default-alignment/parse-align-items-001.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-align/default-alignment/parse-align-items-001.html
new file mode 100644
index 0000000..7905501
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-align/default-alignment/parse-align-items-001.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Default-Alignment: align-items - setting values via CSS</title>
+<link rel="author" title="Javier Fernandez" href="mailto:jfernandez@igalia.com" />
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#default-alignment" />
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#propdef-align-items" />
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#typedef-self-position" />
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#typedef-baseline-position" />
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#typedef-overflow-position" />
+<link rel="stylesheet" href="../../support/alignment.css" >
+<meta name="assert" content="Check that the computed value is the specified value and the JS value is empty."/>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/css-align/resources/alignment-parsing-utils.js"></script>
+<div id="log"></div>
+<script>
+    let classes = Object.assign({"Normal":"normal", "Stretch":"stretch"}, selfPositionClasses,
+                                baselineClasses, overflowClasses);
+
+    for (var key in classes) {
+        let specifiedValue = classes[key];
+        element = document.createElement("div");
+        element.className = "alignItems" + key;
+        document.body.appendChild(element);
+        test(function() {
+            let computedValue = specifiedValue;
+            if (specifiedValue === "baseline")
+                computedValue = "first baseline";
+            checkValues(element, "alignItems", "align-items", "", computedValue);
+        }, "Checking align-items: " + specifiedValue);
+    }
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-align/default-alignment/parse-align-items-002.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-align/default-alignment/parse-align-items-002.html
new file mode 100644
index 0000000..dad2542
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-align/default-alignment/parse-align-items-002.html
@@ -0,0 +1,57 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Default-Alignment: align-items - 'initial' value</title>
+<link rel="author" title="Javier Fernandez" href="mailto:jfernandez@igalia.com" />
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#default-alignment" />
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#propdef-align-items" />
+<link rel="help" href="https://drafts.csswg.org/css-cascade/#initial-values" />
+<meta name="assert" content="Check the 'initial' value in diferent scenarios."/>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/css-align/resources/alignment-parsing-utils.js"></script>
+<div id="log"></div>
+<script>
+container = document.createElement("div");
+element = document.createElement("div");
+container.appendChild(element);
+document.body.appendChild(container);
+
+test(function() {
+    element = document.createElement("div");
+    document.body.appendChild(element);
+    checkValues(element, "alignItems", "align-items", "", "normal");
+}, "Test 'initial' value when nothing is specified");
+
+test(function() {
+    container.style.display = "";
+    checkInitialValues(element, "alignItems", "align-items", "center", "normal");
+}, "Test align-items: 'initial'");
+
+test(function() {
+    container.style.display = "grid";
+    checkInitialValues(element, "alignItems", "align-items", "safe left", "normal");
+}, "Test grid items align-items: 'initial'");
+
+test(function() {
+    container.style.display = "flex";
+    checkInitialValues(element, "alignItems", "align-items", "unsafe right", "normal");
+}, "Test flex items align-items: 'initial'");
+
+test(function() {
+    container.style.display = "";
+    element.style.position = "absolute";
+    checkInitialValues(element, "alignItems", "align-items", "left", "normal");
+}, "Test absolute positioned elements align-items: 'initial'");
+
+test(function() {
+    container.style.display = "grid";
+    element.style.position = "absolute";
+    checkInitialValues(element, "alignItems", "align-items", "right", "normal");
+}, "Test absolute positioned grid items align-items: 'initial'");
+
+test(function() {
+    container.style.display = "flex";
+    element.style.position = "absolute";
+    checkInitialValues(element, "alignItems", "align-items", "end", "normal");
+}, "Test absolute positioned flex items align-items: 'initial'");
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-align/default-alignment/parse-align-items-003.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-align/default-alignment/parse-align-items-003.html
new file mode 100644
index 0000000..03c4951
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-align/default-alignment/parse-align-items-003.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Default-Alignment: align-items - setting values via JS</title>
+<link rel="author" title="Javier Fernandez" href="mailto:jfernandez@igalia.com" />
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#default-alignment" />
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#propdef-align-items" />
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#typedef-self-position" />
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#typedef-baseline-position" />
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#typedef-overflow-position" />
+<meta name="assert" content="Check that the computed value is the specified value and the same than the JS value."/>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/css-align/resources/alignment-parsing-utils.js"></script>
+<div id="log"></div>
+<script>
+    element = document.createElement("div");
+    document.body.appendChild(element);
+
+    let classes = Object.assign({"Normal":"normal", "Stretch":"stretch"}, selfPositionClasses,
+                                baselineClasses, overflowClasses);
+
+    for (var key in classes) {
+        let specifiedValue = classes[key];
+        test(function() {
+            element.style.alignItems = specifiedValue;
+            let computedValue = specifiedValue;
+            if (specifiedValue === "baseline")
+                computedValue = "first baseline";
+            checkValues(element, "alignItems", "align-items",  specifiedValue, computedValue);
+        }, "Checking align-items: " + specifiedValue);
+    }
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-align/default-alignment/parse-align-items-004.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-align/default-alignment/parse-align-items-004.html
new file mode 100644
index 0000000..98e03d1
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-align/default-alignment/parse-align-items-004.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Default-Alignment: align-items - invalid values</title>
+<link rel="author" title="Javier Fernandez" href="mailto:jfernandez@igalia.com" />
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#default-alignment" />
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#propdef-align-items" />
+<meta name="assert" content="Check bad combinations of specified values."/>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/css-align/resources/alignment-parsing-utils.js"></script>
+<div id="log"></div>
+<script>
+    element = document.createElement("div");
+    document.body.appendChild(element);
+
+    let values = ["auto", "legacy", "space-around"].concat(invalidPositionValues);
+
+    values.forEach(function(value) {
+        test(function() {
+            checkBadValues(element, "alignItems", "align-items",  value);
+        }, "Checking invalid combination - align-items: " + value);
+    });
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-align/default-alignment/parse-align-items-005.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-align/default-alignment/parse-align-items-005.html
new file mode 100644
index 0000000..ef8c1bd5
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-align/default-alignment/parse-align-items-005.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Default-Alignment: align-items - inherit value</title>
+<link rel="author" title="Javier Fernandez" href="mailto:jfernandez@igalia.com" />
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#default-alignment" />
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#propdef-align-items" />
+<meta name="assert" content="Check bad cobinations of specified values."/>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/css-align/resources/alignment-parsing-utils.js"></script>
+<div id="log"></div>
+<script>
+test(function() {
+    checkInheritValues("alignItems", "align-items", "end");
+}, "Test the value 'inherit' overrides current value ('end')");
+test(function() {
+    checkInheritValues("alignItems", "align-items", "safe left");
+}, "Test the value 'inherit' overrides current value ('safe left')");
+test(function() {
+    checkInheritValues("alignItems", "align-items", "unsafe center");
+}, "Test the value 'inherit' overrides current value ('unsafe center')");
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-align/default-alignment/parse-justify-items-001.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-align/default-alignment/parse-justify-items-001.html
new file mode 100644
index 0000000..78a0b394
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-align/default-alignment/parse-justify-items-001.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Default-Alignment: justify-items - setting values via CSS</title>
+<link rel="author" title="Javier Fernandez" href="mailto:jfernandez@igalia.com" />
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#default-alignment" />
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#propdef-justify-items" />
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#typedef-self-position" />
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#typedef-baseline-position" />
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#typedef-overflow-position" />
+<link rel="stylesheet" href="../../support/alignment.css" >
+<meta name="assert" content="Check that the computed value is the specified value and the JS value is empty."/>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/css-align/resources/alignment-parsing-utils.js"></script>
+<div id="log"></div>
+<script>
+    let classes = Object.assign({"Normal":"normal", "Stretch":"stretch"},
+                                selfPositionClasses, baselineClasses, overflowClasses);
+
+    for (var key in classes) {
+        let specifiedValue = classes[key];
+        element = document.createElement("div");
+        element.className = "justifyItems" + key;
+        document.body.appendChild(element);
+        test(function() {
+            let computedValue = specifiedValue;
+            if (specifiedValue === "baseline")
+                computedValue = "first baseline";
+            checkValues(element, "justifyItems", "justify-items", "", computedValue);
+        }, "Checking justify-items: " + specifiedValue);
+    }
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-align/default-alignment/parse-justify-items-002.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-align/default-alignment/parse-justify-items-002.html
new file mode 100644
index 0000000..53263b9
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-align/default-alignment/parse-justify-items-002.html
@@ -0,0 +1,57 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Default-Alignment: justify-items - 'initial' value</title>
+<link rel="author" title="Javier Fernandez" href="mailto:jfernandez@igalia.com" />
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#default-alignment" />
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#propdef-justify-items" />
+<link rel="help" href="https://drafts.csswg.org/css-cascade/#initial-values" />
+<meta name="assert" content="Check the 'initial' value in diferent scenarios."/>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/css-align/resources/alignment-parsing-utils.js"></script>
+<div id="log"></div>
+<script>
+container = document.createElement("div");
+element = document.createElement("div");
+container.appendChild(element);
+document.body.appendChild(container);
+
+test(function() {
+    element = document.createElement("div");
+    document.body.appendChild(element);
+    checkValues(element, "justifyItems", "justify-items", "", "legacy");
+}, "Test 'initial' value when nothing is specified");
+
+test(function() {
+    container.style.display = "";
+    checkInitialValues(element, "justifyItems", "justify-items", "center", "legacy");
+}, "Test justify-items: 'initial'");
+
+test(function() {
+    container.style.display = "grid";
+    checkInitialValues(element, "justifyItems", "justify-items", "safe left", "legacy");
+}, "Test grid items justify-items: 'initial'");
+
+test(function() {
+    container.style.display = "flex";
+    checkInitialValues(element, "justifyItems", "justify-items", "unsafe right", "legacy");
+}, "Test flex items justify-items: 'initial'");
+
+test(function() {
+    container.style.display = "";
+    element.style.position = "absolute";
+    checkInitialValues(element, "justifyItems", "justify-items", "left", "legacy");
+}, "Test absolute positioned elements justify-items: 'initial'");
+
+test(function() {
+    container.style.display = "grid";
+    element.style.position = "absolute";
+    checkInitialValues(element, "justifyItems", "justify-items", "right", "legacy");
+}, "Test absolute positioned grid items justify-items: 'initial'");
+
+test(function() {
+    container.style.display = "flex";
+    element.style.position = "absolute";
+    checkInitialValues(element, "justifyItems", "justify-items", "end", "legacy");
+}, "Test absolute positioned flex items justify-items: 'initial'");
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-align/default-alignment/parse-justify-items-003.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-align/default-alignment/parse-justify-items-003.html
new file mode 100644
index 0000000..3b9ef008
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-align/default-alignment/parse-justify-items-003.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Default-Alignment: justify-items - setting values via JS</title>
+<link rel="author" title="Javier Fernandez" href="mailto:jfernandez@igalia.com" />
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#default-alignment" />
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#propdef-justify-items" />
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#typedef-self-position" />
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#typedef-baseline-position" />
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#typedef-overflow-position" />
+<meta name="assert" content="Check that the computed value is the specified value and the same than the JS value."/>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/css-align/resources/alignment-parsing-utils.js"></script>
+<div id="log"></div>
+<script>
+    element = document.createElement("div");
+    document.body.appendChild(element);
+
+    let classes = Object.assign({"Normal":"normal", "Stretch":"stretch"}, selfPositionClasses,
+                                baselineClasses, overflowClasses, legacyValues);
+
+    for (var key in classes) {
+        let specifiedValue = classes[key];
+        test(function() {
+            element.style.justifyItems = specifiedValue;
+            let computedValue = specifiedValue;
+            if (specifiedValue === "baseline")
+                computedValue = "first baseline";
+            checkValues(element, "justifyItems", "justify-items",  specifiedValue, computedValue);
+        }, "Checking justify-items: " + specifiedValue);
+    }
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-align/default-alignment/parse-justify-items-004.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-align/default-alignment/parse-justify-items-004.html
new file mode 100644
index 0000000..0574f8e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-align/default-alignment/parse-justify-items-004.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Default-Alignment: justify-items - invalid values</title>
+<link rel="author" title="Javier Fernandez" href="mailto:jfernandez@igalia.com" />
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#default-alignment" />
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#propdef-justify-items" />
+<meta name="assert" content="Check bad combinations of specified values."/>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/css-align/resources/alignment-parsing-utils.js"></script>
+<div id="log"></div>
+<script>
+    element = document.createElement("div");
+    document.body.appendChild(element);
+
+    let values = ["auto", "space-around"].concat(invalidPositionValues, invalidLEgacyValues);
+
+    values.forEach(function(value) {
+        test(function() {
+            checkBadValues(element, "justifyItems", "justify-items",  value);
+        }, "Checking invalid combination - justify-items: " + value);
+    });
+
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-align/default-alignment/parse-justify-items-005.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-align/default-alignment/parse-justify-items-005.html
new file mode 100644
index 0000000..b4814da
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-align/default-alignment/parse-justify-items-005.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Default-Alignment: justify-items - inherit value</title>
+<link rel="author" title="Javier Fernandez" href="mailto:jfernandez@igalia.com" />
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#default-alignment" />
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#propdef-justify-items" />
+<meta name="assert" content="Check the 'inherit' value in different scenarios."/>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/css-align/resources/alignment-parsing-utils.js"></script>
+<div id="log"></div>
+<script>
+test(function() {
+    checkInheritValues("justifyItems", "justify-items", "end");
+}, "Test the value 'inherit' overrides current value ('end')");
+test(function() {
+    checkInheritValues("justifyItems", "justify-items", "safe left");
+}, "Test the value 'inherit' overrides current value ('safe left')");
+test(function() {
+    checkInheritValues("justifyItems", "justify-items", "unsafe center");
+}, "Test the value 'inherit' overrides current value ('unsafe center')");
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-align/default-alignment/parse-justify-items-006.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-align/default-alignment/parse-justify-items-006.html
new file mode 100644
index 0000000..f64b52e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-align/default-alignment/parse-justify-items-006.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Default-Alignment: justify-items - use of the 'legacy' keyword</title>
+<link rel="author" title="Javier Fernandez" href="mailto:jfernandez@igalia.com" />
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#default-alignment" />
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#propdef-justify-items" />
+<meta name="assert" content="Check the use of the 'legacy' keyword in different scenarios."/>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/css-align/resources/alignment-parsing-utils.js"></script>
+<div id="log"></div>
+<script>
+test(function() {
+    checkLegacyValues("justifyItems", "justify-items", "legacy left");
+}, "Test the value justify-items: legacy left");
+test(function() {
+    checkLegacyValues("justifyItems", "justify-items", "legacy center");
+}, "Test the value justify-items: legacy center");
+test(function() {
+    checkLegacyValues("justifyItems", "justify-items", "legacy right");
+}, "Test the value justify-items: legacy right");
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-align/resources/alignment-parsing-utils.js b/third_party/WebKit/LayoutTests/external/wpt/css/css-align/resources/alignment-parsing-utils.js
index 9084624e..b18c929 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-align/resources/alignment-parsing-utils.js
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-align/resources/alignment-parsing-utils.js
@@ -2,6 +2,27 @@
 var contentPositionValues = [ "start", "end", "left", "right", "center", "flex-start", "flex-end"];
 var distributionValues = [ "stretch", "space-around", "space-between", "space-evenly"];
 var baselineValues = [ "baseline", "first baseline", "last baseline"];
+var overflowValues = [ "safe flex-end", "unsafe start", "safe end", "unsafe self-start", "safe center"];
+var legacyValues = [ "legacy left", "legacy center", "legacy right", "left legacy", "center legacy", "right legacy", "legacy"];
+
+var selfPositionClasses = {"Start":"start", "End":"end", "SelfStart":"self-start", "SelfEnd":"self-end", "Left":"left", "Right":"right", "Center":"center", "FlexStart":"flex-start", "FlexEnd":"flex-end"};
+var contentPositionClasses = {"Start":"start", "End":"end", "Left":"left", "Right":"right", "Center":"center", "FlexStart":"flex-start", "FlexEnd":"flex-end"};
+var distributionClasses = {"Stretch":"stretch", "SpaceAround":"space-around", "SpaceBetween":"space-between", "SpaceEvenly":"space-evenly"};
+var baselineClasses = {"Baseline":"baseline", "FirstBaseline":"first baseline", "LastBaseline":"last baseline"};
+var overflowClasses = {"SafeFlexEnd":"safe flex-end", "UnsafeEnd":"unsafe end", "SafeEnd":"safe end", "UnsafeFlexStart":"unsafe flex-start", "SafeCenter":"safe center"};
+var legacyClasses = {"LegacyLeft":"legacy left", "LegacyCenter":"legacy center", "LegacyRight":"legacy right", "LeftLegacy":"left legacy", "CenterLegacy":"center legacy", "RightLegacy":"right legacy", "Legacy":"legacy"};
+
+var invalidPositionValues = ["auto safe", "auto left", "normal unsafe", "normal stretch", "baseline normal",
+                             "baseline center", "first baseline center", "last baseline center", "baseline last",
+                             "baseline first", "stretch unsafe", "stretch right", "unsafe unsafe", "unsafe safe",
+                             "center start", "unsafe stretch", "safe stretch", "baseline safe", "unsafe baseline",
+                             "unsafe safe left", "unsafe left safe", "left safe unsafe safe", "start safe", "safe"];
+var invalidLegacyValues = ["legacy start", "legacy end", "legacy right unsafe", "legacy auto", "legacy stretch",
+                           "legacy left right"];
+var invalidDistributionValues = ["space-between left", "space-around center", "space-evenly right",
+                                 "stretch safe start", "space-around unsafe", "space-evenly safe flex-start",
+                                 "space-between safe", "space-between stretch", "stretch start",
+                                 "stretch baseline", "first baseline space-around"];
 
 function checkPlaceShorhand(shorthand, alignValue, justifyValue)
 {
@@ -52,3 +73,60 @@
     assert_equals(div.style[justifyLonghand],
                   "end", justifyLonghand + " expanded value");
 }
+
+function checkValues(element, property, propertyID, value, computedValue)
+{
+    window.element = element;
+    var elementID = element.id || "element";
+    assert_equals(eval('element.style.' + property), value, propertyID + ' specified value is not what it should.');
+    assert_equals(eval("window.getComputedStyle(" + elementID + ", '').getPropertyValue('" + propertyID + "')"), computedValue, propertyID + " computed style is not what is should.");
+}
+
+function checkBadValues(element, property, propertyID, value)
+{
+    var elementID = element.id || "element";
+    var initialValue = eval("window.getComputedStyle(" + elementID + " , '').getPropertyValue('" + propertyID + "')");
+    element.style[property] = "";
+    element.style[property] = value;
+    checkValues(element, property, propertyID, "", initialValue);
+}
+
+function checkInitialValues(element, property, propertyID, value, initial)
+{
+    element.style[property] = value;
+    checkValues(element, property, propertyID, value, value);
+    element.style[property] = "initial";
+    checkValues(element, property, propertyID, "initial", initial);
+}
+
+function checkInheritValues(property, propertyID, value)
+{
+    var parentElement = document.createElement("div");
+    document.body.appendChild(parentElement);
+    parentElement.style[property] = value;
+    checkValues(parentElement, property, propertyID, value, value);
+
+    var element = document.createElement("div");
+    parentElement.appendChild(element);
+    element.style[property] = "inherit";
+    checkValues(element, property, propertyID, "inherit", value);
+}
+
+function checkLegacyValues(property, propertyID, value)
+{
+    var parentElement = document.createElement("div");
+    document.body.appendChild(parentElement);
+    parentElement.style[property] = value;
+    checkValues(parentElement, property, propertyID, value, value);
+
+    var element = document.createElement("div");
+    parentElement.appendChild(element);
+    checkValues(element, property, propertyID, "", value);
+}
+
+function checkSupportedValues(elementID, property)
+{
+    var value = eval("window.getComputedStyle(" + elementID + " , '').getPropertyValue('" + property + "')");
+    var value1 = eval("window.getComputedStyle(" + elementID + " , '')");
+    shouldBeTrue("CSS.supports('" + property + "', '" + value + "')");
+}
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-align/self-alignment/parse-align-self-001.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-align/self-alignment/parse-align-self-001.html
new file mode 100644
index 0000000..e951124
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-align/self-alignment/parse-align-self-001.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Self-Alignment: align-self - setting values via CSS</title>
+<link rel="author" title="Javier Fernandez" href="mailto:jfernandez@igalia.com" />
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#self-alignment" />
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#propdef-align-self" />
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#typedef-self-position" />
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#typedef-baseline-position" />
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#typedef-overflow-position" />
+<link rel="stylesheet" href="../../support/alignment.css" >
+<meta name="assert" content="Check that the computed value is the specified value and the JS value is empty."/>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/css-align/resources/alignment-parsing-utils.js"></script>
+<div id="log"></div>
+<script>
+    let classes = Object.assign({"Auto":"auto", "Normal":"normal", "Stretch":"stretch"}, selfPositionClasses,
+                                baselineClasses, overflowClasses);
+
+    for (var key in classes) {
+        let specifiedValue = classes[key];
+        element = document.createElement("div");
+        element.className = "alignSelf" + key;
+        document.body.appendChild(element);
+        test(function() {
+            let computedValue = specifiedValue;
+            if (specifiedValue === "baseline")
+                computedValue = "first baseline";
+            checkValues(element, "alignSelf", "align-self", "", computedValue);
+        }, "Checking align-self: " + specifiedValue);
+    }
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-align/self-alignment/parse-align-self-002.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-align/self-alignment/parse-align-self-002.html
new file mode 100644
index 0000000..e04f87ff
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-align/self-alignment/parse-align-self-002.html
@@ -0,0 +1,57 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Self-Alignment: align-self - 'initial' value</title>
+<link rel="author" title="Javier Fernandez" href="mailto:jfernandez@igalia.com" />
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#self-alignment" />
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#propdef-align-self" />
+<link rel="help" href="https://drafts.csswg.org/css-cascade/#initial-values" />
+<meta name="assert" content="Check the 'initial' value in diferent scenarios."/>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/css-align/resources/alignment-parsing-utils.js"></script>
+<div id="log"></div>
+<script>
+container = document.createElement("div");
+element = document.createElement("div");
+container.appendChild(element);
+document.body.appendChild(container);
+
+test(function() {
+    element = document.createElement("div");
+    document.body.appendChild(element);
+    checkValues(element, "alignSelf", "align-self", "", "auto");
+}, "Test 'initial' value when nothing is specified");
+
+test(function() {
+    container.style.display = "";
+    checkInitialValues(element, "alignSelf", "align-self", "center", "auto");
+}, "Test align-self: 'initial'");
+
+test(function() {
+    container.style.display = "grid";
+    checkInitialValues(element, "alignSelf", "align-self", "safe left", "auto");
+}, "Test grid items align-self: 'initial'");
+
+test(function() {
+    container.style.display = "flex";
+    checkInitialValues(element, "alignSelf", "align-self", "unsafe right", "auto");
+}, "Test flex items align-self: 'initial'");
+
+test(function() {
+    container.style.display = "";
+    element.style.position = "absolute";
+    checkInitialValues(element, "alignSelf", "align-self", "left", "auto");
+}, "Test absolute positioned elements align-self: 'initial'");
+
+test(function() {
+    container.style.display = "grid";
+    element.style.position = "absolute";
+    checkInitialValues(element, "alignSelf", "align-self", "right", "auto");
+}, "Test absolute positioned grid items align-self: 'initial'");
+
+test(function() {
+    container.style.display = "flex";
+    element.style.position = "absolute";
+    checkInitialValues(element, "alignSelf", "align-self", "end", "auto");
+}, "Test absolute positioned flex items align-self: 'initial'");
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-align/self-alignment/parse-align-self-003.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-align/self-alignment/parse-align-self-003.html
new file mode 100644
index 0000000..19c8926
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-align/self-alignment/parse-align-self-003.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Self-Alignment: align-self - setting values via JS</title>
+<link rel="author" title="Javier Fernandez" href="mailto:jfernandez@igalia.com" />
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#self-alignment" />
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#propdef-align-self" />
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#typedef-self-position" />
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#typedef-baseline-position" />
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#typedef-overflow-position" />
+<meta name="assert" content="Check that the computed value is the specified value and the same than the JS value."/>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/css-align/resources/alignment-parsing-utils.js"></script>
+<div id="log"></div>
+<script>
+    element = document.createElement("div");
+    document.body.appendChild(element);
+
+    let classes = Object.assign({"Auto":"auto", "Normal":"normal", "Stretch":"stretch"}, selfPositionClasses,
+                                baselineClasses, overflowClasses);
+
+    for (var key in classes) {
+        let specifiedValue = classes[key];
+        test(function() {
+            element.style.alignSelf = specifiedValue;
+            let computedValue = specifiedValue;
+            if (specifiedValue === "baseline")
+                computedValue = "first baseline";
+            checkValues(element, "alignSelf", "align-self",  specifiedValue, computedValue);
+        }, "Checking align-self: " + specifiedValue);
+    }
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-align/self-alignment/parse-align-self-004.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-align/self-alignment/parse-align-self-004.html
new file mode 100644
index 0000000..4786727e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-align/self-alignment/parse-align-self-004.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Self-Alignment: align-self - invalid values</title>
+<link rel="author" title="Javier Fernandez" href="mailto:jfernandez@igalia.com" />
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#self-alignment" />
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#propdef-align-self" />
+<meta name="assert" content="Check bad combinations of specified values."/>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/css-align/resources/alignment-parsing-utils.js"></script>
+<div id="log"></div>
+<script>
+    element = document.createElement("div");
+    document.body.appendChild(element);
+
+    let values = ["legacy", "space-around"].concat(invalidPositionValues);
+
+    values.forEach(function(value) {
+        test(function() {
+            checkBadValues(element, "alignSelf", "align-self",  value);
+        }, "Checking invalid combination - align-self: " + value);
+    });
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-align/self-alignment/parse-align-self-005.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-align/self-alignment/parse-align-self-005.html
new file mode 100644
index 0000000..c61b24a
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-align/self-alignment/parse-align-self-005.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Self-Alignment: align-self - inherit value</title>
+<link rel="author" title="Javier Fernandez" href="mailto:jfernandez@igalia.com" />
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#self-alignment" />
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#propdef-align-self" />
+<meta name="assert" content="Check bad cobinations of specified values."/>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/css-align/resources/alignment-parsing-utils.js"></script>
+<div id="log"></div>
+<script>
+test(function() {
+    checkInheritValues("alignSelf", "align-self", "end");
+}, "Test the value 'inherit' overrides current value ('end')");
+test(function() {
+    checkInheritValues("alignSelf", "align-self", "safe left");
+}, "Test the value 'inherit' overrides current value ('safe left')");
+test(function() {
+    checkInheritValues("alignSelf", "align-self", "unsafe center");
+}, "Test the value 'inherit' overrides current value ('unsafe center')");
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-align/self-alignment/parse-justify-self-001.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-align/self-alignment/parse-justify-self-001.html
new file mode 100644
index 0000000..c2ee62d
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-align/self-alignment/parse-justify-self-001.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Self-Alignment: justify-self - setting values via CSS</title>
+<link rel="author" title="Javier Fernandez" href="mailto:jfernandez@igalia.com" />
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#self-alignment" />
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#propdef-justify-self" />
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#typedef-self-position" />
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#typedef-baseline-position" />
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#typedef-overflow-position" />
+<link rel="stylesheet" href="../../support/alignment.css" >
+<meta name="assert" content="Check that the computed value is the specified value and the JS value is empty."/>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/css-align/resources/alignment-parsing-utils.js"></script>
+<div id="log"></div>
+<script>
+    let classes = Object.assign({"Auto":"auto", "Normal":"normal", "Stretch":"stretch"}, selfPositionClasses,
+                                baselineClasses, overflowClasses);
+
+    for (var key in classes) {
+        let specifiedValue = classes[key];
+        element = document.createElement("div");
+        element.className = "justifySelf" + key;
+        document.body.appendChild(element);
+        test(function() {
+            let computedValue = specifiedValue;
+            if (specifiedValue === "baseline")
+                computedValue = "first baseline";
+            checkValues(element, "justifySelf", "justify-self", "", computedValue);
+        }, "Checking justify-self: " + specifiedValue);
+    }
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-align/self-alignment/parse-justify-self-002.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-align/self-alignment/parse-justify-self-002.html
new file mode 100644
index 0000000..38bc73d
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-align/self-alignment/parse-justify-self-002.html
@@ -0,0 +1,57 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Self-Alignment: justify-self - 'initial' value</title>
+<link rel="author" title="Javier Fernandez" href="mailto:jfernandez@igalia.com" />
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#self-alignment" />
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#propdef-justify-self" />
+<link rel="help" href="https://drafts.csswg.org/css-cascade/#initial-values" />
+<meta name="assert" content="Check the 'initial' value in diferent scenarios."/>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/css-align/resources/alignment-parsing-utils.js"></script>
+<div id="log"></div>
+<script>
+container = document.createElement("div");
+element = document.createElement("div");
+container.appendChild(element);
+document.body.appendChild(container);
+
+test(function() {
+    element = document.createElement("div");
+    document.body.appendChild(element);
+    checkValues(element, "justifySelf", "justify-self", "", "auto");
+}, "Test 'initial' value when nothing is specified");
+
+test(function() {
+    container.style.display = "";
+    checkInitialValues(element, "justifySelf", "justify-self", "center", "auto");
+}, "Test justify-self: 'initial'");
+
+test(function() {
+    container.style.display = "grid";
+    checkInitialValues(element, "justifySelf", "justify-self", "safe left", "auto");
+}, "Test grid items justify-self: 'initial'");
+
+test(function() {
+    container.style.display = "flex";
+    checkInitialValues(element, "justifySelf", "justify-self", "unsafe right", "auto");
+}, "Test flex items justify-self: 'initial'");
+
+test(function() {
+    container.style.display = "";
+    element.style.position = "absolute";
+    checkInitialValues(element, "justifySelf", "justify-self", "left", "auto");
+}, "Test absolute positioned elements justify-self: 'initial'");
+
+test(function() {
+    container.style.display = "grid";
+    element.style.position = "absolute";
+    checkInitialValues(element, "justifySelf", "justify-self", "right", "auto");
+}, "Test absolute positioned grid items justify-self: 'initial'");
+
+test(function() {
+    container.style.display = "flex";
+    element.style.position = "absolute";
+    checkInitialValues(element, "justifySelf", "justify-self", "end", "auto");
+}, "Test absolute positioned flex items justify-self: 'initial'");
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-align/self-alignment/parse-justify-self-003.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-align/self-alignment/parse-justify-self-003.html
new file mode 100644
index 0000000..7e2dd65
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-align/self-alignment/parse-justify-self-003.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Self-Alignment: justify-self - setting values via JS</title>
+<link rel="author" title="Javier Fernandez" href="mailto:jfernandez@igalia.com" />
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#self-alignment" />
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#propdef-justify-self" />
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#typedef-self-position" />
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#typedef-baseline-position" />
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#typedef-overflow-position" />
+<meta name="assert" content="Check that the computed value is the specified value and the same than the JS value."/>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/css-align/resources/alignment-parsing-utils.js"></script>
+<div id="log"></div>
+<script>
+    element = document.createElement("div");
+    document.body.appendChild(element);
+
+    let classes = Object.assign({"Auto":"auto", "Normal":"normal", "Stretch":"stretch"}, selfPositionClasses,
+                                baselineClasses, overflowClasses);
+
+    for (var key in classes) {
+        let specifiedValue = classes[key];
+        test(function() {
+            element.style.justifySelf = specifiedValue;
+            let computedValue = specifiedValue;
+            if (specifiedValue === "baseline")
+                computedValue = "first baseline";
+            checkValues(element, "justifySelf", "justify-self",  specifiedValue, computedValue);
+        }, "Checking justify-self: " + specifiedValue);
+    }
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-align/self-alignment/parse-justify-self-004.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-align/self-alignment/parse-justify-self-004.html
new file mode 100644
index 0000000..ab81bf95
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-align/self-alignment/parse-justify-self-004.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Self-Alignment: justify-self - invalid values</title>
+<link rel="author" title="Javier Fernandez" href="mailto:jfernandez@igalia.com" />
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#self-alignment" />
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#propdef-justify-self" />
+<meta name="assert" content="Check bad combinations of specified values."/>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/css-align/resources/alignment-parsing-utils.js"></script>
+<div id="log"></div>
+<script>
+    element = document.createElement("div");
+    document.body.appendChild(element);
+
+    let values = ["legacy", "space-around"].concat(invalidPositionValues);
+
+    values.forEach(function(value) {
+        test(function() {
+            checkBadValues(element, "justifySelf", "justify-self",  value);
+        }, "Checking invalid combination - justify-self: " + value);
+    });
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-align/self-alignment/parse-justify-self-005.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-align/self-alignment/parse-justify-self-005.html
new file mode 100644
index 0000000..61b44be3
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-align/self-alignment/parse-justify-self-005.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Self-Alignment: justify-self - inherit value</title>
+<link rel="author" title="Javier Fernandez" href="mailto:jfernandez@igalia.com" />
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#self-alignment" />
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#propdef-justify-self" />
+<meta name="assert" content="Check bad cobinations of specified values."/>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/css-align/resources/alignment-parsing-utils.js"></script>
+<div id="log"></div>
+<script>
+test(function() {
+    checkInheritValues("justifySelf", "justify-self", "end");
+}, "Test the value 'inherit' overrides current value ('end')");
+test(function() {
+    checkInheritValues("justifySelf", "justify-self", "safe left");
+}, "Test the value 'inherit' overrides current value ('safe left')");
+test(function() {
+    checkInheritValues("justifySelf", "justify-self", "unsafe center");
+}, "Test the value 'inherit' overrides current value ('unsafe center')");
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-grid/abspos/grid-positioned-items-content-alignment-001.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-grid/abspos/grid-positioned-items-content-alignment-001.html
index d99dc53..80b795d 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-grid/abspos/grid-positioned-items-content-alignment-001.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-grid/abspos/grid-positioned-items-content-alignment-001.html
@@ -6,7 +6,7 @@
 <link rel="help" href="https://drafts.csswg.org/css-grid-1/#grid-align" title="10.5. Aligning the Grid: the justify-content and align-content properties">
 <meta name="assert" content="This test checks the behavior of the positioned items in a grid using content alignment.">
 <link rel="stylesheet" href="../support/grid.css">
-<link rel="stylesheet" href="../support/grid-alignment.css">
+<link rel="stylesheet" href="../../support/alignment.css">
 <style>
 
 .grid {
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-grid/abspos/grid-positioned-items-content-alignment-rtl-001.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-grid/abspos/grid-positioned-items-content-alignment-rtl-001.html
index 40580ed..ad9147e2 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-grid/abspos/grid-positioned-items-content-alignment-rtl-001.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-grid/abspos/grid-positioned-items-content-alignment-rtl-001.html
@@ -6,7 +6,7 @@
 <link rel="help" href="https://drafts.csswg.org/css-grid-1/#grid-align" title="10.5. Aligning the Grid: the justify-content and align-content properties">
 <meta name="assert" content="This test checks the behavior of the positioned items in a grid using content alignment in RTL.">
 <link rel="stylesheet" href="../support/grid.css">
-<link rel="stylesheet" href="../support/grid-alignment.css">
+<link rel="stylesheet" href="../../support/alignment.css">
 <style>
 
 .grid {
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-grid/support/grid-alignment.css b/third_party/WebKit/LayoutTests/external/wpt/css/css-grid/support/grid-alignment.css
deleted file mode 100644
index 4cf50154..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-grid/support/grid-alignment.css
+++ /dev/null
@@ -1,240 +0,0 @@
-/* align-self */
-.alignSelfAuto { align-self: auto; }
-.alignSelfStretch { align-self: stretch; }
-.alignSelfStart { align-self: start; }
-.alignSelfEnd { align-self: end; }
-.alignSelfCenter { align-self: center; }
-.alignSelfRight { align-self: right; }
-.alignSelfLeft { align-self: left; }
-
-.alignSelfFlexStart { align-self: flex-start; }
-.alignSelfFlexEnd { align-self: flex-end; }
-
-.alignSelfSelfStart { align-self: self-start; }
-.alignSelfSelfEnd { align-self: self-end; }
-
-.alignSelfCenterSafe { align-self: center safe; }
-.alignSelfCenterUnsafe { align-self: center unsafe; }
-.alignSelfEndSafe { align-self: end safe; }
-.alignSelfEndUnsafe { align-self: end unsafe; }
-
-.alignSelfBaseline { align-self: baseline; }
-
-/* align-items */
-.alignItemsAuto { align-items: auto; }
-.alignItemsStretch { align-items: stretch; }
-.alignItemsStart { align-items: start; }
-.alignItemsCenter { align-items: center; }
-.alignItemsEnd { align-items: end; }
-.alignItemsBaseline { align-items: baseline; }
-
-.alignItemsCenterSafe { align-items: center safe; }
-.alignItemsCenterUnsafe { align-items: center unsafe; }
-.alignItemsEndSafe { align-items: end safe; }
-.alignItemsEndUnsafe { align-items: end unsafe; }
-
-/* align-content */
-.alignContentBaseline { align-content: baseline; }
-.alignContentLastBaseline { align-content: last-baseline; }
-.alignContentStart { align-content: start; }
-.alignContentEnd { align-content: end; }
-.alignContentCenter { align-content: center; }
-.alignContentLeft { align-content: left; }
-.alignContentRight { align-content: right; }
-.alignContentFlexStart { align-content: flex-start; }
-.alignContentFlexEnd { align-content: flex-end; }
-.alignContentSpaceBetween { align-content: space-between; }
-.alignContentSpaceAround { align-content: space-around; }
-.alignContentSpaceEvenly { align-content: space-evenly; }
-.alignContentStretch { align-content: stretch; }
-
-/* justify-self */
-.justifySelfAuto { justify-self: auto; }
-.justifySelfStretch { justify-self: stretch; }
-.justifySelfStart { justify-self: start; }
-.justifySelfCenter { justify-self: center; }
-.justifySelfEnd { justify-self: end; }
-.justifySelfRight { justify-self: right; }
-.justifySelfLeft { justify-self: left; }
-
-.justifySelfFlexStart { justify-self: flex-start; }
-.justifySelfFlexEnd { justify-self: flex-end; }
-
-.justifySelfSelfStart { justify-self: self-start; }
-.justifySelfSelfEnd { justify-self: self-end; }
-
-.justifySelfCenterSafe { justify-self: center safe; }
-.justifySelfCenterUnsafe { justify-self: center unsafe; }
-
-.justifySelfBaseline { justify-self: baseline; }
-
-/* justify-items */
-.justifyItemsAuto { justify-items: auto; }
-.justifyItemsStretch { justify-items: stretch; }
-.justifyItemsStart { justify-items: start; }
-.justifyItemsCenter { justify-items: center; }
-.justifyItemsEnd { justify-items: end; }
-
-.justifyItemsCenterSafe { justify-items: center safe; }
-.justifyItemsCenterUnsafe { justify-items: center unsafe; }
-.justifyItemsEndSafe { justify-items: end safe; }
-.justifyItemsEndUnsafe { justify-items: end unsafe; }
-
-.justifyItemsBaseline { justify-items: baseline; }
-
-/* justify-content */
-.justifyContentBaseline { justify-content: baseline; }
-.justifyContentLastBaseline { justify-content: last-baseline; }
-.justifyContentStart { justify-content: start; }
-.justifyContentEnd { justify-content: end; }
-.justifyContentCenter { justify-content: center; }
-.justifyContentLeft { justify-content: left; }
-.justifyContentRight { justify-content: right; }
-.justifyContentFlexStart { justify-content: flex-start; }
-.justifyContentFlexEnd { justify-content: flex-end; }
-.justifyContentSpaceBetween { justify-content: space-between; }
-.justifyContentSpaceAround { justify-content: space-around; }
-.justifyContentSpaceEvenly { justify-content: space-evenly; }
-.justifyContentStretch { justify-content: stretch; }
-
-/* Both align-items and justify-items */
-.itemsNormal {
-  align-items: normal;
-  justify-items: normal;
-}
-
-.itemsStretch {
-  align-items: stretch;
-  justify-items: stretch;
-}
-
-.itemsStart {
-  align-items: start;
-  justify-items: start;
-}
-
-.itemsCenter {
-  align-items: center;
-  justify-items: center;
-}
-
-.itemsEnd {
-  align-items: end;
-  justify-items: end;
-}
-
-.itemsLeft {
-  align-items: left;
-  justify-items: left;
-}
-
-.itemsRight {
-  align-items: right;
-  justify-items: right;
-}
-
-.itemsSelfStart {
-  align-items: self-start;
-  justify-items: self-start;
-}
-
-.itemsSelfEnd {
-  align-items: self-end;
-  justify-items: self-end;
-}
-.itemsBaseline {
-  align-items: baseline;
-  justify-items: baseline;
-}
-
-/* Both align-self and justify-self */
-.selfStretch {
-  align-self: stretch;
-  justify-self: stretch;
-}
-.selfStart {
-  align-self: start;
-  justify-self: start;
-}
-.selfEnd {
-  align-self: end;
-  justify-self: end;
-}
-.selfCenter {
-  align-self: center;
-  justify-self: center;
-}
-.selfRight {
-  align-self: right;
-  justify-self: right;
-}
-.selfLeft {
-  align-self: left;
-  justify-self: left;
-}
-.selfSelfStart {
-  align-self: self-start;
-  justify-self: self-start;
-}
-.selfSelfEnd {
-  align-self: self-end;
-  justify-self: self-end;
-}
-.selfBaseline {
-  align-self: baseline;
-  justify-self: baseline;
-}
-
-/* Both align-content and justify-content */
-.contentStart {
-  align-content: start;
-  justify-content: start;
-}
-.contentCenter {
-  align-content: center;
-  justify-content: center;
-}
-.contentEnd {
-  align-content: end;
-  justify-content: end;
-}
-
-.contentCenterSafe {
-  align-content: center safe;
-  justify-content: center safe;
-}
-
-.contentCenterUnsafe {
-  align-content: center unsafe;
-  justify-content: center unsafe;
-}
-
-.contentEndSafe {
-  align-content: end safe;
-  justify-content: end safe;
-}
-
-.contentEndUnsafe {
-  align-content: end unsafe;
-  justify-content: end unsafe;
-}
-
-.contentSpaceBetween {
-  justify-content: space-between;
-  align-content: space-between;
-}
-
-.contentSpaceAround {
-  justify-content: space-around;
-  align-content: space-around;
-}
-
-.contentSpaceEvenly {
-  justify-content: space-evenly;
-  align-content: space-evenly;
-}
-
-.contentStretch {
-  justify-content: stretch;
-  align-content: stretch;
-}
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-paint-api/parse-input-arguments-018-ref.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-paint-api/parse-input-arguments-018-ref.html
index 8222ab4..05da4ed 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-paint-api/parse-input-arguments-018-ref.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-paint-api/parse-input-arguments-018-ref.html
@@ -1,15 +1,17 @@
 <!DOCTYPE html>
 <html>
 <body>
-<p>The test result should show only one black rect border. It should not paint
-any content in the rect because registerPaint will be called twice and the
-inputArguments will return two different strings, that will throw an exception
-and paint won't be executed.</p>
+<p>This test result should show a rect with black border, where the rect is
+filled with green on the lower right corner. The registerPaint('failureIndicator')
+will be called twice and the inputArguments will return two different strings,
+which will throw an exception and the paint function with 'failureIndicator'
+should never be called. In other words, there should be no red painted in the result.</p>
 <canvas id ="canvas" width="100" height="100" style="border:1px solid black"></canvas>
 <script>
 var canvas = document.getElementById('canvas');
 var context = canvas.getContext("2d");
-context.clearRect(0, 0, 100, 100);
+context.fillStyle = 'green'
+context.fillRect(50, 50, 50, 50);
 </script>
 </body>
 </html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-paint-api/parse-input-arguments-018.https.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-paint-api/parse-input-arguments-018.https.html
index 2cfac40..9d03a8d2 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-paint-api/parse-input-arguments-018.https.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-paint-api/parse-input-arguments-018.https.html
@@ -9,16 +9,17 @@
 
 #canvas-geometry {
     border:1px solid black;
-    background-image: paint(geometry);
+    background-image: paint(failureIndicator), paint(geometry);
 }
 </style>
 <script src="/common/reftest-wait.js"></script>
 <script src="/common/css-paint-tests.js"></script>
 <body>
-<p>The test result should show only one black rect border. It should not paint
-any content in the rect because registerPaint will be called twice and the
-inputArguments will return two different strings, that will throw an exception
-and paint won't be executed.</p>
+<p>This test result should show a rect with black border, where the rect is
+filled with green on the lower right corner. The registerPaint('failureIndicator')
+will be called twice and the inputArguments will return two different strings,
+which will throw an exception and the paint function with 'failureIndicator'
+should never be called. In other words, there should be no red painted in the result.</p>
 <div id="canvas-geometry" class="container"></div>
 
 <script id="code" type="text/worklet">
@@ -31,7 +32,7 @@
 }
 
 try {
-    registerPaint('geometry', class {
+    registerPaint('failureIndicator', class {
         static get inputArguments() {
             // This test is testing the case where an exception should be thrown
             // when two paint definitions with different properties are registered
@@ -42,14 +43,23 @@
             var current_str = generateRandString(100);
             return [current_str];
         }
+        // The paint function here should never be called because the inputArguments
+        // will generate two different properties, and that should throw an
+        // exception.
         paint(ctx, geom) {
-            ctx.strokeStyle = 'red';
-            ctx.lineWidth = 4;
-            ctx.strokeRect(0, 0, geom.width, geom.height);
+            ctx.fillStyle = 'red';
+            ctx.fillRect(0, 0, 50, 50);
         }
     });
 } catch(ex) {
 }
+
+registerPaint('geometry', class {
+    paint(ctx, geom) {
+        ctx.fillStyle = 'green';
+        ctx.fillRect(50, 50, 50, 50);
+    }
+});
 </script>
 
 <script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/selectors/hover-002-manual.html b/third_party/WebKit/LayoutTests/external/wpt/css/selectors/hover-002-manual.html
new file mode 100644
index 0000000..50859c5
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/selectors/hover-002-manual.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Selectors: Change class to enable :hover</title>
+<link rel="author" title="Rune Lillesveen" href="futhark@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/selectors/#the-hover-pseudo">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<style>
+  .affected:hover { color: green }
+  #hoveredContents { display: contents }
+</style>
+<div id="hovered">Hover me - should become green</div>
+<div id="hoveredContents">
+  <div id="hovered2">Hover me - should become green</div>
+</div>
+<script>
+  function testElementGreen(test, element) {
+    element.addEventListener("mouseover", test.step_func(event => {
+      assert_equals(getComputedStyle(element).color, "rgb(0, 128, 0)");
+      test.done();
+    }));
+  }
+
+  // Setting the affected classes here makes the two elements go from never
+  // reacting to hover to being affected by hover without changing computed
+  // style.
+  hovered.offsetTop;
+  hovered.className = "affected";
+  hoveredContents.className = "affected";
+
+  async_test(t => { testElementGreen(t, hovered); }, "Hover #hovered element should make it go green");
+  async_test(t => { testElementGreen(t, hovered2); }, "Hover #hoveredContents child should make it go green");
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/support/alignment.css b/third_party/WebKit/LayoutTests/external/wpt/css/support/alignment.css
new file mode 100644
index 0000000..d4c970c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/support/alignment.css
@@ -0,0 +1,367 @@
+/* align-self */
+.alignSelfAuto { align-self: auto; }
+.alignSelfNormal { align-self: normal; }
+.alignSelfStretch { align-self: stretch; }
+.alignSelfStart { align-self: start; }
+.alignSelfEnd { align-self: end; }
+.alignSelfCenter { align-self: center; }
+.alignSelfRight { align-self: right; }
+.alignSelfLeft { align-self: left; }
+
+.alignSelfFlexStart { align-self: flex-start; }
+.alignSelfFlexEnd { align-self: flex-end; }
+
+.alignSelfSelfStart { align-self: self-start; }
+.alignSelfSelfEnd { align-self: self-end; }
+
+.alignSelfSafeCenter { align-self: safe center; }
+.alignSelfUnsafeCenter { align-self: unsafe center; }
+.alignSelfSafeEnd { align-self: safe end; }
+.alignSelfUnsafeEnd { align-self: unsafe end; }
+.alignSelfSafeSelfEnd { align-self: safe self-end; }
+.alignSelfUnsafeSelfEnd { align-self: unsafe self-end; }
+.alignSelfSafeSelfStart { align-self: safe self-start; }
+.alignSelfUnsafeSelfStart { align-self: unsafe self-start; }
+.alignSelfSafeRight { align-self: safe right; }
+.alignSelfUnsafeRight { align-self: unsafe right; }
+.alignSelfSafeLeft { align-self: safe left; }
+.alignSelfUnsafeLeft { align-self: unsafe left; }
+.alignSelfSafeFlexEnd { align-self: safe flex-end; }
+.alignSelfUnsafeFlexEnd { align-self: unsafe flex-end; }
+.alignSelfSafeFlexStart { align-self: safe flex-start; }
+.alignSelfUnsafeFlexStart { align-self: unsafe flex-start; }
+
+.alignSelfBaseline { align-self: baseline; }
+.alignSelfFirstBaseline { align-self: first baseline; }
+.alignSelfLastBaseline { align-self: last baseline; }
+
+/* align-items */
+.alignItemsAuto { align-items: auto; }
+.alignItemsNormal { align-items: normal; }
+.alignItemsStretch { align-items: stretch; }
+.alignItemsStart { align-items: start; }
+.alignItemsCenter { align-items: center; }
+.alignItemsEnd { align-items: end; }
+.alignItemsLeft { align-items: left; }
+.alignItemsRight { align-items: right; }
+
+.alignItemsFlexStart { align-items: flex-start; }
+.alignItemsFlexEnd { align-items: flex-end; }
+
+.alignItemsSelfStart { align-items: self-start; }
+.alignItemsSelfEnd { align-items: self-end; }
+
+.alignItemsSafeCenter { align-items: safe center; }
+.alignItemsUnsafeCenter { align-items: unsafe center; }
+.alignItemsSafeEnd { align-items: safe end; }
+.alignItemsUnsafeEnd { align-items: unsafe end; }
+.alignItemsSafeSelfEnd { align-items: safe self-end; }
+.alignItemsUnsafeSelfEnd { align-items: unsafe self-end; }
+.alignItemsSafeSelfStart { align-items: safe self-start; }
+.alignItemsUnsafeSelfStart { align-items: unsafe self-start; }
+.alignItemsSafeRight { align-items: safe right; }
+.alignItemsUnsafeRight { align-items: unsafe right; }
+.alignItemsSafeLeft { align-items: safe left; }
+.alignItemsUnsafeLeft { align-items: unsafe left; }
+.alignItemsSafeFlexEnd { align-items: safe flex-end; }
+.alignItemsUnsafeFlexEnd { align-items: unsafe flex-end; }
+.alignItemsSafeFlexStart { align-items: safe flex-start; }
+.alignItemsUnsafeFlexStart { align-items: unsafe flex-start; }
+
+.alignItemsBaseline { align-items: baseline; }
+.alignItemsFirstBaseline { align-items: first baseline; }
+.alignItemsLastBaseline { align-items: last baseline; }
+
+/* align-content */
+.alignContentBaseline { align-content: baseline; }
+.alignContentLastBaseline { align-content: last-baseline; }
+.alignContentStart { align-content: start; }
+.alignContentEnd { align-content: end; }
+.alignContentCenter { align-content: center; }
+.alignContentLeft { align-content: left; }
+.alignContentRight { align-content: right; }
+
+.alignContentFlexStart { align-content: flex-start; }
+.alignContentFlexEnd { align-content: flex-end; }
+
+.alignContentSpaceBetween { align-content: space-between; }
+.alignContentSpaceAround { align-content: space-around; }
+.alignContentSpaceEvenly { align-content: space-evenly; }
+.alignContentStretch { align-content: stretch; }
+
+.alignContentSafeCenter { align-content: safe center; }
+.alignContentUnsafeCenter { align-content: unsafe center; }
+.alignContentSafeEnd { align-content: safe end; }
+.alignContentUnsafeEnd { align-content: unsafe end; }
+.alignContentSafeRight { align-content: safe right; }
+.alignContentUnsafeRight { align-content: unsafe right; }
+.alignContentSafeLeft { align-content: safe left; }
+.alignContentUnsafeLeft { align-content: unsafe left; }
+.alignContentSafeFlexEnd { align-content: safe flex-end; }
+.alignContentUnsafeFlexEnd { align-content: unsafe flex-end; }
+.alignContentSafeFlexStart { align-content: safe flex-start; }
+.alignContentUnsafeFlexStart { align-content: unsafe flex-start; }
+
+.alignContentBaseline { align-content: baseline; }
+.alignContentFirstBaseline { align-content: first baseline; }
+.alignContentLastBaseline { align-content: last baseline; }
+
+/* justify-self */
+.justifySelfAuto { justify-self: auto; }
+.justifySelfNormal { justify-self: normal; }
+.justifySelfStretch { justify-self: stretch; }
+.justifySelfStart { justify-self: start; }
+.justifySelfCenter { justify-self: center; }
+.justifySelfEnd { justify-self: end; }
+.justifySelfRight { justify-self: right; }
+.justifySelfLeft { justify-self: left; }
+
+.justifySelfFlexStart { justify-self: flex-start; }
+.justifySelfFlexEnd { justify-self: flex-end; }
+
+.justifySelfSelfStart { justify-self: self-start; }
+.justifySelfSelfEnd { justify-self: self-end; }
+
+.justifySelfSafeCenter { justify-self: safe center; }
+.justifySelfUnsafeCenter { justify-self: unsafe center; }
+.justifySelfSafeEnd { justify-self: safe end; }
+.justifySelfUnsafeEnd { justify-self: unsafe end; }
+.justifySelfSafeSelfEnd { justify-self: safe self-end; }
+.justifySelfUnsafeSelfEnd { justify-self: unsafe self-end; }
+.justifySelfSafeSelfStart { justify-self: safe self-start; }
+.justifySelfUnsafeSelfStart { justify-self: unsafe self-start; }
+.justifySelfSafeRight { justify-self: safe right; }
+.justifySelfUnsafeRight { justify-self: unsafe right; }
+.justifySelfSafeLeft { justify-self: safe left; }
+.justifySelfUnsafeLeft { justify-self: unsafe left; }
+.justifySelfSafeFlexEnd { justify-self: safe flex-end; }
+.justifySelfUnsafeFlexEnd { justify-self: unsafe flex-end; }
+.justifySelfSafeFlexStart { justify-self: safe flex-start; }
+.justifySelfUnsafeFlexStart { justify-self: unsafe flex-start; }
+
+.justifySelfBaseline { justify-self: baseline; }
+.justifySelfFirstBaseline { justify-self: first baseline; }
+.justifySelfLastBaseline { justify-self: last baseline; }
+
+/* justify-items */
+.justifyItemsAuto { justify-items: auto; }
+.justifyItemsNormal { justify-items: normal; }
+.justifyItemsStretch { justify-items: stretch; }
+.justifyItemsStart { justify-items: start; }
+.justifyItemsCenter { justify-items: center; }
+.justifyItemsEnd { justify-items: end; }
+.justifyItemsLeft { justify-items: left; }
+.justifyItemsRight { justify-items: right; }
+
+.justifyItemsFlexStart { justify-items: flex-start; }
+.justifyItemsFlexEnd { justify-items: flex-end; }
+
+.justifyItemsSelfStart { justify-items: self-start; }
+.justifyItemsSelfEnd { justify-items: self-end; }
+
+.justifyItemsLegacy { justify-items: legacy; }
+.justifyItemsLegacyLeft { justify-items: legacy left; }
+.justifyItemsLegacyCenter { justify-items: legacy center; }
+.justifyItemsLegacyRight { justify-items: legacy right; }
+.justifyItemsLeftLegacy { justify-items: left legacy; }
+.justifyItemsCenterLegacy { justify-items: center legacy; }
+.justifyItemsRightLegacy { justify-items: right legacy; }
+
+.justifyItemsSafeCenter { justify-items: safe center; }
+.justifyItemsUnsafeCenter { justify-items: unsafe center; }
+.justifyItemsSafeEnd { justify-items: safe end; }
+.justifyItemsUnsafeEnd { justify-items: unsafe end; }
+.justifyItemsSafeSelfEnd { justify-items: safe self-end; }
+.justifyItemsUnsafeSelfEnd { justify-items: unsafe self-end; }
+.justifyItemsSafeSelfStart { justify-items: safe self-start; }
+.justifyItemsUnsafeSelfStart { justify-items: unsafe self-start; }
+.justifyItemsSafeRight { justify-items: safe right; }
+.justifyItemsUnsafeRight { justify-items: unsafe right; }
+.justifyItemsSafeLeft { justify-items: safe left; }
+.justifyItemsUnsafeLeft { justify-items: unsafe left; }
+.justifyItemsSafeFlexEnd { justify-items: safe flex-end; }
+.justifyItemsUnsafeFlexEnd { justify-items: unsafe flex-end; }
+.justifyItemsSafeFlexStart { justify-items: safe flex-start; }
+.justifyItemsUnsafeFlexStart { justify-items: unsafe flex-start; }
+
+.justifyItemsTest { justify-items: safe end; }
+
+.justifyItemsBaseline { justify-items: baseline; }
+.justifyItemsFirstBaseline { justify-items: first baseline; }
+.justifyItemsLastBaseline { justify-items: last baseline; }
+
+/* justify-content */
+.justifyContentBaseline { justify-content: baseline; }
+.justifyContentLastBaseline { justify-content: last-baseline; }
+.justifyContentStart { justify-content: start; }
+.justifyContentEnd { justify-content: end; }
+.justifyContentCenter { justify-content: center; }
+.justifyContentLeft { justify-content: left; }
+.justifyContentRight { justify-content: right; }
+
+.justifyContentFlexStart { justify-content: flex-start; }
+.justifyContentFlexEnd { justify-content: flex-end; }
+
+.justifyContentSpaceBetween { justify-content: space-between; }
+.justifyContentSpaceAround { justify-content: space-around; }
+.justifyContentSpaceEvenly { justify-content: space-evenly; }
+.justifyContentStretch { justify-content: stretch; }
+
+.justifyContentSafeCenter { justify-content: safe center; }
+.justifyContentUnsafeCenter { justify-content: unsafe center; }
+.justifyContentSafeEnd { justify-content: safe end; }
+.justifyContentUnsafeEnd { justify-content: unsafe end; }
+.justifyContentSafeRight { justify-content: safe right; }
+.justifyContentUnsafeRight { justify-content: unsafe right; }
+.justifyContentSafeLeft { justify-content: safe left; }
+.justifyContentUnsafeLeft { justify-content: unsafe left; }
+.justifyContentSafeFlexEnd { justify-content: safe flex-end; }
+.justifyContentUnsafeFlexEnd { justify-content: unsafe flex-end; }
+.justifyContentSafeFlexStart { justify-content: safe flex-start; }
+.justifyContentUnsafeFlexStart { justify-content: unsafe flex-start; }
+
+.justifyContentBaseline { justify-content: baseline; }
+.justifyContentFirstBaseline { justify-content: first baseline; }
+.justifyContentLastBaseline { justify-content: last baseline; }
+
+/* Both align-items and justify-items */
+.itemsNormal {
+    align-items: normal;
+    justify-items: normal;
+}
+
+.itemsStretch {
+    align-items: stretch;
+    justify-items: stretch;
+}
+
+.itemsStart {
+    align-items: start;
+    justify-items: start;
+}
+
+.itemsCenter {
+    align-items: center;
+    justify-items: center;
+}
+
+.itemsEnd {
+    align-items: end;
+    justify-items: end;
+}
+
+.itemsLeft {
+    align-items: left;
+    justify-items: left;
+}
+
+.itemsRight {
+    align-items: right;
+    justify-items: right;
+}
+
+.itemsSelfStart {
+    align-items: self-start;
+    justify-items: self-start;
+}
+
+.itemsSelfEnd {
+    align-items: self-end;
+    justify-items: self-end;
+}
+.itemsBaseline {
+    align-items: baseline;
+    justify-items: baseline;
+}
+
+/* Both align-self and justify-self */
+.selfStretch {
+    align-self: stretch;
+    justify-self: stretch;
+}
+.selfStart {
+    align-self: start;
+    justify-self: start;
+}
+.selfEnd {
+    align-self: end;
+    justify-self: end;
+}
+.selfCenter {
+    align-self: center;
+    justify-self: center;
+}
+.selfRight {
+    align-self: right;
+    justify-self: right;
+}
+.selfLeft {
+    align-self: left;
+    justify-self: left;
+}
+.selfSelfStart {
+    align-self: self-start;
+    justify-self: self-start;
+}
+.selfSelfEnd {
+    align-self: self-end;
+    justify-self: self-end;
+}
+.selfBaseline {
+    align-self: baseline;
+    justify-self: baseline;
+}
+
+/* Both align-content and justify-content */
+.contentStart {
+    align-content: start;
+    justify-content: start;
+}
+.contentCenter {
+    align-content: center;
+    justify-content: center;
+}
+.contentEnd {
+    align-content: end;
+    justify-content: end;
+}
+
+.contentCenterSafe {
+    align-content: safe center;
+    justify-content: safe center;
+}
+
+.contentCenterUnsafe {
+    align-content: unsafe center;
+    justify-content: unsafe center;
+}
+
+.contentEndSafe {
+    align-content: safe end;
+    justify-content: safe end;
+}
+
+.contentEndUnsafe {
+    align-content: unsafe end;
+    justify-content: unsafe end;
+}
+
+.contentSpaceBetween {
+    justify-content: space-between;
+    align-content: space-between;
+}
+
+.contentSpaceAround {
+    justify-content: space-around;
+    align-content: space-around;
+}
+
+.contentSpaceEvenly {
+    justify-content: space-evenly;
+    align-content: space-evenly;
+}
+
+.contentStretch {
+    justify-content: stretch;
+    align-content: stretch;
+}
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/dom/usvstring-reflection.html b/third_party/WebKit/LayoutTests/external/wpt/html/dom/usvstring-reflection.html
index 7b408e0..aaf6c0be 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/html/dom/usvstring-reflection.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/dom/usvstring-reflection.html
@@ -95,8 +95,18 @@
 }, "websocket url : unpaired surrogate codepoint should be replaced with U+FFFD")
 
 test(() => {
+  try {
+    navigator.sendBeacon("resources/\uD800blank.txt");
+    assert_true(true);
+  } catch (e) {
+    assert_true(false);
+  }
+}, "sendBeacon URL: unpaired surrogate codepoint should not make any exceptions.")
+
+test(() => {
   var w = window.open("about:blank#\uD800");
   assert_equals(w.document.URL, 'about:blank#%EF%BF%BD');
   assert_equals(w.document.documentURI, 'about:blank#%EF%BF%BD');
 }, "Document URLs: unpaired surrogate codepoint should be replaced with U+FFFD")
+
 </script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-non-snap-to-lines-ref.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-non-snap-to-lines-ref.html
new file mode 100644
index 0000000..92c1e9f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-non-snap-to-lines-ref.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<title>Reference test for track-webvtt-non-snap-to-lines.html</title>
+<script src="/common/reftest-wait.js"></script>
+<script src="/common/media.js"></script>
+<style>
+.container {
+  position: relative;
+  display: inline-block;
+}
+.cue {
+  position: absolute;
+  top: 48px;
+  font-family: sans-serif;
+  background: green;
+  color: rgba(255, 255, 255, 1);
+  font-size: 12px;
+  padding: 0px 2px;
+}
+</style>
+<div class="container">
+  <video autoplay onplaying="this.onplaying = null; this.pause(); takeScreenshot();">
+    <script>
+    document.currentScript.parentNode.src = getVideoURI("/media/test");
+    </script>
+  </video>
+  <span class="cue">Bear is Coming!!!!!</span>
+</div>
+</html>
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-non-snap-to-lines.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-non-snap-to-lines.html
new file mode 100644
index 0000000..0da8c6f8
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-non-snap-to-lines.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<title>Position is not adjusted for non snap-to-lines cues</title>
+<link rel="match" href="track-webvtt-non-snap-to-lines-ref.html">
+<script src="/common/reftest-wait.js"></script>
+<script src="/common/media.js"></script>
+<style>
+::cue {
+  background: green;
+}
+</style>
+<video autoplay onplaying="this.onplaying = null; this.pause(); takeScreenshot();"></video>
+<script>
+var video = document.querySelector("video");
+var track = video.addTextTrack("captions");
+var cue = new VTTCue(0, 1, "Bear is Coming!!!!!");
+cue.snapToLines = false;
+cue.line = 20;
+cue.align = "left";
+track.addCue(cue);
+track.mode = "showing";
+video.src = getVideoURI("/media/test");
+</script>
+</html>
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/media/track/track-webvtt-two-cue-layout-after-first-end-expected.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-two-cue-layout-after-first-end-ref.html
similarity index 63%
rename from third_party/WebKit/LayoutTests/media/track/track-webvtt-two-cue-layout-after-first-end-expected.html
rename to third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-two-cue-layout-after-first-end-ref.html
index fa89860..c0415367 100644
--- a/third_party/WebKit/LayoutTests/media/track/track-webvtt-two-cue-layout-after-first-end-expected.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-two-cue-layout-after-first-end-ref.html
@@ -1,8 +1,10 @@
 <!DOCTYPE html>
+<html class="reftest-wait">
 <title>WebVTT two-cue layout after the first cue has ended (reference)</title>
+<script src="/common/reftest-wait.js"></script>
 <video style="border:1px solid gray">
-  <source src="../content/white.webm" type="video/webm">
-  <source src="../content/white.mp4" type="video/mp4">
+  <source src="/media/white.webm" type="video/webm">
+  <source src="/media/white.mp4" type="video/mp4">
 </video>
 <script>
 // Add a single cue at line -2, where it would be if there was a first
@@ -13,4 +15,9 @@
 cue.line = -2;
 track.addCue(cue);
 track.mode = "showing";
+
+video.onloadeddata = function() {
+  takeScreenshot();
+};
 </script>
+</html>
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-two-cue-layout-after-first-end.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-two-cue-layout-after-first-end.html
new file mode 100644
index 0000000..c90313c88
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-two-cue-layout-after-first-end.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<title>WebVTT two-cue layout after the first cue has ended</title>
+<link rel="match" href="track-webvtt-two-cue-layout-after-first-end-ref.html">
+<script src="/common/reftest-wait.js"></script>
+<video style="border:1px solid gray">
+  <source src="/media/white.webm" type="video/webm">
+  <source src="/media/white.mp4" type="video/mp4">
+</video>
+<script>
+// Add two cues, where the first cue ends before the second.
+var video = document.querySelector("video");
+var track = video.addTextTrack("captions");
+track.addCue(new VTTCue(0, 1, "cue 1"));
+track.addCue(new VTTCue(0, 3, "cue 2"));
+track.mode = "showing";
+
+video.onloadeddata = function() {
+  // Double nesting of requestAnimationFrame to
+  // make sure cue layout and paint happens.
+  window.requestAnimationFrame(function() {
+    window.requestAnimationFrame(function() {
+      // Seek past the end of the first cue. The second cue should not move.
+      video.currentTime = 2;
+      video.onseeked = function() { takeScreenshot(); };
+    });
+  });
+};
+</script>
+</html>
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/forms/the-input-element/checkbox-click-events-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/forms/the-input-element/checkbox-click-events-expected.txt
deleted file mode 100644
index 61398503..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/forms/the-input-element/checkbox-click-events-expected.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-This is a testharness.js-based test.
-PASS clicking and preventDefaulting a checkbox causes the checkbox to be checked during the click handler but reverted
-FAIL a checkbox input emits click, input, change events in order after synthetic click assert_array_equals: lengths differ, expected 3 got 2
-FAIL a checkbox input emits click, input, change events in order after dispatching click event assert_array_equals: lengths differ, expected 3 got 2
-PASS checkbox input respects cancel behavior on synthetic clicks
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/forms/the-input-element/checkbox-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/forms/the-input-element/checkbox-expected.txt
deleted file mode 100644
index 5f40ca4b..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/forms/the-input-element/checkbox-expected.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-This is a testharness.js-based test.
-FAIL click on mutable checkbox fires a click event, then an input event, then a change event assert_true: change event should fire after input event expected true got false
-PASS click on non-mutable checkbox doesn't fire the input or change event
-PASS pre-activation steps on unchecked checkbox
-PASS pre-activation steps on checked checkbox
-PASS canceled activation steps on unchecked checkbox
-PASS canceled activation steps on unchecked checkbox (indeterminate=true in onclick)
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/rellist-feature-detection.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/rellist-feature-detection.html
new file mode 100644
index 0000000..9295913
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/rellist-feature-detection.html
@@ -0,0 +1,80 @@
+<!DOCTYPE html>
+<title>Test relList attribute</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+let link_support_table = {};
+// https://html.spec.whatwg.org/multipage/links.html#linkTypes
+link_support_table['link'] = {
+  supported : ['modulepreload', 'preload', 'preconnect', 'dns-prefetch',
+               'stylesheet', 'import', 'icon', 'alternate', 'prefetch',
+               'prerender', 'next', 'manifest', 'apple-touch-icon',
+               'apple-touch-icon-precomposed', 'canonical'],
+  unsupported : ['author', 'bookmark', 'external', 'help', 'license',
+                 'nofollow', 'pingback', 'prev', 'search', 'tag',
+                 'noreferrer', 'noopener']
+};
+link_support_table['a'] =  {
+  supported : ['noreferrer', 'noopener'],
+  unsupported : ['author', 'bookmark', 'external', 'help', 'license',
+                 'nofollow', 'pingback', 'prev', 'search', 'tag',
+                 'modulepreload', 'preload', 'preconnect', 'dns-prefetch',
+                 'stylesheet', 'import', 'icon', 'alternate', 'prefetch',
+                 'prerender', 'next', 'manifest', 'apple-touch-icon',
+                 'apple-touch-icon-precomposed', 'canonical']
+};
+link_support_table['area'] = link_support_table['a'];
+
+function test_rellist(tag_name, rel_table) {
+  let element = document.createElement(tag_name);
+  let tag = element.tagName;
+  // Test that setting rel is also setting relList, for both
+  // valid and invalid values.
+  element.rel = 'whatever';
+  assert_true(element.relList.contains('whatever'), 'tag = ' + tag + ', setting rel must work');
+  element.rel = 'prefetch';
+  assert_true(element.relList.contains('prefetch'), 'tag = ' + tag + ', setting rel must work');
+  // Test that add() works.
+  element.relList.add('preloadwhatever');
+  assert_equals(element.rel, 'prefetch preloadwhatever', 'tag = ' + tag + ', add must work');
+  assert_true(element.relList.contains('preloadwhatever'), 'tag = ' + tag + ', add must work');
+  // Test that remove() works.
+  element.relList.remove('preloadwhatever');
+  assert_equals(element.rel, 'prefetch', 'tag = ' + tag + ', remove must work');
+  assert_false(element.relList.contains('preloadwhatever'), 'tag = ' + tag + ', remove must work');
+  // Test that toggle() works.
+  element.relList.toggle('prefetch', false);
+  assert_equals(element.rel, '', 'tag = ' + tag + ', toggle must work');
+  element.relList.toggle('prefetch', true);
+  assert_equals(element.rel, 'prefetch', 'tag = ' + tag + ', toggle must work');
+  // Test that replace() works.
+  element.relList.replace('prefetch', 'first');
+  assert_equals(element.rel, 'first', 'tag = ' + tag + ', replace must work');
+  // Test that indexed item getter works.
+  element.relList.add('second');
+  assert_equals(element.relList.length, 2, 'tag = ' + tag + ', relList length must be correct');
+  assert_equals(element.relList[0], 'first', 'tag = ' + tag + ', relList indexed item must work');
+  assert_equals(element.relList[1], 'second', 'tag = ' + tag + ', relList indexed item must work');
+  // Test that relList is  [SameObject].
+  let savedRelList = element.relList;
+  element.rel = 'something';
+  assert_equals(element.relList, savedRelList, 'tag = ' + tag + ', SameObject must work');
+
+  // Test that supports() is returning true for valid values
+  // and false for invalid ones.
+  let supported = rel_table['supported'];
+  for (let link_type in supported) {
+    assert_true(element.relList.supports(supported[link_type]), 'tag = ' + tag + ', link type = ' + supported[link_type] + ' must be supported');
+  }
+  let unsupported = rel_table['unsupported'];
+  for (let link_type in unsupported) {
+    assert_false(element.relList.supports(unsupported[link_type]), 'tag = ' + tag + ', link type = ' + unsupported[link_type] + ' must be unsupported');
+  }
+}
+
+test(function() {
+  test_rellist('LINK', link_support_table['link']);
+  test_rellist('A', link_support_table['a']);
+  test_rellist('AREA', link_support_table['area']);
+}, 'Make sure that relList based feature detection is working');
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/text-level-semantics/the-a-element/rellist-feature-detection.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/text-level-semantics/the-a-element/rellist-feature-detection.html
deleted file mode 100644
index 5af9a5e..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/text-level-semantics/the-a-element/rellist-feature-detection.html
+++ /dev/null
@@ -1,57 +0,0 @@
-<!DOCTYPE html>
-<title>HTMLAnchorElement relList</title>
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script>
-test(function() {
-  var element = document.createElement("a");
-  // Test that setting rel is also setting relList, for both
-  // valid and invalid values.
-  element.rel = "whatever";
-  assert_true(element.relList.contains("whatever"));
-  element.rel = "prefetch";
-  assert_true(element.relList.contains("prefetch"));
-  // Test that add() works.
-  element.relList.add("preloadwhatever");
-  assert_equals(element.rel, "prefetch preloadwhatever");
-  assert_true(element.relList.contains("preloadwhatever"));
-  // Test that remove() works.
-  element.relList.remove("preloadwhatever");
-  assert_equals(element.rel, "prefetch");
-  assert_false(element.relList.contains("preloadwhatever"));
-  // Test that toggle() works.
-  element.relList.toggle("prefetch", false);
-  assert_equals(element.rel, "");
-  element.relList.toggle("prefetch", true);
-  assert_equals(element.rel, "prefetch");
-  // Test that replace() works.
-  element.relList.replace("prefetch", "first");
-  assert_equals(element.rel, "first");
-  // Test that indexed item getter works.
-  element.relList.add("second");
-  assert_equals(element.relList.length, 2);
-  assert_equals(element.relList[0], "first");
-  assert_equals(element.relList[1], "second");
-  // Test that relList is  [SameObject].
-  let savedRelList = element.relList;
-  element.rel = "something";
-  assert_equals(element.relList, savedRelList);
-
-  // Test that supports() is returning true for valid values
-  // and false for invalid ones.
-  assert_false(element.relList.supports("bogus"));
-  assert_false(element.relList.supports("alternate"));
-  assert_false(element.relList.supports("author"));
-  assert_false(element.relList.supports("bookmark"));
-  assert_false(element.relList.supports("external"));
-  assert_false(element.relList.supports("help"));
-  assert_false(element.relList.supports("license"));
-  assert_false(element.relList.supports("next"));
-  assert_false(element.relList.supports("nofollow"));
-  assert_false(element.relList.supports("prev"));
-  assert_false(element.relList.supports("search"));
-  assert_false(element.relList.supports("tag"));
-  assert_true(element.relList.supports("noreferrer"));
-  assert_true(element.relList.supports("noopener"));
-}, "Make sure that relList based feature detection is working");
-</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/text-level-semantics/the-area-element/rellist-feature-detection.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/text-level-semantics/the-area-element/rellist-feature-detection.html
deleted file mode 100644
index 1099819..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/text-level-semantics/the-area-element/rellist-feature-detection.html
+++ /dev/null
@@ -1,57 +0,0 @@
-<!DOCTYPE html>
-<title>HTMLAreaElement relList</title>
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script>
-test(function() {
-  var element = document.createElement("area");
-  // Test that setting rel is also setting relList, for both
-  // valid and invalid values.
-  element.rel = "whatever";
-  assert_true(element.relList.contains("whatever"));
-  element.rel = "prefetch";
-  assert_true(element.relList.contains("prefetch"));
-  // Test that add() works.
-  element.relList.add("preloadwhatever");
-  assert_equals(element.rel, "prefetch preloadwhatever");
-  assert_true(element.relList.contains("preloadwhatever"));
-  // Test that remove() works.
-  element.relList.remove("preloadwhatever");
-  assert_equals(element.rel, "prefetch");
-  assert_false(element.relList.contains("preloadwhatever"));
-  // Test that toggle() works.
-  element.relList.toggle("prefetch", false);
-  assert_equals(element.rel, "");
-  element.relList.toggle("prefetch", true);
-  assert_equals(element.rel, "prefetch");
-  // Test that replace() works.
-  element.relList.replace("prefetch", "first");
-  assert_equals(element.rel, "first");
-  // Test that indexed item getter works.
-  element.relList.add("second");
-  assert_equals(element.relList.length, 2);
-  assert_equals(element.relList[0], "first");
-  assert_equals(element.relList[1], "second");
-  // Test that relList is  [SameObject].
-  let savedRelList = element.relList;
-  element.rel = "something";
-  assert_equals(element.relList, savedRelList);
-
-  // Test that supports() is returning true for valid values
-  // and false for invalid ones.
-  assert_false(element.relList.supports("bogus"));
-  assert_false(element.relList.supports("alternate"));
-  assert_false(element.relList.supports("author"));
-  assert_false(element.relList.supports("bookmark"));
-  assert_false(element.relList.supports("external"));
-  assert_false(element.relList.supports("help"));
-  assert_false(element.relList.supports("license"));
-  assert_false(element.relList.supports("next"));
-  assert_false(element.relList.supports("nofollow"));
-  assert_false(element.relList.supports("prev"));
-  assert_false(element.relList.supports("search"));
-  assert_false(element.relList.supports("tag"));
-  assert_true(element.relList.supports("noreferrer"));
-  assert_true(element.relList.supports("noopener"));
-}, "Make sure that relList based feature detection is working");
-</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/shadow-dom/event-composed-path-with-related-target.html b/third_party/WebKit/LayoutTests/external/wpt/shadow-dom/event-composed-path-with-related-target.html
index 675a7d7..f6dff13a 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/shadow-dom/event-composed-path-with-related-target.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/shadow-dom/event-composed-path-with-related-target.html
@@ -131,14 +131,12 @@
                                  ['sr2', 'target', 'host1', path],
                                  ['host2', 'host2', 'host1', path],
                                  ['sr1', 'host2', 'host1', path]]);
-}, 'Event path for an event with a relatedTarget. relaterTarget is a shadow-including ancestor of target.');
+}, 'Event path for an event with a relatedTarget. relatedTarget is a shadow-including ancestor of target.');
 
 test(() => {
   let n = createTestTree(test4);
   let log = dispatchEventWithLog(n, n.host1, new FocusEvent('my-focus', { bubbles: true, composed: true, relatedTarget: n.target }));
-  let path = ['host1', 'test4'];
-  assert_event_path_equals(log, [['host1', 'host1', 'host1', path],
-                                 ['test4', 'host1', 'host1', path]]);
+  assert_event_path_equals(log, []);
 }, 'Event path for an event with a relatedTarget. target is a shadow-including ancestor of relatedTarget.');
 </script>
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webauthn/createcredential-badargs-rp.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/webauthn/createcredential-badargs-rp.https-expected.txt
new file mode 100644
index 0000000..9ba21178
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/webauthn/createcredential-badargs-rp.https-expected.txt
@@ -0,0 +1,14 @@
+This is a testharness.js-based test.
+PASS rp missing
+PASS rp is string
+FAIL Bad rp: id is object assert_throws: Expected bad parameters to fail function "function() { throw e }" threw object "SecurityError: The relying party ID '[object Object]' is not a registrable domain suffix of, nor equal to 'https://web-platform.test:8444'." ("SecurityError") expected object "TypeError" ("TypeError")
+FAIL Bad rp: id is null assert_throws: Expected bad parameters to fail function "function() { throw e }" threw object "SecurityError: The relying party ID 'null' is not a registrable domain suffix of, nor equal to 'https://web-platform.test:8444'." ("SecurityError") expected object "TypeError" ("TypeError")
+FAIL Bad rp: id is empty String assert_throws: Expected bad parameters to fail function "function() { throw e }" threw object "NotSupportedError: The user agent does not implement a password store." ("NotSupportedError") expected object "TypeError" ("TypeError")
+FAIL Bad rp: name is object assert_throws: Expected bad parameters to fail function "function() { throw e }" threw object "NotSupportedError: The user agent does not implement a password store." ("NotSupportedError") expected object "TypeError" ("TypeError")
+FAIL Bad rp: name is null assert_throws: Expected bad parameters to fail function "function() { throw e }" threw object "NotSupportedError: The user agent does not implement a password store." ("NotSupportedError") expected object "TypeError" ("TypeError")
+FAIL Bad rp: name is empty String assert_throws: Expected bad parameters to fail function "function() { throw e }" threw object "NotSupportedError: The user agent does not implement a password store." ("NotSupportedError") expected object "TypeError" ("TypeError")
+FAIL Bad rp: icon is object assert_throws: Expected bad parameters to fail function "function() { throw e }" threw object "NotSupportedError: The user agent does not implement a password store." ("NotSupportedError") expected object "TypeError" ("TypeError")
+FAIL Bad rp: icon is null assert_throws: Expected bad parameters to fail function "function() { throw e }" threw object "NotSupportedError: The user agent does not implement a password store." ("NotSupportedError") expected object "TypeError" ("TypeError")
+FAIL Bad rp: icon is empty String assert_throws: Expected bad parameters to fail function "function() { throw e }" threw object "NotSupportedError: The user agent does not implement a password store." ("NotSupportedError") expected object "TypeError" ("TypeError")
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webauthn/createcredential-badargs-rp.https.html b/third_party/WebKit/LayoutTests/external/wpt/webauthn/createcredential-badargs-rp.https.html
new file mode 100644
index 0000000..f06e02cc
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/webauthn/createcredential-badargs-rp.https.html
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>WebAuthn navigator.credentials.create() rp Tests</title>
+<link rel="author" title="Adam Powers" href="mailto:adam@fidoalliance.org">
+<link rel="help" href="https://w3c.github.io/webauthn/#iface-credential">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src=helpers.js></script>
+<body></body>
+<script>
+standardSetup(function() {
+    "use strict";
+
+    // rp bad values
+    new CreateCredentialsTest({path: "options.publicKey.rp", value: undefined}).testBadArgs("rp missing");
+    new CreateCredentialsTest("options.publicKey.rp", "hi mom").testBadArgs("rp is string");
+    // new CreateCredentialsTest("options.publicKey.rp", {}).testBadArgs("rp is empty object");
+
+    // rp.id
+    // new CreateCredentialsTest({path: "options.publicKey.rp.id", value: undefined}).testBadArgs("rp missing id");
+    new CreateCredentialsTest("options.publicKey.rp.id", {}).testBadArgs("Bad rp: id is object");
+    new CreateCredentialsTest("options.publicKey.rp.id", null).testBadArgs("Bad rp: id is null");
+    new CreateCredentialsTest("options.publicKey.rp.id", "").testBadArgs("Bad rp: id is empty String");
+
+    // rp.name
+    // new CreateCredentialsTest({path: "options.publicKey.rp.name", value: undefined}).testBadArgs("rp missing name");
+    new CreateCredentialsTest("options.publicKey.rp.name", {}).testBadArgs("Bad rp: name is object");
+    new CreateCredentialsTest("options.publicKey.rp.name", null).testBadArgs("Bad rp: name is null");
+    new CreateCredentialsTest("options.publicKey.rp.name", "").testBadArgs("Bad rp: name is empty String");
+
+    // rp.icon
+    // new CreateCredentialsTest({path: "options.publicKey.rp.icon", value: undefined}).testBadArgs("rp missing icon");
+    new CreateCredentialsTest("options.publicKey.rp.icon", {}).testBadArgs("Bad rp: icon is object");
+    new CreateCredentialsTest("options.publicKey.rp.icon", null).testBadArgs("Bad rp: icon is null");
+    new CreateCredentialsTest("options.publicKey.rp.icon", "").testBadArgs("Bad rp: icon is empty String");
+    // TODO: see https://github.com/w3c/webauthn/issues/587 for the 'undefined' tests that are commented out above
+    // TODO: unicode tests for icon URL (see also: USVString)
+});
+
+/* JSHINT */
+/* globals standardSetup, CreateCredentialsTest */
+</script>
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webauthn/createcredential-passing.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/webauthn/createcredential-passing.https-expected.txt
new file mode 100644
index 0000000..f2ce985
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/webauthn/createcredential-passing.https-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL WebAuthn credential.create() Passing Tests promise_test: Unhandled rejection with value: object "NotSupportedError: The user agent does not implement a password store."
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webauthn/createcredential-passing.https.html b/third_party/WebKit/LayoutTests/external/wpt/webauthn/createcredential-passing.https.html
new file mode 100644
index 0000000..a66d3c1
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/webauthn/createcredential-passing.https.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>WebAuthn credential.create() Passing Tests</title>
+<link rel="author" title="Adam Powers" href="mailto:adam@fidoalliance.org">
+<link rel="help" href="https://w3c.github.io/webauthn/#iface-credential">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src=helpers.js></script>
+<body></body>
+<script>
+standardSetup(function() {
+    "use strict";
+
+    // CreateCredentialTest passing tests
+    new CreateCredentialsTest().test();
+});
+
+/* JSHINT */
+/* globals standardSetup, CreateCredentialsTest */
+</script>
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webauthn/getcredential-passing.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/webauthn/getcredential-passing.https-expected.txt
new file mode 100644
index 0000000..eee96a9
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/webauthn/getcredential-passing.https-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL WebAuthn credential.get() Passing Tests The user agent does not implement a password store.
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webauthn/getcredential-passing.https.html b/third_party/WebKit/LayoutTests/external/wpt/webauthn/getcredential-passing.https.html
new file mode 100644
index 0000000..c7cf794
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/webauthn/getcredential-passing.https.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>WebAuthn credential.get() Passing Tests</title>
+<link rel="author" title="Adam Powers" href="mailto:adam@fidoalliance.org">
+<link rel="help" href="https://w3c.github.io/webauthn/#iface-credential">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src=helpers.js></script>
+<body></body>
+<script>
+standardSetup(function() {
+    "use strict";
+
+    // GetCredentialsTest passing tests
+    // new GetCredentialsTest().addCredential();
+    new GetCredentialsTest().addCredential().test();
+});
+
+/* JSHINT */
+/* globals standardSetup, GetCredentialsTest */
+</script>
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webauthn/helpers.js b/third_party/WebKit/LayoutTests/external/wpt/webauthn/helpers.js
index e36cb6d..11d0aee 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/webauthn/helpers.js
+++ b/third_party/WebKit/LayoutTests/external/wpt/webauthn/helpers.js
@@ -1,3 +1,15 @@
+
+/* Useful constants for working with COSE key objects */
+const cose_kty = 1;
+const cose_kty_ec2 = 2;
+const cose_alg = 3;
+const cose_alg_ECDSA_w_SHA256 = -7;
+const cose_alg_ECDSA_w_SHA512 = -36;
+const cose_crv = -1;
+const cose_crv_P256 = 1;
+const cose_crv_x = -2;
+const cose_crv_y = -3;
+
 /**
  * TestCase
  *
@@ -5,7 +17,7 @@
  * Is intended to be overloaded with subclasses that override testObject, testFunction and argOrder
  * The testObject is the default arguments for the testFunction
  * The default testObject can be modified with the modify() method, making it easy to create new tests based on the default
- * The testFunction is the target of the test and is called by the test() method. test() applies the testObject as arguments via toArgs()
+ * The testFunction is the target of the test and is called by the doIt() method. doIt() applies the testObject as arguments via toArgs()
  * toArgs() uses argOrder to make sure the resulting array is in the right order of the arguments for the testFunction
  */
 class TestCase {
@@ -15,6 +27,7 @@
         };
         this.testObject = {};
         this.argOrder = [];
+        this.ctx = null;
     }
 
     /**
@@ -70,7 +83,6 @@
         }
 
         // iterate through each of the desired modifications, and call recursiveSetObject on them
-        var obj = this.testObject;
         for (let idx in mods) {
             var mod = mods[idx];
             let paths = mod.path.split(".");
@@ -94,61 +106,103 @@
     }
 
     /**
-     * test
-     *
-     * run the test function with the top-level properties of the test object applied as arguments
+     * actually runs the test function with the supplied arguments
      */
-    test() {
-        return this.testFunction(...this.toArgs());
+    doIt() {
+        if (typeof this.testFunction !== "function") {
+            throw new Error("Test function not found");
+        }
+
+        return this.testFunction.call(this.ctx, ...this.toArgs());
     }
 
     /**
-     * testArgs
-     *
-     * calls test() with testObject() and expects it to fail with a TypeError()
+     * run the test function with the top-level properties of the test object applied as arguments
+     */
+    test(desc) {
+        promise_test(() => {
+            return this.doIt()
+                .then((ret) => {
+                    // check the result
+                    this.validateRet(ret);
+                    return ret;
+                });
+        }, desc);
+    }
+
+    /**
+     * validates the value returned from the test function
+     */
+    validateRet() {
+        throw new Error("Not implemented");
+    }
+
+    /**
+     * calls doIt() with testObject() and expects it to fail with a TypeError()
      */
     testBadArgs(testDesc) {
         promise_test(function(t) {
-            return promise_rejects(t, new TypeError(), this.test());
+            return promise_rejects(t, new TypeError(), this.doIt(), "Expected bad parameters to fail");
         }.bind(this), testDesc);
     }
 }
 
+var createCredentialDefaultArgs = {
+    options: {
+        publicKey: {
+            // Relying Party:
+            rp: {
+                name: "Acme"
+            },
+
+            // User:
+            user: {
+                id: new Uint8Array(), // Won't survive the copy, must be rebuilt
+                name: "john.p.smith@example.com",
+                displayName: "John P. Smith",
+                icon: "https://pics.acme.com/00/p/aBjjjpqPb.png"
+            },
+
+            pubKeyCredParams: [{
+                type: "public-key",
+                alg: cose_alg_ECDSA_w_SHA256,
+            }],
+
+            timeout: 60000, // 1 minute
+            excludeCredentials: [] // No excludeList
+        }
+    }
+};
+
+function cloneObject(o) {
+    return JSON.parse(JSON.stringify(o));
+}
+
 /**
- * MakeCredentialTest
+ * CreateCredentialTest
  *
- * tests the WebAuthn makeCredential() interface
+ * tests the WebAuthn navigator.credentials.create() interface
  */
-class MakeCredentialTest extends TestCase {
+class CreateCredentialsTest extends TestCase {
     constructor() {
         // initialize the parent class
         super();
 
         // the function to be tested
-        this.testFunction = navigator.authentication.makeCredential;
+        this.testFunction = navigator.credentials.create;
+        // the context to call the test function with (i.e. - the 'this' object for the function)
+        this.ctx = navigator.credentials;
 
         // the default object to pass to makeCredential, to be modified with modify() for various tests
-        // var challenge = Uint8Array.from("Y2xpbWIgYSBtb3VudGFpbg");
-        this.testObject = {
-            accountInformation: {
-                rpDisplayName: "ACME",
-                displayName: "John P. Smith",
-                name: "johnpsmith@example.com",
-                id: "1098237235409872",
-                imageUri: "https://pics.acme.com/00/p/aBjjjpqPb.png"
-            },
-            cryptoParameters: [{
-                type: "ScopedCred",
-                algorithm: "RSASSA-PKCS1-v1_5",
-            }],
-            attestationChallenge: Uint8Array.from([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17]).buffer
-        };
+        let challengeBytes = new Uint8Array(16);
+        window.crypto.getRandomValues(challengeBytes);
+        this.testObject = cloneObject(createCredentialDefaultArgs);
+        // cloneObject can't clone the BufferSource in user.id, so let's recreate it.
+        this.testObject.options.publicKey.user.id = new Uint8Array();
+        this.testObject.options.publicKey.challenge = challengeBytes;
 
         // how to order the properties of testObject when passing them to makeCredential
         this.argOrder = [
-            "accountInformation",
-            "cryptoParameters",
-            "attestationChallenge",
             "options"
         ];
 
@@ -156,43 +210,201 @@
         // would prefer to do this in the super class, but have to call super() before using `this.*`
         if (arguments.length) this.modify(...arguments);
     }
+
+    validateRet(ret) {
+        validatePublicKeyCredential(ret);
+        validateAuthenticatorAttestationResponse(ret.response);
+    }
 }
 
-//************* BEGIN DELETE AFTER 1/1/2017 *************** //
+/**
+ * GetCredentialsTest
+ *
+ * tests the WebAuthn navigator.credentials.get() interface
+ */
+class GetCredentialsTest extends TestCase {
+    constructor(...args) {
+        // initialize the parent class
+        super();
+
+        // the function to be tested
+        this.testFunction = navigator.credentials.get;
+        // the context to call the test function with (i.e. - the 'this' object for the function)
+        this.ctx = navigator.credentials;
+
+        // default arguments
+        let challengeBytes = new Uint8Array(16);
+        window.crypto.getRandomValues(challengeBytes);
+        this.testObject = {
+            options: {
+                publicKey: {
+                    challenge: challengeBytes,
+                    // timeout: 60000,
+                    // allowCredentials: [newCredential]
+                }
+            }
+        };
+
+        // how to order the properties of testObject when passing them to makeCredential
+        this.argOrder = [
+            "options"
+        ];
+
+        this.credentialPromiseList = [];
+
+        // enable the constructor to modify the default testObject
+        // would prefer to do this in the super class, but have to call super() before using `this.*`
+        if (arguments.length) {
+            if (args.cred instanceof Promise) this.credPromise = args.cred;
+            else if (typeof args.cred === "object") this.credPromise = Promise.resolve(args.cred);
+            delete args.cred;
+            this.modify(...arguments);
+        }
+    }
+
+    addCredential(arg) {
+        // if a Promise was passed in, add it to the list
+        if (arg instanceof Promise) {
+            this.credentialPromiseList.push(arg);
+            return;
+        }
+
+        // if a credential object was passed in, convert it to a Promise for consistency
+        if (typeof arg === "object") {
+            this.credentialPromiseList.push(Promise.resolve(arg));
+            return;
+        }
+
+        // if a credential wasn't passed in, create one
+        let challengeBytes = new Uint8Array(16);
+        window.crypto.getRandomValues(challengeBytes);
+        var createArgs = cloneObject(createCredentialDefaultArgs);
+        createArgs.options.publicKey.challenge = challengeBytes;
+        createArgs.options.publicKey.user.id = new Uint8Array();
+        var p = navigator.credentials.create(createArgs.options);
+        this.credentialPromiseList.push(p);
+
+        return this;
+    }
+
+    test() {
+        if (!this.credentialPromiseList.length) {
+            throw new Error("Attempting list without defining credential to test");
+        }
+
+        Promise.all(this.credentialPromiseList)
+            .then((credList) => {
+                var idList = credList.map((cred) => {
+                    return {
+                        id: cred.rawId,
+                        transports: ["usb", "nfc", "ble"],
+                        type: "public-key"
+                    };
+                });
+                this.testObject.options.publicKey.allowCredentials = idList;
+                return super.test();
+            });
+    }
+
+    validateRet(ret) {
+        validatePublicKeyCredential (ret);
+        validateAuthenticatorAssertionResponse(ret.response);
+    }
+}
+
+/**
+ * runs assertions against a PublicKeyCredential object to ensure it is properly formatted
+ */
+function validatePublicKeyCredential(cred) {
+    // class
+    assert_class_string(cred, "PublicKeyCredential", "Expected return to be instance of 'PublicKeyCredential' class");
+    // id
+    assert_idl_attribute(cred, "id", "should return PublicKeyCredential with id attribute");
+    assert_readonly(cred, "id", "should return PublicKeyCredential with readonly id attribute");
+    // rawId
+    assert_idl_attribute(cred, "rawId", "should return PublicKeyCredential with rawId attribute");
+    assert_readonly(cred, "rawId", "should return PublicKeyCredential with readonly rawId attribute");
+    // type
+    assert_idl_attribute(cred, "type", "should return PublicKeyCredential with type attribute");
+    assert_equals(cred.type, "public-key", "should return PublicKeyCredential with type 'public-key'");
+}
+
+/**
+ * runs assertions against a AuthenticatorAttestationResponse object to ensure it is properly formatted
+ */
+function validateAuthenticatorAttestationResponse(attr) {
+    // class
+    assert_class_string(attr, "AuthenticatorAttestationResponse", "Expected credentials.create() to return instance of 'AuthenticatorAttestationResponse' class");
+    // clientDataJSON
+    assert_idl_attribute(attr, "clientDataJSON", "credentials.create() should return AuthenticatorAttestationResponse with clientDataJSON attribute");
+    assert_readonly(attr, "clientDataJSON", "credentials.create() should return AuthenticatorAttestationResponse with readonly clientDataJSON attribute");
+    // attestationObject
+    assert_idl_attribute(attr, "attestationObject", "credentials.create() should return AuthenticatorAttestationResponse with attestationObject attribute");
+    assert_readonly(attr, "attestationObject", "credentials.create() should return AuthenticatorAttestationResponse with readonly attestationObject attribute");
+}
+
+/**
+ * runs assertions against a AuthenticatorAssertionResponse object to ensure it is properly formatted
+ */
+function validateAuthenticatorAssertionResponse(assert) {
+    // class
+    assert_class_string(assert, "AuthenticatorAssertionResponse", "Expected credentials.create() to return instance of 'AuthenticatorAssertionResponse' class");
+    // clientDataJSON
+    assert_idl_attribute(assert, "clientDataJSON", "credentials.get() should return AuthenticatorAssertionResponse with clientDataJSON attribute");
+    assert_readonly(assert, "clientDataJSON", "credentials.get() should return AuthenticatorAssertionResponse with readonly clientDataJSON attribute");
+    // signature
+    assert_idl_attribute(assert, "signature", "credentials.get() should return AuthenticatorAssertionResponse with signature attribute");
+    assert_readonly(assert, "signature", "credentials.get() should return AuthenticatorAssertionResponse with readonly signature attribute");
+    // authenticatorData
+    assert_idl_attribute(assert, "authenticatorData", "credentials.get() should return AuthenticatorAssertionResponse with authenticatorData attribute");
+    assert_readonly(assert, "authenticatorData", "credentials.get() should return AuthenticatorAssertionResponse with readonly authenticatorData attribute");
+}
+
+//************* BEGIN DELETE AFTER 1/1/2018 *************** //
 // XXX for development mode only!!
 // debug() for debugging purposes... we can drop this later if it is considered ugly
 // note that debug is currently an empty function (i.e. - prints no output)
 // and debug only prints output if the polyfill is loaded
 var debug = function() {};
 // if the WebAuthn API doesn't exist load a polyfill for testing
-// note that the polyfill only gets loaded if navigator.authentication doesn't exist
+// note that the polyfill only gets loaded if navigator.credentials create doesn't exist
 // AND if the polyfill script is found at the right path (i.e. - the polyfill is opt-in)
 function ensureInterface() {
-    return new Promise(function(resolve, reject) {
-        if (typeof navigator.authentication !== "object") {
-            debug = console.log;
+    if (typeof navigator.credentials.create !== "function") {
+        debug = console.log;
 
-            // dynamic loading of polyfill script by creating new <script> tag and seeing the src=
-            var scriptElem = document.createElement("script");
-            if (typeof scriptElem !== "object") {
-                debug("ensureInterface: Error creating script element while attempting loading polyfill");
-                return reject(new Error("ensureInterface: Error creating script element while loading polyfill"));
-            }
-            scriptElem.type = "application/javascript";
-            scriptElem.onload = function() {
-                debug("!!! XXX - LOADING POLYFILL FOR WEBAUTHN TESTING - XXX !!!");
-                return resolve();
-            };
-            scriptElem.onerror = function() {
-                return reject(new Error("navigator.authentication does not exist"));
-            };
-            scriptElem.src = "/webauthn/webauthn-polyfill/webauthn-polyfill.js";
-            if (document.body) {
-                document.body.appendChild(scriptElem);
-            } else {
-                debug("ensureInterface: DOM has no body");
-                return reject(new Error("ensureInterface: DOM has no body"));
-            }
+        return loadJavaScript("/webauthn/webauthn-polyfill/webauthn-polyfill.js")
+            .then(() => {
+                return loadJavaScript("/webauthn/webauthn-soft-authn/soft-authn.js");
+            });
+    } else {
+        return Promise.resolve();
+    }
+}
+
+function loadJavaScript(path) {
+    return new Promise((resolve, reject) => {
+        // dynamic loading of polyfill script by creating new <script> tag and seeing the src=
+        var scriptElem = document.createElement("script");
+        if (typeof scriptElem !== "object") {
+            debug("ensureInterface: Error creating script element while attempting loading polyfill");
+            return reject(new Error("ensureInterface: Error creating script element while loading polyfill"));
+        }
+        scriptElem.type = "application/javascript";
+        scriptElem.onload = function() {
+            debug("!!! Loaded " + path + " ...");
+            return resolve();
+        };
+        scriptElem.onerror = function() {
+            debug("navigator.credentials.create does not exist");
+            resolve();
+        };
+        scriptElem.src = path;
+        if (document.body) {
+            document.body.appendChild(scriptElem);
+        } else {
+            debug("ensureInterface: DOM has no body");
+            return reject(new Error("ensureInterface: DOM has no body"));
         }
     });
 }
@@ -201,9 +413,10 @@
     return ensureInterface()
         .then(() => {
             if (cb) return cb();
-        })
-        .catch((err) => {
-            return (err);
         });
 }
-//************* END DELETE AFTER 1/1/2017 *************** //
\ No newline at end of file
+//************* END DELETE AFTER 1/1/2018 *************** //
+
+/* JSHINT */
+/* globals promise_rejects, assert_class_string, assert_equals, assert_idl_attribute, assert_readonly, promise_test */
+/* exported standardSetup, CreateCredentialsTest, GetCredentialsTest */
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webauthn/interfaces.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/webauthn/interfaces.https-expected.txt
new file mode 100644
index 0000000..765224c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/webauthn/interfaces.https-expected.txt
@@ -0,0 +1,33 @@
+This is a testharness.js-based test.
+PASS Validate WebAuthn IDL
+FAIL PublicKeyCredential interface: existence and properties of interface object Cannot read property 'has_extended_attribute' of undefined
+PASS PublicKeyCredential interface object length
+PASS PublicKeyCredential interface object name
+FAIL PublicKeyCredential interface: existence and properties of interface prototype object Cannot read property 'has_extended_attribute' of undefined
+PASS PublicKeyCredential interface: existence and properties of interface prototype object's "constructor" property
+PASS PublicKeyCredential interface: attribute rawId
+PASS PublicKeyCredential interface: attribute response
+FAIL PublicKeyCredential interface: operation getClientExtensionResults() assert_own_property: interface prototype object missing non-static operation expected property "getClientExtensionResults" missing
+FAIL PublicKeyCredential interface: operation isUserVerifyingPlatformAuthenticatorAvailable() assert_own_property: interface object missing static operation expected property "isUserVerifyingPlatformAuthenticatorAvailable" missing
+PASS AuthenticatorResponse interface: existence and properties of interface object
+PASS AuthenticatorResponse interface object length
+PASS AuthenticatorResponse interface object name
+PASS AuthenticatorResponse interface: existence and properties of interface prototype object
+PASS AuthenticatorResponse interface: existence and properties of interface prototype object's "constructor" property
+PASS AuthenticatorResponse interface: attribute clientDataJSON
+PASS AuthenticatorAttestationResponse interface: existence and properties of interface object
+PASS AuthenticatorAttestationResponse interface object length
+PASS AuthenticatorAttestationResponse interface object name
+PASS AuthenticatorAttestationResponse interface: existence and properties of interface prototype object
+PASS AuthenticatorAttestationResponse interface: existence and properties of interface prototype object's "constructor" property
+PASS AuthenticatorAttestationResponse interface: attribute attestationObject
+PASS AuthenticatorAssertionResponse interface: existence and properties of interface object
+PASS AuthenticatorAssertionResponse interface object length
+PASS AuthenticatorAssertionResponse interface object name
+PASS AuthenticatorAssertionResponse interface: existence and properties of interface prototype object
+PASS AuthenticatorAssertionResponse interface: existence and properties of interface prototype object's "constructor" property
+PASS AuthenticatorAssertionResponse interface: attribute authenticatorData
+PASS AuthenticatorAssertionResponse interface: attribute signature
+PASS AuthenticatorAssertionResponse interface: attribute userHandle
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webauthn/interfaces.idl b/third_party/WebKit/LayoutTests/external/wpt/webauthn/interfaces.idl
index 173e515..dcd1f87 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/webauthn/interfaces.idl
+++ b/third_party/WebKit/LayoutTests/external/wpt/webauthn/interfaces.idl
@@ -1,96 +1,134 @@
-[SecureContext] interface WebAuthentication {
-    Promise < ScopedCredentialInfo > makeCredential (
-        Account                                 accountInformation,
-        sequence < ScopedCredentialParameters > cryptoParameters,
-        BufferSource                            attestationChallenge,
-        optional ScopedCredentialOptions        options
-    );
-
-    Promise < WebAuthnAssertion > getAssertion (
-        BufferSource               assertionChallenge,
-        optional AssertionOptions  options
-    );
+[SecureContext, Exposed=Window]
+interface PublicKeyCredential : Credential {
+    [SameObject] readonly attribute ArrayBuffer              rawId;
+    [SameObject] readonly attribute AuthenticatorResponse    response;
+    AuthenticationExtensions getClientExtensionResults();
 };
 
-[SecureContext]
-interface ScopedCredentialInfo {
-    readonly attribute ScopedCredential     credential;
-    readonly attribute CryptoKey            publicKey;
-    readonly attribute WebAuthnAttestation  attestation;
+partial dictionary CredentialCreationOptions {
+    MakePublicKeyCredentialOptions      publicKey;
 };
 
-dictionary Account {
-    required DOMString rpDisplayName;
-    required DOMString displayName;
-    required DOMString id;
-    DOMString          name;
-    DOMString          imageURL;
+partial dictionary CredentialRequestOptions {
+    PublicKeyCredentialRequestOptions      publicKey;
 };
 
-dictionary ScopedCredentialParameters {
-    required ScopedCredentialType  type;
-    required AlgorithmIdentifier   algorithm;
+partial interface PublicKeyCredential {
+    static Promise < boolean > isUserVerifyingPlatformAuthenticatorAvailable();
 };
 
-dictionary ScopedCredentialOptions {
-    unsigned long                             timeoutSeconds;
-    USVString                                 rpId;
-    sequence < ScopedCredentialDescriptor >  excludeList;
-    WebAuthnExtensions                        extensions;
+[SecureContext, Exposed=Window]
+interface AuthenticatorResponse {
+    [SameObject] readonly attribute ArrayBuffer      clientDataJSON;
 };
 
-[SecureContext]
-interface WebAuthnAssertion {
-    readonly attribute ScopedCredential  credential;
-    readonly attribute ArrayBuffer       clientData;
-    readonly attribute ArrayBuffer       authenticatorData;
-    readonly attribute ArrayBuffer       signature;
+[SecureContext, Exposed=Window]
+interface AuthenticatorAttestationResponse : AuthenticatorResponse {
+    [SameObject] readonly attribute ArrayBuffer      attestationObject;
 };
 
-dictionary AssertionOptions {
-    unsigned long                            timeoutSeconds;
-    USVString                                rpId;
-    sequence < ScopedCredentialDescriptor > allowList;
-    WebAuthnExtensions                       extensions;
+[SecureContext, Exposed=Window]
+interface AuthenticatorAssertionResponse : AuthenticatorResponse {
+    [SameObject] readonly attribute ArrayBuffer      authenticatorData;
+    [SameObject] readonly attribute ArrayBuffer      signature;
+    [SameObject] readonly attribute ArrayBuffer      userHandle;
 };
 
-dictionary WebAuthnExtensions {
+dictionary PublicKeyCredentialParameters {
+    required PublicKeyCredentialType      type;
+    required COSEAlgorithmIdentifier      alg;
 };
 
-[SecureContext]
-interface WebAuthnAttestation {
-    readonly    attribute USVString     format;
-    readonly    attribute ArrayBuffer   clientData;
-    readonly    attribute ArrayBuffer   authenticatorData;
-    readonly    attribute any           attestation;
+dictionary MakePublicKeyCredentialOptions {
+    required PublicKeyCredentialRpEntity         rp;
+    required PublicKeyCredentialUserEntity       user;
+
+    required BufferSource                             challenge;
+    required sequence<PublicKeyCredentialParameters>  pubKeyCredParams;
+
+    unsigned long                                timeout;
+    sequence<PublicKeyCredentialDescriptor>      excludeCredentials = [];
+    AuthenticatorSelectionCriteria               authenticatorSelection;
+    AttestationConveyancePreference              attestation = "none";
+    AuthenticationExtensions                     extensions;
 };
 
-dictionary ClientData {
+dictionary PublicKeyCredentialEntity {
+    required DOMString    name;
+    USVString             icon;
+};
+
+dictionary PublicKeyCredentialRpEntity : PublicKeyCredentialEntity {
+    DOMString      id;
+};
+
+dictionary PublicKeyCredentialUserEntity : PublicKeyCredentialEntity {
+    required BufferSource   id;
+    required DOMString      displayName;
+};
+
+dictionary AuthenticatorSelectionCriteria {
+    AuthenticatorAttachment      authenticatorAttachment;
+    boolean                      requireResidentKey = false;
+    UserVerificationRequirement  userVerification = "preferred";
+};
+
+enum AuthenticatorAttachment {
+    "platform",       // Platform attachment
+    "cross-platform"  // Cross-platform attachment
+};
+
+enum AttestationConveyancePreference {
+    "none",
+    "indirect",
+    "direct"
+};
+
+dictionary PublicKeyCredentialRequestOptions {
+    required BufferSource                challenge;
+    unsigned long                        timeout;
+    USVString                            rpId;
+    sequence<PublicKeyCredentialDescriptor> allowCredentials = [];
+    UserVerificationRequirement          userVerification = "preferred";
+    AuthenticationExtensions             extensions;
+};
+
+typedef record<DOMString, any>       AuthenticationExtensions;
+
+dictionary CollectedClientData {
+    required DOMString           type;
     required DOMString           challenge;
     required DOMString           origin;
-    required AlgorithmIdentifier hashAlg;
-    DOMString                    tokenBinding;
-    WebAuthnExtensions           extensions;
+    required DOMString           hashAlgorithm;
+    DOMString                    tokenBindingId;
+    AuthenticationExtensions     clientExtensions;
+    AuthenticationExtensions     authenticatorExtensions;
 };
 
-enum ScopedCredentialType {
-    "ScopedCred"
+enum PublicKeyCredentialType {
+    "public-key"
 };
 
-[SecureContext]
-interface ScopedCredential {
-    readonly attribute ScopedCredentialType type;
-    readonly attribute ArrayBuffer          id;
+dictionary PublicKeyCredentialDescriptor {
+    required PublicKeyCredentialType      type;
+    required BufferSource                 id;
+    sequence<AuthenticatorTransport>      transports;
 };
 
-dictionary ScopedCredentialDescriptor {
-    required ScopedCredentialType type;
-    required BufferSource   id;
-    sequence < Transport >  transports;
-};
-
-enum Transport {
+enum AuthenticatorTransport {
     "usb",
     "nfc",
     "ble"
-};
\ No newline at end of file
+};
+
+typedef long COSEAlgorithmIdentifier;
+
+enum UserVerificationRequirement {
+    "required",
+    "preferred",
+    "discouraged"
+};
+
+typedef sequence<AAGUID>      AuthenticatorSelectionList;
+
+typedef BufferSource      AAGUID;
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webauthn/makecredential-badargs-accountinformation.https.html b/third_party/WebKit/LayoutTests/external/wpt/webauthn/makecredential-badargs-accountinformation.https.html
deleted file mode 100644
index e0e95e58..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/webauthn/makecredential-badargs-accountinformation.https.html
+++ /dev/null
@@ -1,34 +0,0 @@
-<!DOCTYPE html>
-<meta charset="utf-8">
-<title>WebAuthn makeCredential accountInformation Tests</title>
-<link rel="author" title="Adam Powers" href="mailto:adam@fidoalliance.org">
-<link rel="help" href="https://w3c.github.io/webauthn/#iface-credential">
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script src=helpers.js></script>
-<body></body>
-<script>
-standardSetup(function() {
-    "use strict";
-
-    // accountInformation bad values
-    new MakeCredentialTest({path: "accountInformation", value: undefined}).testBadArgs("accountInformation missing");
-    new MakeCredentialTest("accountInformation", "hi mom").testBadArgs("accountInformation is string");
-    new MakeCredentialTest("accountInformation", {}).testBadArgs("accountInformation is empty object");
-    // accountInformation.rpDisplayName
-    new MakeCredentialTest({path: "accountInformation.rpDisplayName", value: undefined}).testBadArgs("accountInformation missing rpDisplayName");
-    new MakeCredentialTest("accountInformation.rpDisplayName", {}).testBadArgs("Bad accountInformation: rpDisplayName is object");
-    new MakeCredentialTest("accountInformation.rpDisplayName", null).testBadArgs("Bad accountInformation: rpDisplayName is null");
-    new MakeCredentialTest("accountInformation.rpDisplayName", "").testBadArgs("Bad accountInformation: rpDisplayName is empty String");
-    // accountInformation.displayName
-    new MakeCredentialTest({path: "accountInformation.displayName", value: undefined}).testBadArgs("accountInformation missing displayName");
-    new MakeCredentialTest("accountInformation.displayName", {}).testBadArgs("Bad accountInformation: displayName is object");
-    new MakeCredentialTest("accountInformation.displayName", null).testBadArgs("Bad accountInformation: displayName is null");
-    new MakeCredentialTest("accountInformation.displayName", "").testBadArgs("Bad accountInformation: displayName is empty String");
-    // accountInformation.id
-    new MakeCredentialTest({path: "accountInformation.id", value: undefined}).testBadArgs("accountInformation missing id");
-    new MakeCredentialTest("accountInformation.id", {}).testBadArgs("Bad accountInformation: id is object");
-    new MakeCredentialTest("accountInformation.id", null).testBadArgs("Bad accountInformation: id is null");
-    new MakeCredentialTest("accountInformation.id", "").testBadArgs("Bad accountInformation: id is empty String");
-});
-</script>
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webauthn/makecredential-badargs-attestationchallenge.https.html b/third_party/WebKit/LayoutTests/external/wpt/webauthn/makecredential-badargs-attestationchallenge.https.html
deleted file mode 100644
index 441d1ad..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/webauthn/makecredential-badargs-attestationchallenge.https.html
+++ /dev/null
@@ -1,20 +0,0 @@
-<!DOCTYPE html>
-<meta charset="utf-8">
-<title>WebAuthn makeCredential attestationChallenge Tests</title>
-<link rel="author" title="Adam Powers" href="mailto:adam@fidoalliance.org">
-<link rel="help" href="https://w3c.github.io/webauthn/#iface-credential">
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script src=helpers.js></script>
-<body></body>
-<script>
-standardSetup(function() {
-    "use strict";
-
-    // attestationChallenge bad values
-    new MakeCredentialTest({path: "attestationChallenge", value: undefined}).testBadArgs("attestationChallenge missing");
-    new MakeCredentialTest("attestationChallenge", "hi mom").testBadArgs("accountInformation is string");
-    new MakeCredentialTest("attestationChallenge", {}).testBadArgs("accountInformation is empty object");
-    new MakeCredentialTest("attestationChallenge", Uint8Array.from([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17])).testBadArgs("accountInformation is Uint8Array");
-});
-</script>
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webauthn/makecredential-badargs-cryptoparameters.https.html b/third_party/WebKit/LayoutTests/external/wpt/webauthn/makecredential-badargs-cryptoparameters.https.html
deleted file mode 100644
index 7e177573..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/webauthn/makecredential-badargs-cryptoparameters.https.html
+++ /dev/null
@@ -1,33 +0,0 @@
-<!DOCTYPE html>
-<meta charset="utf-8">
-<title>WebAuthn makeCredential cryptoParameters Tests</title>
-<link rel="author" title="Adam Powers" href="mailto:adam@fidoalliance.org">
-<link rel="help" href="https://w3c.github.io/webauthn/#iface-credential">
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script src=helpers.js></script>
-<body></body>
-<script>
-standardSetup(function() {
-    "use strict";
-
-    // cryptoParameters bad values
-    new MakeCredentialTest({path: "cryptoParameters", value: undefined}).testBadArgs("cryptoParameters is missing");
-    new MakeCredentialTest("cryptoParameters", "hi mom").testBadArgs("cryptoParameters is String");
-    new MakeCredentialTest("cryptoParameters", []).testBadArgs("cryptoParameters is empty Array");
-    // cryptoParameters.type
-    new MakeCredentialTest({path: "cryptoParameters.0.type", value: undefined}).testBadArgs("cryptoParameters missing type");
-    new MakeCredentialTest("cryptoParameters.0.type", {}).testBadArgs("Bad cryptoParameters: type is object");
-    new MakeCredentialTest("cryptoParameters.0.type", null).testBadArgs("Bad cryptoParameters: type is null");
-    new MakeCredentialTest("cryptoParameters.0.type", "").testBadArgs("Bad cryptoParameters: type is empty String");
-    new MakeCredentialTest("cryptoParameters.0.type", "FIDO_2_0").testBadArgs("Bad cryptoParameters: type is not 'ScopedCred'");
-    // cryptoParameters.algorithm
-    new MakeCredentialTest({path: "cryptoParameters.0.algorithm", value: undefined}).testBadArgs("cryptoParameters missing algorithm");
-    new MakeCredentialTest("cryptoParameters.0.algorithm", {}).testBadArgs("Bad cryptoParameters: algorithm is object");
-    new MakeCredentialTest("cryptoParameters.0.algorithm", null).testBadArgs("Bad cryptoParameters: algorithm is null");
-    new MakeCredentialTest("cryptoParameters.0.algorithm", "").testBadArgs("Bad cryptoParameters: algorithm is empty String");
-    // multiple cryptoParameters
-    new MakeCredentialTest("cryptoParameters.1", {type: "FIDO_2_0", algorithm: "RSASSA-PKCS1-v1_5"}).testBadArgs("Bad cryptoParameters: second param has invalid type");
-    new MakeCredentialTest("cryptoParameters.1", {type: "ScopedCred", algorithm: ""}).testBadArgs("Bad cryptoParameters: second param has algorithm of empty String");
-});
-</script>
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webauthn/securecontext.http-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/webauthn/securecontext.http-expected.txt
new file mode 100644
index 0000000..3ba41d9
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/webauthn/securecontext.http-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL WebAuthn Secure Context Tests Uncaught TypeError: Cannot read property 'create' of undefined
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webauthn/securecontext.http.html b/third_party/WebKit/LayoutTests/external/wpt/webauthn/securecontext.http.html
new file mode 100644
index 0000000..82464bd8
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/webauthn/securecontext.http.html
@@ -0,0 +1,48 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>WebAuthn Secure Context Tests</title>
+<link rel="author" title="Adam Powers" href="mailto:adam@fidoalliance.org">
+<link rel="help" href="https://w3c.github.io/webauthn/#iface-credential">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src=helpers.js></script>
+<body></body>
+<script>
+standardSetup(function() {
+    "use strict";
+
+    // See https://www.w3.org/TR/secure-contexts/
+    // Section 1.1 - 1.4 for list of examples referenced below
+
+    // Example 1
+    // http://example.com/ opened in a top-level browsing context is not a secure context, as it was not delivered over an authenticated and encrypted channel.
+    test (() => {
+        assert_false (typeof navigator.credentials.create === "function");
+    }, "no navigator.credentials.create in non-secure context");
+
+    // Example 4: TODO
+    // If a non-secure context opens https://example.com/ in a new window, then things are more complicated. The new window’s status depends on how it was opened. If the non-secure context can obtain a reference to the secure context, or vice-versa, then the new window is not a secure context.
+    //
+    // This means that the following will both produce non-secure contexts:
+    //<a href="https://example.com/" target="_blank">Link!</a>
+    // <script>
+    //     var w = window.open("https://example.com/");
+    // < /script>
+
+    // Example 6: TODO
+    // If https://example.com/ was somehow able to frame http://non-secure.example.com/ (perhaps the user has overridden mixed content checking?), the top-level frame would remain secure, but the framed content is not a secure context.
+
+    // Example 7: TODO
+    // If, on the other hand, https://example.com/ is framed inside of http://non-secure.example.com/, then it is not a secure context, as its ancestor is not delivered over an authenticated and encrypted channel.
+
+    // Example 9: TODO
+    // If http://non-secure.example.com/ in a top-level browsing context frames https://example.com/, which runs https://example.com/worker.js, then neither the framed document nor the worker are secure contexts.
+
+    // Example 12: TODO
+    // https://example.com/ nested in http://non-secure.example.com/ may not connect to the secure worker, as it is not a secure context.
+
+    // Example 13: TODO
+    // Likewise, if https://example.com/ nested in http://non-secure.example.com/ runs https://example.com/worker.js as a Shared Worker, then both the document and the worker are considered non-secure.
+
+});
+</script>
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webauthn/securecontext.https.html b/third_party/WebKit/LayoutTests/external/wpt/webauthn/securecontext.https.html
new file mode 100644
index 0000000..9810a7fe
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/webauthn/securecontext.https.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>WebAuthn Secure Context Tests</title>
+<link rel="author" title="Adam Powers" href="mailto:adam@fidoalliance.org">
+<link rel="help" href="https://w3c.github.io/webauthn/#iface-credential">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src=helpers.js></script>
+<body></body>
+<script>
+standardSetup(function() {
+    "use strict";
+
+    // See https://www.w3.org/TR/secure-contexts/
+    // Section 1.1 - 1.4 for list of examples referenced below
+
+    // Example 2
+    // https://example.com/ opened in a top-level browsing context is a secure context, as it was delivered over an authenticated and encrypted channel.
+    test (() => {
+        assert_true (typeof navigator.credentials.create === "function");
+    }, "navigator.credentials.create exists in secure context");
+
+    // Example 3: TODO
+    // Example 5: TODO
+    // Example 8: TODO
+    // Example 10: TODO
+    // Example 11: TODO
+
+});
+</script>
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt_automation/css/selectors/hover-002-manual-automation.js b/third_party/WebKit/LayoutTests/external/wpt_automation/css/selectors/hover-002-manual-automation.js
new file mode 100644
index 0000000..b4968ca4
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt_automation/css/selectors/hover-002-manual-automation.js
@@ -0,0 +1,7 @@
+importAutomationScript('/pointerevents/pointerevent_common_input.js');
+
+function inject_input() {
+  return mouseMoveIntoTarget("#hovered").then(() => {
+    return mouseMoveIntoTarget("#hovered2");
+  });
+}
diff --git a/third_party/WebKit/LayoutTests/fast/alignment/new-alignment-values.html b/third_party/WebKit/LayoutTests/fast/alignment/new-alignment-values.html
index 4dd11c65..a80a3ee3 100644
--- a/third_party/WebKit/LayoutTests/fast/alignment/new-alignment-values.html
+++ b/third_party/WebKit/LayoutTests/fast/alignment/new-alignment-values.html
@@ -32,10 +32,10 @@
 {
     item.style.webkitAlignSelf = "flex-start";
 
-    checkAlignSelfValue("start unsafe", "start unsafe")
+    checkAlignSelfValue("unsafe start", "unsafe start")
     checkAlignSelfValue("start", "start")
     checkAlignSelfValue("end", "end")
-    checkAlignSelfValue("flex-start safe", "flex-start safe")
+    checkAlignSelfValue("safe flex-start", "safe flex-start")
     checkAlignSelfValue("self-start", "self-start")
     checkAlignSelfValue("self-end", "self-end")
 }
@@ -45,10 +45,10 @@
     container.style.webkitAlignItems = "flex-end";
     item.style.webkitAlignSelf = "auto";
 
-    checkAlignItemsValue("start unsafe", "start unsafe")
+    checkAlignItemsValue("unsafe start", "unsafe start")
     checkAlignItemsValue("start", "start")
     checkAlignItemsValue("end", "end")
-    checkAlignItemsValue("flex-start safe", "flex-start safe")
+    checkAlignItemsValue("safe flex-start", "safe flex-start")
     checkAlignItemsValue("self-start", "self-start")
     checkAlignItemsValue("self-end", "self-end")
 }
diff --git a/third_party/WebKit/LayoutTests/fast/alignment/overwrite-content-alignment-expected.txt b/third_party/WebKit/LayoutTests/fast/alignment/overwrite-content-alignment-expected.txt
index 5c8d0744..b887df00 100644
--- a/third_party/WebKit/LayoutTests/fast/alignment/overwrite-content-alignment-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/alignment/overwrite-content-alignment-expected.txt
@@ -3,8 +3,8 @@
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
 
 
-PASS getComputedStyle(childOfDefaultParent, '').getPropertyValue('justify-content') is "flex-end unsafe"
-PASS getComputedStyle(childOfDefaultParent, '').getPropertyValue('align-content') is "center safe"
+PASS getComputedStyle(childOfDefaultParent, '').getPropertyValue('justify-content') is "unsafe flex-end"
+PASS getComputedStyle(childOfDefaultParent, '').getPropertyValue('align-content') is "safe center"
 PASS getComputedStyle(childOfParentId, '').getPropertyValue('justify-content') is "space-between"
 PASS getComputedStyle(childOfParentId, '').getPropertyValue('align-content') is "space-around"
 PASS successfullyParsed is true
diff --git a/third_party/WebKit/LayoutTests/fast/alignment/overwrite-content-alignment.html b/third_party/WebKit/LayoutTests/fast/alignment/overwrite-content-alignment.html
index 1543050..6464840 100644
--- a/third_party/WebKit/LayoutTests/fast/alignment/overwrite-content-alignment.html
+++ b/third_party/WebKit/LayoutTests/fast/alignment/overwrite-content-alignment.html
@@ -5,8 +5,8 @@
 }
 .parent .child {
    display: flex;
-   justify-content: flex-end unsafe;
-   align-content: center safe;
+   justify-content: unsafe flex-end;
+   align-content: safe center;
 }
 #parentId .child {
    justify-content: space-between;
@@ -25,8 +25,8 @@
 description('Test overwriting justify-content and align-content works as expected');
 
 var childOfDefaultParent = document.getElementById("childOfDefaultParent");
-shouldBeEqualToString("getComputedStyle(childOfDefaultParent, '').getPropertyValue('justify-content')", "flex-end unsafe");
-shouldBeEqualToString("getComputedStyle(childOfDefaultParent, '').getPropertyValue('align-content')", "center safe");
+shouldBeEqualToString("getComputedStyle(childOfDefaultParent, '').getPropertyValue('justify-content')", "unsafe flex-end");
+shouldBeEqualToString("getComputedStyle(childOfDefaultParent, '').getPropertyValue('align-content')", "safe center");
 
 var childOfParentId = document.getElementById("childOfParentId");
 shouldBeEqualToString("getComputedStyle(childOfParentId, '').getPropertyValue('justify-content')", "space-between");
diff --git a/third_party/WebKit/LayoutTests/fast/alignment/overwrite-self-alignment-expected.txt b/third_party/WebKit/LayoutTests/fast/alignment/overwrite-self-alignment-expected.txt
index afc5949..cd7c4d28 100644
--- a/third_party/WebKit/LayoutTests/fast/alignment/overwrite-self-alignment-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/alignment/overwrite-self-alignment-expected.txt
@@ -5,8 +5,8 @@
 
 PASS getComputedStyle(parent, '').getPropertyValue('justify-items') is "center"
 PASS getComputedStyle(parent, '').getPropertyValue('align-items') is "stretch"
-PASS getComputedStyle(childOfDefaultParent, '').getPropertyValue('justify-self') is "flex-end unsafe"
-PASS getComputedStyle(childOfDefaultParent, '').getPropertyValue('align-self') is "flex-start safe"
+PASS getComputedStyle(childOfDefaultParent, '').getPropertyValue('justify-self') is "unsafe flex-end"
+PASS getComputedStyle(childOfDefaultParent, '').getPropertyValue('align-self') is "safe flex-start"
 PASS getComputedStyle(childOfParentId, '').getPropertyValue('justify-self') is "center"
 PASS getComputedStyle(childOfParentId, '').getPropertyValue('align-self') is "stretch"
 PASS successfullyParsed is true
diff --git a/third_party/WebKit/LayoutTests/fast/alignment/overwrite-self-alignment.html b/third_party/WebKit/LayoutTests/fast/alignment/overwrite-self-alignment.html
index 4e38c25..3bf7358 100644
--- a/third_party/WebKit/LayoutTests/fast/alignment/overwrite-self-alignment.html
+++ b/third_party/WebKit/LayoutTests/fast/alignment/overwrite-self-alignment.html
@@ -2,13 +2,13 @@
 <style>
 .parent {
    display: flex;
-   justify-items: flex-end unsafe;
-   align-items: flex-start safe;
+   justify-items: unsafe flex-end;
+   align-items: safe flex-start;
 }
 .parent .child {
    display: flex;
-   justify-self: flex-end unsafe;
-   align-self: flex-start safe;
+   justify-self: unsafe flex-end;
+   align-self: safe flex-start;
 }
 #parentId {
    justify-items: center;
@@ -35,8 +35,8 @@
 shouldBeEqualToString("getComputedStyle(parent, '').getPropertyValue('align-items')", "stretch");
 
 var childOfDefaultParent = document.getElementById("childOfDefaultParent");
-shouldBeEqualToString("getComputedStyle(childOfDefaultParent, '').getPropertyValue('justify-self')", "flex-end unsafe");
-shouldBeEqualToString("getComputedStyle(childOfDefaultParent, '').getPropertyValue('align-self')", "flex-start safe");
+shouldBeEqualToString("getComputedStyle(childOfDefaultParent, '').getPropertyValue('justify-self')", "unsafe flex-end");
+shouldBeEqualToString("getComputedStyle(childOfDefaultParent, '').getPropertyValue('align-self')", "safe flex-start");
 
 var childOfParentId = document.getElementById("childOfParentId");
 shouldBeEqualToString("getComputedStyle(childOfParentId, '').getPropertyValue('justify-self')", "center");
diff --git a/third_party/WebKit/LayoutTests/fast/alignment/parse-align-content.html b/third_party/WebKit/LayoutTests/fast/alignment/parse-align-content.html
index 98119e7..2f4b034 100644
--- a/third_party/WebKit/LayoutTests/fast/alignment/parse-align-content.html
+++ b/third_party/WebKit/LayoutTests/fast/alignment/parse-align-content.html
@@ -60,30 +60,31 @@
     align-content: flex-end;
 }
 
-#alignContentEndUnsafe {
-    align-content: end unsafe;
+#alignContentUnsafeEnd {
+    align-content: unsafe end ;
 }
 
-#alignContentCenterUnsafe {
-    align-content: center unsafe;
+#alignContentUnsafeCenter {
+    align-content: unsafe center ;
 }
 
-#alignContentRightSafe {
-    align-content: right safe;
+#alignContentSafeRight {
+    align-content: safe right;
 }
 
-#alignContentLeftUnsafe {
-    align-content: left unsafe;
+#alignContentUnsafeLeft {
+    align-content: unsafe left;
 }
 
-#alignContentFlexStartUnsafe {
-    align-content: flex-start unsafe;
+#alignContentUnsafeFlexStart {
+    align-content: unsafe flex-start;
 }
 
-#alignContentFlexEndSafe {
-    align-content: flex-end safe;
+#alignContentSafeFlexEnd {
+    align-content: safe flex-end;
 }
 
+<!-- Invalid CSS cases -->
 #alignContentSpaceBetweenLeft {
     align-content: space-between left;
 }
@@ -108,7 +109,6 @@
     align-content: space-evenly flex-start safe;
 }
 
-<!-- Invalid CSS cases -->
 #alignContentSpaceBetweenSafe {
     align-content: space-between safe;
 }
@@ -145,19 +145,27 @@
 <div id="alignContentRight"></div>
 <div id="alignContentFlexStart"></div>
 <div id="alignContentFlexEnd"></div>
+<div id="alignContentUnsafeEnd"></div>
+<div id="alignContentUnsafeCenter"></div>
+<div id="alignContentSafeSelfEnd"></div>
+<div id="alignContentSafeSelfStart"></div>
+<div id="alignContentSafeRight"></div>
+<div id="alignContentUnsafeLeft"></div>
+<div id="alignContentUnsafeFlexStart"></div>
+<div id="alignContentSafeFlexEnd"></div>
 <div id="alignContentEndUnsafe"></div>
 <div id="alignContentCenterUnsafe"></div>
 <div id="alignContentRightSafe"></div>
 <div id="alignContentLeftUnsafe"></div>
 <div id="alignContentFlexStartUnsafe"></div>
 <div id="alignContentFlexEndSafe"></div>
+
 <div id="alignContentSpaceBetweenLeft"></div>
 <div id="alignContentSpaceAroundCenter"></div>
 <div id="alignContentSpaceEvenlyRight"></div>
 <div id="alignContentStretchStartSafe"></div>
 <div id="alignContentSpaceAroundEndUnsafe"></div>
 <div id="alignContentSpaceEvenlyFlexStartSafe"></div>
-
 <div id="alignContentSpaceBetweenSafe"></div>
 <div id="alignContentSpaceBetweenStretch"></div>
 <div id="alignContentSafe"></div>
@@ -199,33 +207,45 @@
     checkValues(alignContentFlexStart, "alignContent", "align-content", "", "flex-start");
     var alignContentFlexEnd = document.getElementById("alignContentFlexEnd");
     checkValues(alignContentFlexEnd, "alignContent", "align-content", "", "flex-end");
-    var alignContentEndUnsafe = document.getElementById("alignContentEndUnsafe");
-    checkValues(alignContentEndUnsafe, "alignContent", "align-content", "", "end unsafe");
-    var alignContentCenterUnsafe = document.getElementById("alignContentCenterUnsafe");
-    checkValues(alignContentCenterUnsafe, "alignContent", "align-content", "", "center unsafe");
-    var alignContentRightSafe = document.getElementById("alignContentRightSafe");
-    checkValues(alignContentRightSafe, "alignContent", "align-content", "", "right safe");
-    var alignContentLeftUnsafe = document.getElementById("alignContentLeftUnsafe");
-    checkValues(alignContentLeftUnsafe, "alignContent", "align-content", "", "left unsafe");
-    var alignContentFlexStartUnsafe = document.getElementById("alignContentFlexStartUnsafe");
-    checkValues(alignContentFlexStartUnsafe, "alignContent", "align-content", "", "flex-start unsafe");
-    var alignContentFlexEndSafe = document.getElementById("alignContentFlexEndSafe");
-    checkValues(alignContentFlexEndSafe, "alignContent", "align-content", "", "flex-end safe");
-    var alignContentSpaceBetweenLeft = document.getElementById("alignContentSpaceBetweenLeft");
-    checkValues(alignContentSpaceBetweenLeft, "alignContent", "align-content", "", "space-between left");
-    var alignContentSpaceAroundCenter = document.getElementById("alignContentSpaceAroundCenter");
-    checkValues(alignContentSpaceAroundCenter, "alignContent", "align-content", "", "space-around center");
-    var alignContentSpaceEvenlyRight = document.getElementById("alignContentSpaceEvenlyRight");
-    checkValues(alignContentSpaceEvenlyRight, "alignContent", "align-content", "", "space-evenly right");
-    var alignContentStretchStartSafe = document.getElementById("alignContentStretchStartSafe");
-    checkValues(alignContentStretchStartSafe, "alignContent", "align-content", "", "stretch start safe");
-    var alignContentSpaceAroundEndUnsafe = document.getElementById("alignContentSpaceAroundEndUnsafe");
-    checkValues(alignContentSpaceAroundEndUnsafe, "alignContent", "align-content", "", "space-around end unsafe");
-    var alignContentSpaceEvenlyFlexStartSafe = document.getElementById("alignContentSpaceEvenlyFlexStartSafe");
-    checkValues(alignContentSpaceEvenlyFlexStartSafe, "alignContent", "align-content", "", "space-evenly flex-start safe");
+    var alignContentUnsafeEnd = document.getElementById("alignContentUnsafeEnd");
+    checkValues(alignContentUnsafeEnd, "alignContent", "align-content", "", "unsafe end");
+    var alignContentUnsafeCenter = document.getElementById("alignContentUnsafeCenter");
+    checkValues(alignContentUnsafeCenter, "alignContent", "align-content", "", "unsafe center");
+    var alignContentSafeRight = document.getElementById("alignContentSafeRight");
+    checkValues(alignContentSafeRight, "alignContent", "align-content", "", "safe right");
+    var alignContentUnsafeLeft = document.getElementById("alignContentUnsafeLeft");
+    checkValues(alignContentUnsafeLeft, "alignContent", "align-content", "", "unsafe left");
+    var alignContentUnsafeFlexStart = document.getElementById("alignContentUnsafeFlexStart");
+    checkValues(alignContentUnsafeFlexStart, "alignContent", "align-content", "", "unsafe flex-start");
+    var alignContentSafeFlexEnd = document.getElementById("alignContentSafeFlexEnd");
+    checkValues(alignContentSafeFlexEnd, "alignContent", "align-content", "", "safe flex-end");
 }, "Test getting align-content values previously set through CSS.");
 
 test(function() {
+    var alignContentEndUnsafe = document.getElementById("alignContentEndUnsafe");
+    checkValues(alignContentEndUnsafe, "alignContent", "align-content", "", "normal");
+    var alignContentCenterUnsafe = document.getElementById("alignContentCenterUnsafe");
+    checkValues(alignContentCenterUnsafe, "alignContent", "align-content", "", "normal");
+    var alignContentRightSafe = document.getElementById("alignContentRightSafe");
+    checkValues(alignContentRightSafe, "alignContent", "align-content", "", "normal");
+    var alignContentLeftUnsafe = document.getElementById("alignContentLeftUnsafe");
+    checkValues(alignContentLeftUnsafe, "alignContent", "align-content", "", "normal");
+    var alignContentFlexStartUnsafe = document.getElementById("alignContentFlexStartUnsafe");
+    checkValues(alignContentFlexStartUnsafe, "alignContent", "align-content", "", "normal");
+    var alignContentFlexEndSafe = document.getElementById("alignContentFlexEndSafe");
+    checkValues(alignContentFlexEndSafe, "alignContent", "align-content", "", "normal");
+    var alignContentSpaceBetweenLeft = document.getElementById("alignContentSpaceBetweenLeft");
+    checkValues(alignContentSpaceBetweenLeft, "alignContent", "align-content", "", "normal");
+    var alignContentSpaceAroundCenter = document.getElementById("alignContentSpaceAroundCenter");
+    checkValues(alignContentSpaceAroundCenter, "alignContent", "align-content", "", "normal");
+    var alignContentSpaceEvenlyRight = document.getElementById("alignContentSpaceEvenlyRight");
+    checkValues(alignContentSpaceEvenlyRight, "alignContent", "align-content", "", "normal");
+    var alignContentStretchStartSafe = document.getElementById("alignContentStretchStartSafe");
+    checkValues(alignContentStretchStartSafe, "alignContent", "align-content", "", "normal");
+    var alignContentSpaceAroundEndUnsafe = document.getElementById("alignContentSpaceAroundEndUnsafe");
+    checkValues(alignContentSpaceAroundEndUnsafe, "alignContent", "align-content", "", "normal");
+    var alignContentSpaceEvenlyFlexStartSafe = document.getElementById("alignContentSpaceEvenlyFlexStartSafe");
+    checkValues(alignContentSpaceEvenlyFlexStartSafe, "alignContent", "align-content", "", "normal");
     var alignContentSpaceBetweenSafe = document.getElementById("alignContentSpaceBetweenSafe");
     checkValues(alignContentSpaceBetweenSafe, "alignContent", "align-content", "", "normal");
     var alignContentSpaceBetweenStretch = document.getElementById("alignContentSpaceBetweenStretch");
@@ -251,19 +271,13 @@
     checkValues(element, "alignContent", "align-content",  "center", "center");
 
     element.style.alignContent = "unsafe start";
-    checkValues(element, "alignContent", "align-content",  "start unsafe", "start unsafe");
+    checkValues(element, "alignContent", "align-content",  "unsafe start", "unsafe start");
 
-    element.style.alignContent = "flex-end safe";
-    checkValues(element, "alignContent", "align-content",  "flex-end safe", "flex-end safe");
+    element.style.alignContent = "safe flex-end";
+    checkValues(element, "alignContent", "align-content",  "safe flex-end", "safe flex-end");
 
-    element.style.alignContent = "space-between right safe";
-    checkValues(element, "alignContent", "align-content",  "space-between right safe", "space-between right safe");
-
-    element.style.alignContent = "stretch center";
-    checkValues(element, "alignContent", "align-content",  "stretch center", "stretch center");
-
-    element.style.alignContent = "right unsafe";
-    checkValues(element, "alignContent", "align-content",  "right unsafe", "right unsafe");
+    element.style.alignContent = " unsafe right";
+    checkValues(element, "alignContent", "align-content",  "unsafe right", "unsafe right");
 
     element.style.justifyContent = "first baseline";
     checkValues(element, "justifyContent", "justify-content",  "first baseline", "baseline");
@@ -309,12 +323,16 @@
     checkBadValues(element, "alignContent", "align-content",  "safe stretch");
     checkBadValues(element, "alignContent", "align-content",  "normal space-between");
     checkBadValues(element, "alignContent", "align-content",  "stretch normal");
+    checkBadValues(element, "alignContent", "align-content",  "stretch center");
+    checkBadValues(element, "alignContent", "align-content",  "space-between right safe");
     checkBadValues(element, "alignContent", "align-content",  "normal safe");
     checkBadValues(element, "alignContent", "align-content",  "space-around stretch");
     checkBadValues(element, "alignContent", "align-content",  "end space-between start");
     checkBadValues(element, "alignContent", "align-content",  "right safe left");
     checkBadValues(element, "alignContent", "align-content",  "unsafe");
     checkBadValues(element, "alignContent", "align-content",  "safe");
+    checkBadValues(element, "alignContent", "align-content",  "start safe");
+    checkBadValues(element, "alignContent", "align-content",  "end unsafe");
 }, "Test bad combinations of align-content");
 
 test(function() {
@@ -324,17 +342,17 @@
 
 test(function() {
     element.style.display = "grid";
-    checkInitialValues(element, "alignContent", "align-content", "left safe", "normal");
+    checkInitialValues(element, "alignContent", "align-content", "safe left", "normal");
 }, "Test the value 'initial' for grid containers");
 
 test(function() {
     element.style.display = "flex";
-    checkInitialValues(element, "alignContent", "align-content", "right unsafe", "normal");
+    checkInitialValues(element, "alignContent", "align-content", "unsafe right", "normal");
 }, "Test the value 'initial' for flex containers");
 
 test(function() {
     checkInheritValues("alignContent", "align-content", "end");
-    checkInheritValues("alignContent", "align-content", "left safe");
-    checkInheritValues("alignContent", "align-content", "center unsafe");
+    checkInheritValues("alignContent", "align-content", "safe left");
+    checkInheritValues("alignContent", "align-content", "unsafe center");
 }, "Test the value 'inherit'");
 </script>
diff --git a/third_party/WebKit/LayoutTests/fast/alignment/parse-align-items.html b/third_party/WebKit/LayoutTests/fast/alignment/parse-align-items.html
index 5b9d9e3..b21eb23 100644
--- a/third_party/WebKit/LayoutTests/fast/alignment/parse-align-items.html
+++ b/third_party/WebKit/LayoutTests/fast/alignment/parse-align-items.html
@@ -16,6 +16,10 @@
     align-items: stretch;
 }
 
+#alignItemsNormal {
+    align-items: normal;
+}
+
 #alignItemsStart {
     align-items: start;
 }
@@ -52,36 +56,36 @@
     align-items: flex-end;
 }
 
-#alignItemsEndUnsafe {
-    align-items: end unsafe;
+#alignItemsUnsafeEnd {
+    align-items: unsafe end ;
 }
 
-#alignItemsCenterUnsafe {
-    align-items: center unsafe;
+#alignItemsUnsafeCenter {
+    align-items: unsafe center ;
 }
 
-#alignItemsSelfEndSafe {
-    align-items: self-end safe;
+#alignItemsSafeSelfEnd {
+    align-items: safe self-end;
 }
 
-#alignItemsSelfStartSafe {
-    align-items: self-start safe;
+#alignItemsSafeSelfStart {
+    align-items: safe self-start;
 }
 
-#alignItemsRightSafe {
-    align-items: right safe;
+#alignItemsSafeRight {
+    align-items: safe right;
 }
 
-#alignItemsLeftUnsafe {
-    align-items: left unsafe;
+#alignItemsUnsafeLeft {
+    align-items: unsafe left;
 }
 
-#alignItemsFlexStartUnsafe {
-    align-items: flex-start unsafe;
+#alignItemsUnsafeFlexStart {
+    align-items: unsafe flex-start;
 }
 
-#alignItemsFlexEndSafe {
-    align-items: flex-end safe;
+#alignItemsSafeFlexEnd {
+    align-items: safe flex-end;
 }
 </style>
 <p>Test that setting and getting align-items works as expected</p>
@@ -89,6 +93,7 @@
 <div id="alignItemsFirstBaseline"></div>
 <div id="alignItemsLastBaseline"></div>
 <div id="alignItemsStretch"></div>
+<div id="alignItemsNormal"></div>
 <div id="alignItemsStart"></div>
 <div id="alignItemsEnd"></div>
 <div id="alignItemsCenter"></div>
@@ -99,14 +104,14 @@
 <div id="alignItemsFlexStart"></div>
 <div id="alignItemsFlexEnd"></div>
 
-<div id="alignItemsEndUnsafe"></div>
-<div id="alignItemsCenterUnsafe"></div>
-<div id="alignItemsSelfEndSafe"></div>
-<div id="alignItemsSelfStartSafe"></div>
-<div id="alignItemsRightSafe"></div>
-<div id="alignItemsLeftUnsafe"></div>
-<div id="alignItemsFlexStartUnsafe"></div>
-<div id="alignItemsFlexEndSafe"></div>
+<div id="alignItemsUnsafeEnd"></div>
+<div id="alignItemsUnsafeCenter"></div>
+<div id="alignItemsSafeSelfEnd"></div>
+<div id="alignItemsSafeSelfStart"></div>
+<div id="alignItemsSafeRight"></div>
+<div id="alignItemsUnsafeLeft"></div>
+<div id="alignItemsUnsafeFlexStart"></div>
+<div id="alignItemsSafeFlexEnd"></div>
 <script src="../../resources/testharness.js"></script>
 <script src="../../resources/testharnessreport.js"></script>
 <script src="resources/alignment-parsing-utils-th.js"></script>
@@ -120,6 +125,8 @@
     checkValues(alignItemsLastBaseline, "alignItems", "align-items", "", "last baseline");
     var alignItemsStretch = document.getElementById("alignItemsStretch");
     checkValues(alignItemsStretch, "alignItems", "align-items", "", "stretch");
+    var alignItemsNormal = document.getElementById("alignItemsNormal");
+    checkValues(alignItemsNormal, "alignItems", "align-items", "", "normal");
     var alignItemsStart = document.getElementById("alignItemsStart");
     checkValues(alignItemsStart, "alignItems", "align-items", "", "start");
     var alignItemsEnd = document.getElementById("alignItemsEnd");
@@ -139,22 +146,22 @@
     var alignItemsFlexEnd = document.getElementById("alignItemsFlexEnd");
     checkValues(alignItemsFlexEnd, "alignItems", "align-items", "", "flex-end");
 
-    var alignItemsEndUnsafe = document.getElementById("alignItemsEndUnsafe");
-    checkValues(alignItemsEndUnsafe, "alignItems", "align-items", "", "end unsafe");
-    var alignItemsCenterUnsafe = document.getElementById("alignItemsCenterUnsafe");
-    checkValues(alignItemsCenterUnsafe, "alignItems", "align-items", "", "center unsafe");
-    var alignItemsSelfEndSafe = document.getElementById("alignItemsSelfEndSafe");
-    checkValues(alignItemsSelfEndSafe, "alignItems", "align-items", "", "self-end safe");
-    var alignItemsSelfStartSafe = document.getElementById("alignItemsSelfStartSafe");
-    checkValues(alignItemsSelfStartSafe, "alignItems", "align-items", "", "self-start safe");
-    var alignItemsRightSafe = document.getElementById("alignItemsRightSafe");
-    checkValues(alignItemsRightSafe, "alignItems", "align-items", "", "right safe");
-    var alignItemsLeftUnsafe = document.getElementById("alignItemsLeftUnsafe");
-    checkValues(alignItemsLeftUnsafe, "alignItems", "align-items", "", "left unsafe");
-    var alignItemsFlexStartUnsafe = document.getElementById("alignItemsFlexStartUnsafe");
-    checkValues(alignItemsFlexStartUnsafe, "alignItems", "align-items", "", "flex-start unsafe");
-    var alignItemsFlexEndSafe = document.getElementById("alignItemsFlexEndSafe");
-    checkValues(alignItemsFlexEndSafe, "alignItems", "align-items", "", "flex-end safe");
+    var alignItemsUnsafeEnd = document.getElementById("alignItemsUnsafeEnd");
+    checkValues(alignItemsUnsafeEnd, "alignItems", "align-items", "", "unsafe end");
+    var alignItemsUnsafeCenter = document.getElementById("alignItemsUnsafeCenter");
+    checkValues(alignItemsUnsafeCenter, "alignItems", "align-items", "", "unsafe center");
+    var alignItemsSafeSelfEnd = document.getElementById("alignItemsSafeSelfEnd");
+    checkValues(alignItemsSafeSelfEnd, "alignItems", "align-items", "", "safe self-end");
+    var alignItemsSafeSelfStart = document.getElementById("alignItemsSafeSelfStart");
+    checkValues(alignItemsSafeSelfStart, "alignItems", "align-items", "", "safe self-start");
+    var alignItemsSafeRight = document.getElementById("alignItemsSafeRight");
+    checkValues(alignItemsSafeRight, "alignItems", "align-items", "", "safe right");
+    var alignItemsUnsafeLeft = document.getElementById("alignItemsUnsafeLeft");
+    checkValues(alignItemsUnsafeLeft, "alignItems", "align-items", "", "unsafe left");
+    var alignItemsUnsafeFlexStart = document.getElementById("alignItemsUnsafeFlexStart");
+    checkValues(alignItemsUnsafeFlexStart, "alignItems", "align-items", "", "unsafe flex-start");
+    var alignItemsSafeFlexEnd = document.getElementById("alignItemsSafeFlexEnd");
+    checkValues(alignItemsSafeFlexEnd, "alignItems", "align-items", "", "safe flex-end");
 }, "Test getting align-items set through CSS.");
 
 test(function() {
@@ -170,10 +177,10 @@
     checkValues(element, "alignItems", "align-items",  "center", "center");
 
     element.style.alignItems = "unsafe start";
-    checkValues(element, "alignItems", "align-items",  "start unsafe", "start unsafe");
+    checkValues(element, "alignItems", "align-items",  "unsafe start", "unsafe start");
 
-    element.style.alignItems = "flex-end safe";
-    checkValues(element, "alignItems", "align-items",  "flex-end safe", "flex-end safe");
+    element.style.alignItems = "safe flex-end";
+    checkValues(element, "alignItems", "align-items",  "safe flex-end", "safe flex-end");
 
     element.style.alignItems = "right";
     checkValues(element, "alignItems", "align-items",  "right", "right");
@@ -184,6 +191,9 @@
     element.style.alignItems = "self-start";
     checkValues(element, "alignItems", "align-items",  "self-start", "self-start");
 
+    element.style.alignItems = "normal";
+    checkValues(element, "alignItems", "align-items",  "normal", "normal");
+
     // The 'auto' value is not valid for the align-items property.
     element.style.alignItems = "";
     element.style.alignItems = "auto";
@@ -209,6 +219,9 @@
     checkBadValues(element, "alignItems", "align-items",  "unsafe auto");
     checkBadValues(element, "alignItems", "align-items",  "auto safe");
     checkBadValues(element, "alignItems", "align-items",  "auto left");
+    checkBadValues(element, "alignItems", "align-items",  "normal unsafe");
+    checkBadValues(element, "alignItems", "align-items",  "normal stretch");
+    checkBadValues(element, "alignItems", "align-items",  "baseline normal");
     checkBadValues(element, "alignItems", "align-items",  "baseline safe");
     checkBadValues(element, "alignItems", "align-items",  "baseline center");
     checkBadValues(element, "alignItems", "align-items",  "first baseline center");
@@ -234,6 +247,8 @@
     checkBadValues(element, "alignItems", "align-items",  "legacy stretch");
     checkBadValues(element, "alignItems", "align-items",  "legacy");
     checkBadValues(element, "alignItems", "align-items",  "legacy left right");
+    checkBadValues(element, "alignItems", "align-items",  "start safe");
+    checkBadValues(element, "alignItems", "align-items",  "end unsafe");
 }, "Test bad combinations of align-items");
 
 test(function() {
@@ -243,17 +258,17 @@
 
 test(function() {
     element.style.display = "grid";
-    checkInitialValues(element, "alignItems", "align-items", "left safe", "normal");
+    checkInitialValues(element, "alignItems", "align-items", "safe left", "normal");
 }, "Test the value 'initial' for grid containers");
 
 test(function() {
     element.style.display = "flex";
-    checkInitialValues(element, "alignItems", "align-items", "right unsafe", "normal");
+    checkInitialValues(element, "alignItems", "align-items", "unsafe right", "normal");
 }, "Test the value 'initial' for flex containers");
 
 test(function() {
     checkInheritValues("alignItems", "align-items", "end");
-    checkInheritValues("alignItems", "align-items", "left safe");
-    checkInheritValues("alignItems", "align-items", "center unsafe");
+    checkInheritValues("alignItems", "align-items", "safe left");
+    checkInheritValues("alignItems", "align-items", "unsafe center");
 }, "Test the value 'inherit'");
 </script>
diff --git a/third_party/WebKit/LayoutTests/fast/alignment/parse-align-self.html b/third_party/WebKit/LayoutTests/fast/alignment/parse-align-self.html
index 8e81f78..57da38abe 100644
--- a/third_party/WebKit/LayoutTests/fast/alignment/parse-align-self.html
+++ b/third_party/WebKit/LayoutTests/fast/alignment/parse-align-self.html
@@ -56,36 +56,36 @@
     align-self: flex-end;
 }
 
-#alignSelfEndUnsafe {
-    align-self: end unsafe;
+#alignSelfUnsafeEnd {
+    align-self: unsafe end ;
 }
 
-#alignSelfCenterUnsafe {
-    align-self: center unsafe;
+#alignSelfUnsafeCenter {
+    align-self: unsafe center ;
 }
 
-#alignSelfSelfEndSafe {
-    align-self: self-end safe;
+#alignSelfSafeSelfEnd {
+    align-self: safe self-end;
 }
 
-#alignSelfSelfStartSafe {
-    align-self: self-start safe;
+#alignSelfSafeSelfStart {
+    align-self: safe self-start;
 }
 
-#alignSelfRightSafe {
-    align-self: right safe;
+#alignSelfSafeRight {
+    align-self: safe right;
 }
 
-#alignSelfLeftUnsafe {
-    align-self: left unsafe;
+#alignSelfUnsafeLeft {
+    align-self: unsafe left;
 }
 
-#alignSelfFlexStartUnsafe {
-    align-self: flex-start unsafe;
+#alignSelfUnsafeFlexStart {
+    align-self: unsafe flex-start;
 }
 
-#alignSelfFlexEndSafe {
-    align-self: flex-end safe;
+#alignSelfSafeFlexEnd {
+    align-self: safe flex-end;
 }
 </style>
 <p>Test that setting and getting align-self works as expected</p>
@@ -104,14 +104,14 @@
 <div id="alignSelfFlexStart"></div>
 <div id="alignSelfFlexEnd"></div>
 
-<div id="alignSelfEndUnsafe"></div>
-<div id="alignSelfCenterUnsafe"></div>
-<div id="alignSelfSelfEndSafe"></div>
-<div id="alignSelfSelfStartSafe"></div>
-<div id="alignSelfRightSafe"></div>
-<div id="alignSelfLeftUnsafe"></div>
-<div id="alignSelfFlexStartUnsafe"></div>
-<div id="alignSelfFlexEndSafe"></div>
+<div id="alignSelfUnsafeEnd"></div>
+<div id="alignSelfUnsafeCenter"></div>
+<div id="alignSelfSafeSelfEnd"></div>
+<div id="alignSelfSafeSelfStart"></div>
+<div id="alignSelfSafeRight"></div>
+<div id="alignSelfUnsafeLeft"></div>
+<div id="alignSelfUnsafeFlexStart"></div>
+<div id="alignSelfSafeFlexEnd"></div>
 <script src="../../resources/testharness.js"></script>
 <script src="../../resources/testharnessreport.js"></script>
 <script src="resources/alignment-parsing-utils-th.js"></script>
@@ -146,22 +146,22 @@
     var alignSelfFlexEnd = document.getElementById("alignSelfFlexEnd");
     checkValues(alignSelfFlexEnd, "alignSelf", "align-self", "", "flex-end");
 
-    var alignSelfEndUnsafe = document.getElementById("alignSelfEndUnsafe");
-    checkValues(alignSelfEndUnsafe, "alignSelf", "align-self", "", "end unsafe");
-    var alignSelfCenterUnsafe = document.getElementById("alignSelfCenterUnsafe");
-    checkValues(alignSelfCenterUnsafe, "alignSelf", "align-self", "", "center unsafe");
-    var alignSelfSelfEndSafe = document.getElementById("alignSelfSelfEndSafe");
-    checkValues(alignSelfSelfEndSafe, "alignSelf", "align-self", "", "self-end safe");
-    var alignSelfSelfStartSafe = document.getElementById("alignSelfSelfStartSafe");
-    checkValues(alignSelfSelfStartSafe, "alignSelf", "align-self", "", "self-start safe");
-    var alignSelfRightSafe = document.getElementById("alignSelfRightSafe");
-    checkValues(alignSelfRightSafe, "alignSelf", "align-self", "", "right safe");
-    var alignSelfLeftUnsafe = document.getElementById("alignSelfLeftUnsafe");
-    checkValues(alignSelfLeftUnsafe, "alignSelf", "align-self", "", "left unsafe");
-    var alignSelfFlexStartUnsafe = document.getElementById("alignSelfFlexStartUnsafe");
-    checkValues(alignSelfFlexStartUnsafe, "alignSelf", "align-self", "", "flex-start unsafe");
-    var alignSelfFlexEndSafe = document.getElementById("alignSelfFlexEndSafe");
-    checkValues(alignSelfFlexEndSafe, "alignSelf", "align-self", "", "flex-end safe");
+    var alignSelfUnsafeEnd = document.getElementById("alignSelfUnsafeEnd");
+    checkValues(alignSelfUnsafeEnd, "alignSelf", "align-self", "", "unsafe end");
+    var alignSelfUnsafeCenter = document.getElementById("alignSelfUnsafeCenter");
+    checkValues(alignSelfUnsafeCenter, "alignSelf", "align-self", "", "unsafe center");
+    var alignSelfSafeSelfEnd = document.getElementById("alignSelfSafeSelfEnd");
+    checkValues(alignSelfSafeSelfEnd, "alignSelf", "align-self", "", "safe self-end");
+    var alignSelfSafeSelfStart = document.getElementById("alignSelfSafeSelfStart");
+    checkValues(alignSelfSafeSelfStart, "alignSelf", "align-self", "", "safe self-start");
+    var alignSelfSafeRight = document.getElementById("alignSelfSafeRight");
+    checkValues(alignSelfSafeRight, "alignSelf", "align-self", "", "safe right");
+    var alignSelfUnsafeLeft = document.getElementById("alignSelfUnsafeLeft");
+    checkValues(alignSelfUnsafeLeft, "alignSelf", "align-self", "", "unsafe left");
+    var alignSelfUnsafeFlexStart = document.getElementById("alignSelfUnsafeFlexStart");
+    checkValues(alignSelfUnsafeFlexStart, "alignSelf", "align-self", "", "unsafe flex-start");
+    var alignSelfSafeFlexEnd = document.getElementById("alignSelfSafeFlexEnd");
+    checkValues(alignSelfSafeFlexEnd, "alignSelf", "align-self", "", "safe flex-end");
 }, "Test getting align-self set through CSS.");
 
 test(function() {
@@ -179,10 +179,10 @@
     checkValues(element, "alignSelf", "align-self",  "center", "center");
 
     element.style.alignSelf = "unsafe start";
-    checkValues(element, "alignSelf", "align-self",  "start unsafe", "start unsafe");
+    checkValues(element, "alignSelf", "align-self",  "unsafe start", "unsafe start");
 
-    element.style.alignSelf = "flex-end safe";
-    checkValues(element, "alignSelf", "align-self",  "flex-end safe", "flex-end safe");
+    element.style.alignSelf = "safe flex-end";
+    checkValues(element, "alignSelf", "align-self",  "safe flex-end", "safe flex-end");
 
     element.style.alignSelf = "right";
     checkValues(element, "alignSelf", "align-self",  "right", "right");
@@ -229,6 +229,10 @@
     checkBadValues(element, "alignSelf", "align-self",  "baseline normal");
     checkBadValues(element, "alignSelf", "align-self",  "baseline safe");
     checkBadValues(element, "alignSelf", "align-self",  "baseline center");
+    checkBadValues(element, "alignSelf", "align-self",  "first baseline center");
+    checkBadValues(element, "alignSelf", "align-self",  "last baseline center");
+    checkBadValues(element, "alignSelf", "align-self",  "baseline last");
+    checkBadValues(element, "alignSelf", "align-self",  "baseline first");
     checkBadValues(element, "alignSelf", "align-self",  "stretch unsafe");
     checkBadValues(element, "alignSelf", "align-self",  "stretch right");
     checkBadValues(element, "alignSelf", "align-self",  "unsafe unsafe");
@@ -248,6 +252,8 @@
     checkBadValues(element, "alignSelf", "align-self",  "legacy stretch");
     checkBadValues(element, "alignSelf", "align-self",  "legacy");
     checkBadValues(element, "alignSelf", "align-self",  "legacy left right");
+    checkBadValues(element, "alignSelf", "align-self",  "start safe");
+    checkBadValues(element, "alignSelf", "align-self",  "end unsafe");
 }, "Test bad combinations of align-self");
 
 test(function() {
@@ -257,12 +263,12 @@
 
 test(function() {
     container.style.display = "grid";
-    checkInitialValues(element, "alignSelf", "align-self", "left safe", "auto");
+    checkInitialValues(element, "alignSelf", "align-self", "safe left", "auto");
 }, "Test the value 'initial' for grid containers");
 
 test(function() {
     container.style.display = "flex";
-    checkInitialValues(element, "alignSelf", "align-self", "right unsafe", "auto");
+    checkInitialValues(element, "alignSelf", "align-self", "unsafe right", "auto");
 }, "Test the value 'initial' for flex containers");
 
 test(function() {
@@ -285,7 +291,7 @@
 
 test(function() {
     checkInheritValues("alignSelf", "align-self", "end");
-    checkInheritValues("alignSelf", "align-self", "left safe");
-    checkInheritValues("alignSelf", "align-self", "center unsafe");
+    checkInheritValues("alignSelf", "align-self", "safe left");
+    checkInheritValues("alignSelf", "align-self", "unsafe center");
 }, "Test the value 'inherit'");
 </script>
diff --git a/third_party/WebKit/LayoutTests/fast/alignment/parse-justify-content.html b/third_party/WebKit/LayoutTests/fast/alignment/parse-justify-content.html
index cc58d11..f4b78ddd 100644
--- a/third_party/WebKit/LayoutTests/fast/alignment/parse-justify-content.html
+++ b/third_party/WebKit/LayoutTests/fast/alignment/parse-justify-content.html
@@ -60,30 +60,31 @@
     justify-content: flex-end;
 }
 
-#justifyContentEndUnsafe {
-    justify-content: end unsafe;
+#justifyContentUnsafeEnd {
+    justify-content: unsafe end ;
 }
 
-#justifyContentCenterUnsafe {
-    justify-content: center unsafe;
+#justifyContentUnsafeCenter {
+    justify-content: unsafe center ;
 }
 
-#justifyContentRightSafe {
-    justify-content: right safe;
+#justifyContentSafeRight {
+    justify-content: safe right;
 }
 
-#justifyContentLeftUnsafe {
-    justify-content: left unsafe;
+#justifyContentUnsafeLeft {
+    justify-content: unsafe left;
 }
 
-#justifyContentFlexStartUnsafe {
-    justify-content: flex-start unsafe;
+#justifyContentUnsafeFlexStart {
+    justify-content: unsafe flex-start;
 }
 
-#justifyContentFlexEndSafe {
-    justify-content: flex-end safe;
+#justifyContentSafeFlexEnd {
+    justify-content: safe flex-end;
 }
 
+<!-- Invalid CSS cases -->
 #justifyContentSpaceBetweenLeft {
     justify-content: space-between left;
 }
@@ -108,7 +109,6 @@
     justify-content: space-evenly flex-start safe;
 }
 
-<!-- Invalid CSS cases -->
 #justifyContentSpaceBetweenSafe {
     justify-content: space-between safe;
 }
@@ -145,19 +145,27 @@
 <div id="justifyContentRight"></div>
 <div id="justifyContentFlexStart"></div>
 <div id="justifyContentFlexEnd"></div>
+<div id="justifyContentUnsafeEnd"></div>
+<div id="justifyContentUnsafeCenter"></div>
+<div id="justifyContentSafeSelfEnd"></div>
+<div id="justifyContentSafeSelfStart"></div>
+<div id="justifyContentSafeRight"></div>
+<div id="justifyContentUnsafeLeft"></div>
+<div id="justifyContentUnsafeFlexStart"></div>
+<div id="justifyContentSafeFlexEnd"></div>
 <div id="justifyContentEndUnsafe"></div>
 <div id="justifyContentCenterUnsafe"></div>
 <div id="justifyContentRightSafe"></div>
 <div id="justifyContentLeftUnsafe"></div>
 <div id="justifyContentFlexStartUnsafe"></div>
 <div id="justifyContentFlexEndSafe"></div>
+
 <div id="justifyContentSpaceBetweenLeft"></div>
 <div id="justifyContentSpaceAroundCenter"></div>
 <div id="justifyContentSpaceEvenlyRight"></div>
 <div id="justifyContentStretchStartSafe"></div>
 <div id="justifyContentSpaceAroundEndUnsafe"></div>
 <div id="justifyContentSpaceEvenlyFlexStartSafe"></div>
-
 <div id="justifyContentSpaceBetweenSafe"></div>
 <div id="justifyContentSpaceBetweenStretch"></div>
 <div id="justifyContentSafe"></div>
@@ -199,33 +207,45 @@
     checkValues(justifyContentFlexStart, "justifyContent", "justify-content", "", "flex-start");
     var justifyContentFlexEnd = document.getElementById("justifyContentFlexEnd");
     checkValues(justifyContentFlexEnd, "justifyContent", "justify-content", "", "flex-end");
-    var justifyContentEndUnsafe = document.getElementById("justifyContentEndUnsafe");
-    checkValues(justifyContentEndUnsafe, "justifyContent", "justify-content", "", "end unsafe");
-    var justifyContentCenterUnsafe = document.getElementById("justifyContentCenterUnsafe");
-    checkValues(justifyContentCenterUnsafe, "justifyContent", "justify-content", "", "center unsafe");
-    var justifyContentRightSafe = document.getElementById("justifyContentRightSafe");
-    checkValues(justifyContentRightSafe, "justifyContent", "justify-content", "", "right safe");
-    var justifyContentLeftUnsafe = document.getElementById("justifyContentLeftUnsafe");
-    checkValues(justifyContentLeftUnsafe, "justifyContent", "justify-content", "", "left unsafe");
-    var justifyContentFlexStartUnsafe = document.getElementById("justifyContentFlexStartUnsafe");
-    checkValues(justifyContentFlexStartUnsafe, "justifyContent", "justify-content", "", "flex-start unsafe");
-    var justifyContentFlexEndSafe = document.getElementById("justifyContentFlexEndSafe");
-    checkValues(justifyContentFlexEndSafe, "justifyContent", "justify-content", "", "flex-end safe");
-    var justifyContentSpaceBetweenLeft = document.getElementById("justifyContentSpaceBetweenLeft");
-    checkValues(justifyContentSpaceBetweenLeft, "justifyContent", "justify-content", "", "space-between left");
-    var justifyContentSpaceAroundCenter = document.getElementById("justifyContentSpaceAroundCenter");
-    checkValues(justifyContentSpaceAroundCenter, "justifyContent", "justify-content", "", "space-around center");
-    var justifyContentSpaceEvenlyRight = document.getElementById("justifyContentSpaceEvenlyRight");
-    checkValues(justifyContentSpaceEvenlyRight, "justifyContent", "justify-content", "", "space-evenly right");
-    var justifyContentStretchStartSafe = document.getElementById("justifyContentStretchStartSafe");
-    checkValues(justifyContentStretchStartSafe, "justifyContent", "justify-content", "", "stretch start safe");
-    var justifyContentSpaceAroundEndUnsafe = document.getElementById("justifyContentSpaceAroundEndUnsafe");
-    checkValues(justifyContentSpaceAroundEndUnsafe, "justifyContent", "justify-content", "", "space-around end unsafe");
-    var justifyContentSpaceEvenlyFlexStartSafe = document.getElementById("justifyContentSpaceEvenlyFlexStartSafe");
-    checkValues(justifyContentSpaceEvenlyFlexStartSafe, "justifyContent", "justify-content", "", "space-evenly flex-start safe");
+    var justifyContentUnsafeEnd = document.getElementById("justifyContentUnsafeEnd");
+    checkValues(justifyContentUnsafeEnd, "justifyContent", "justify-content", "", "unsafe end");
+    var justifyContentUnsafeCenter = document.getElementById("justifyContentUnsafeCenter");
+    checkValues(justifyContentUnsafeCenter, "justifyContent", "justify-content", "", "unsafe center");
+    var justifyContentSafeRight = document.getElementById("justifyContentSafeRight");
+    checkValues(justifyContentSafeRight, "justifyContent", "justify-content", "", "safe right");
+    var justifyContentUnsafeLeft = document.getElementById("justifyContentUnsafeLeft");
+    checkValues(justifyContentUnsafeLeft, "justifyContent", "justify-content", "", "unsafe left");
+    var justifyContentUnsafeFlexStart = document.getElementById("justifyContentUnsafeFlexStart");
+    checkValues(justifyContentUnsafeFlexStart, "justifyContent", "justify-content", "", "unsafe flex-start");
+    var justifyContentSafeFlexEnd = document.getElementById("justifyContentSafeFlexEnd");
+    checkValues(justifyContentSafeFlexEnd, "justifyContent", "justify-content", "", "safe flex-end");
 }, "Test getting justify-content values previously set through CSS.");
 
 test(function() {
+    var justifyContentEndUnsafe = document.getElementById("justifyContentEndUnsafe");
+    checkValues(justifyContentEndUnsafe, "justifyContent", "justify-content", "", "normal");
+    var justifyContentCenterUnsafe = document.getElementById("justifyContentCenterUnsafe");
+    checkValues(justifyContentCenterUnsafe, "justifyContent", "justify-content", "", "normal");
+    var justifyContentRightSafe = document.getElementById("justifyContentRightSafe");
+    checkValues(justifyContentRightSafe, "justifyContent", "justify-content", "", "normal");
+    var justifyContentLeftUnsafe = document.getElementById("justifyContentLeftUnsafe");
+    checkValues(justifyContentLeftUnsafe, "justifyContent", "justify-content", "", "normal");
+    var justifyContentFlexStartUnsafe = document.getElementById("justifyContentFlexStartUnsafe");
+    checkValues(justifyContentFlexStartUnsafe, "justifyContent", "justify-content", "", "normal");
+    var justifyContentFlexEndSafe = document.getElementById("justifyContentFlexEndSafe");
+    checkValues(justifyContentFlexEndSafe, "justifyContent", "justify-content", "", "normal");
+    var justifyContentSpaceBetweenLeft = document.getElementById("justifyContentSpaceBetweenLeft");
+    checkValues(justifyContentSpaceBetweenLeft, "justifyContent", "justify-content", "", "normal");
+    var justifyContentSpaceAroundCenter = document.getElementById("justifyContentSpaceAroundCenter");
+    checkValues(justifyContentSpaceAroundCenter, "justifyContent", "justify-content", "", "normal");
+    var justifyContentSpaceEvenlyRight = document.getElementById("justifyContentSpaceEvenlyRight");
+    checkValues(justifyContentSpaceEvenlyRight, "justifyContent", "justify-content", "", "normal");
+    var justifyContentStretchStartSafe = document.getElementById("justifyContentStretchStartSafe");
+    checkValues(justifyContentStretchStartSafe, "justifyContent", "justify-content", "", "normal");
+    var justifyContentSpaceAroundEndUnsafe = document.getElementById("justifyContentSpaceAroundEndUnsafe");
+    checkValues(justifyContentSpaceAroundEndUnsafe, "justifyContent", "justify-content", "", "normal");
+    var justifyContentSpaceEvenlyFlexStartSafe = document.getElementById("justifyContentSpaceEvenlyFlexStartSafe");
+    checkValues(justifyContentSpaceEvenlyFlexStartSafe, "justifyContent", "justify-content", "", "normal");
     var justifyContentSpaceBetweenSafe = document.getElementById("justifyContentSpaceBetweenSafe");
     checkValues(justifyContentSpaceBetweenSafe, "justifyContent", "justify-content", "", "normal");
     var justifyContentSpaceBetweenStretch = document.getElementById("justifyContentSpaceBetweenStretch");
@@ -251,19 +271,13 @@
     checkValues(element, "justifyContent", "justify-content",  "center", "center");
 
     element.style.justifyContent = "unsafe start";
-    checkValues(element, "justifyContent", "justify-content",  "start unsafe", "start unsafe");
+    checkValues(element, "justifyContent", "justify-content",  "unsafe start", "unsafe start");
 
-    element.style.justifyContent = "flex-end safe";
-    checkValues(element, "justifyContent", "justify-content",  "flex-end safe", "flex-end safe");
+    element.style.justifyContent = "safe flex-end";
+    checkValues(element, "justifyContent", "justify-content",  "safe flex-end", "safe flex-end");
 
-    element.style.justifyContent = "space-between right safe";
-    checkValues(element, "justifyContent", "justify-content",  "space-between right safe", "space-between right safe");
-
-    element.style.justifyContent = "center stretch";
-    checkValues(element, "justifyContent", "justify-content",  "stretch center", "stretch center");
-
-    element.style.justifyContent = "right unsafe";
-    checkValues(element, "justifyContent", "justify-content",  "right unsafe", "right unsafe");
+    element.style.justifyContent = " unsafe right";
+    checkValues(element, "justifyContent", "justify-content",  "unsafe right", "unsafe right");
 
     element.style.justifyContent = "first baseline";
     checkValues(element, "justifyContent", "justify-content",  "first baseline", "baseline");
@@ -309,12 +323,16 @@
     checkBadValues(element, "justifyContent", "justify-content",  "safe stretch");
     checkBadValues(element, "justifyContent", "justify-content",  "normal space-between");
     checkBadValues(element, "justifyContent", "justify-content",  "stretch normal");
+    checkBadValues(element, "justifyContent", "justify-content",  "stretch center");
+    checkBadValues(element, "justifyContent", "justify-content",  "space-between right safe");
     checkBadValues(element, "justifyContent", "justify-content",  "normal safe");
     checkBadValues(element, "justifyContent", "justify-content",  "space-around stretch");
     checkBadValues(element, "justifyContent", "justify-content",  "end space-between start");
     checkBadValues(element, "justifyContent", "justify-content",  "right safe left");
     checkBadValues(element, "justifyContent", "justify-content",  "unsafe");
     checkBadValues(element, "justifyContent", "justify-content",  "safe");
+    checkBadValues(element, "justifyContent", "justify-content",  "start safe");
+    checkBadValues(element, "justifyContent", "justify-content",  "end unsafe");
 }, "Test bad combinations of justify-content");
 
 test(function() {
@@ -324,20 +342,17 @@
 
 test(function() {
     element.style.display = "grid";
-    checkInitialValues(element, "justifyContent", "justify-content", "left safe", "normal");
+    checkInitialValues(element, "justifyContent", "justify-content", "safe left", "normal");
 }, "Test the value 'initial' for grid containers");
 
 test(function() {
     element.style.display = "flex";
-    checkInitialValues(element, "justifyContent", "justify-content", "right unsafe", "normal");
+    checkInitialValues(element, "justifyContent", "justify-content", "unsafe right", "normal");
 }, "Test the value 'initial' for flex containers");
 
 test(function() {
     checkInheritValues("justifyContent", "justify-content", "end");
-    checkInheritValues("justifyContent", "justify-content", "left safe");
-    checkInheritValues("justifyContent", "justify-content", "center unsafe");
+    checkInheritValues("justifyContent", "justify-content", "safe left");
+    checkInheritValues("justifyContent", "justify-content", "unsafe center");
 }, "Test the value 'inherit'");
-
 </script>
-</body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/fast/alignment/parse-justify-items.html b/third_party/WebKit/LayoutTests/fast/alignment/parse-justify-items.html
index 21d8d71..cf2411d 100644
--- a/third_party/WebKit/LayoutTests/fast/alignment/parse-justify-items.html
+++ b/third_party/WebKit/LayoutTests/fast/alignment/parse-justify-items.html
@@ -16,6 +16,10 @@
     justify-items: stretch;
 }
 
+#justifyItemsNormal {
+    justify-items: normal;
+}
+
 #justifyItemsStart {
     justify-items: start;
 }
@@ -52,36 +56,36 @@
     justify-items: flex-end;
 }
 
-#justifyItemsEndUnsafe {
-    justify-items: end unsafe;
+#justifyItemsUnsafeEnd {
+    justify-items: unsafe end ;
 }
 
-#justifyItemsCenterUnsafe {
-    justify-items: center unsafe;
+#justifyItemsUnsafeCenter {
+    justify-items: unsafe center ;
 }
 
-#justifyItemsSelfEndSafe {
-    justify-items: self-end safe;
+#justifyItemsSafeSelfEnd {
+    justify-items: safe self-end;
 }
 
-#justifyItemsSelfStartSafe {
-    justify-items: self-start safe;
+#justifyItemsSafeSelfStart {
+    justify-items: safe self-start;
 }
 
-#justifyItemsRightSafe {
-    justify-items: right safe;
+#justifyItemsSafeRight {
+    justify-items: safe right;
 }
 
-#justifyItemsLeftUnsafe {
-    justify-items: left unsafe;
+#justifyItemsUnsafeLeft {
+    justify-items: unsafe left;
 }
 
-#justifyItemsFlexStartUnsafe {
-    justify-items: flex-start unsafe;
+#justifyItemsUnsafeFlexStart {
+    justify-items: unsafe flex-start;
 }
 
-#justifyItemsFlexEndSafe {
-    justify-items: flex-end safe;
+#justifyItemsSafeFlexEnd {
+    justify-items: safe flex-end;
 }
 
 #justifyItemsLegacyLeft {
@@ -113,6 +117,7 @@
 <div id="justifyItemsFirstBaseline"></div>
 <div id="justifyItemsLastBaseline"></div>
 <div id="justifyItemsStretch"></div>
+<div id="justifyItemsNormal"></div>
 <div id="justifyItemsStart"></div>
 <div id="justifyItemsEnd"></div>
 <div id="justifyItemsCenter"></div>
@@ -123,14 +128,14 @@
 <div id="justifyItemsFlexStart"></div>
 <div id="justifyItemsFlexEnd"></div>
 
-<div id="justifyItemsEndUnsafe"></div>
-<div id="justifyItemsCenterUnsafe"></div>
-<div id="justifyItemsSelfEndSafe"></div>
-<div id="justifyItemsSelfStartSafe"></div>
-<div id="justifyItemsRightSafe"></div>
-<div id="justifyItemsLeftUnsafe"></div>
-<div id="justifyItemsFlexStartUnsafe"></div>
-<div id="justifyItemsFlexEndSafe"></div>
+<div id="justifyItemsUnsafeEnd"></div>
+<div id="justifyItemsUnsafeCenter"></div>
+<div id="justifyItemsSafeSelfEnd"></div>
+<div id="justifyItemsSafeSelfStart"></div>
+<div id="justifyItemsSafeRight"></div>
+<div id="justifyItemsUnsafeLeft"></div>
+<div id="justifyItemsUnsafeFlexStart"></div>
+<div id="justifyItemsSafeFlexEnd"></div>
 <div id="justifyItemsLegacyLeft"></div>
 <div id="justifyItemsLegacyCenter"></div>
 <div id="justifyItemsLegacyRight"></div>
@@ -150,6 +155,8 @@
     checkValues(justifyItemsLastBaseline, "justifyItems", "justify-items", "", "last baseline");
     var justifyItemsStretch = document.getElementById("justifyItemsStretch");
     checkValues(justifyItemsStretch, "justifyItems", "justify-items", "", "stretch");
+    var justifyItemsNormal = document.getElementById("justifyItemsNormal");
+    checkValues(justifyItemsNormal, "justifyItems", "justify-items", "", "normal");
     var justifyItemsStart = document.getElementById("justifyItemsStart");
     checkValues(justifyItemsStart, "justifyItems", "justify-items", "", "start");
     var justifyItemsEnd = document.getElementById("justifyItemsEnd");
@@ -169,22 +176,22 @@
     var justifyItemsFlexEnd = document.getElementById("justifyItemsFlexEnd");
     checkValues(justifyItemsFlexEnd, "justifyItems", "justify-items", "", "flex-end");
 
-    var justifyItemsEndUnsafe = document.getElementById("justifyItemsEndUnsafe");
-    checkValues(justifyItemsEndUnsafe, "justifyItems", "justify-items", "", "end unsafe");
-    var justifyItemsCenterUnsafe = document.getElementById("justifyItemsCenterUnsafe");
-    checkValues(justifyItemsCenterUnsafe, "justifyItems", "justify-items", "", "center unsafe");
-    var justifyItemsSelfEndSafe = document.getElementById("justifyItemsSelfEndSafe");
-    checkValues(justifyItemsSelfEndSafe, "justifyItems", "justify-items", "", "self-end safe");
-    var justifyItemsSelfStartSafe = document.getElementById("justifyItemsSelfStartSafe");
-    checkValues(justifyItemsSelfStartSafe, "justifyItems", "justify-items", "", "self-start safe");
-    var justifyItemsRightSafe = document.getElementById("justifyItemsRightSafe");
-    checkValues(justifyItemsRightSafe, "justifyItems", "justify-items", "", "right safe");
-    var justifyItemsLeftUnsafe = document.getElementById("justifyItemsLeftUnsafe");
-    checkValues(justifyItemsLeftUnsafe, "justifyItems", "justify-items", "", "left unsafe");
-    var justifyItemsFlexStartUnsafe = document.getElementById("justifyItemsFlexStartUnsafe");
-    checkValues(justifyItemsFlexStartUnsafe, "justifyItems", "justify-items", "", "flex-start unsafe");
-    var justifyItemsFlexEndSafe = document.getElementById("justifyItemsFlexEndSafe");
-    checkValues(justifyItemsFlexEndSafe, "justifyItems", "justify-items", "", "flex-end safe");
+    var justifyItemsUnsafeEnd = document.getElementById("justifyItemsUnsafeEnd");
+    checkValues(justifyItemsUnsafeEnd, "justifyItems", "justify-items", "", "unsafe end");
+    var justifyItemsUnsafeCenter = document.getElementById("justifyItemsUnsafeCenter");
+    checkValues(justifyItemsUnsafeCenter, "justifyItems", "justify-items", "", "unsafe center");
+    var justifyItemsSafeSelfEnd = document.getElementById("justifyItemsSafeSelfEnd");
+    checkValues(justifyItemsSafeSelfEnd, "justifyItems", "justify-items", "", "safe self-end");
+    var justifyItemsSafeSelfStart = document.getElementById("justifyItemsSafeSelfStart");
+    checkValues(justifyItemsSafeSelfStart, "justifyItems", "justify-items", "", "safe self-start");
+    var justifyItemsSafeRight = document.getElementById("justifyItemsSafeRight");
+    checkValues(justifyItemsSafeRight, "justifyItems", "justify-items", "", "safe right");
+    var justifyItemsUnsafeLeft = document.getElementById("justifyItemsUnsafeLeft");
+    checkValues(justifyItemsUnsafeLeft, "justifyItems", "justify-items", "", "unsafe left");
+    var justifyItemsUnsafeFlexStart = document.getElementById("justifyItemsUnsafeFlexStart");
+    checkValues(justifyItemsUnsafeFlexStart, "justifyItems", "justify-items", "", "unsafe flex-start");
+    var justifyItemsSafeFlexEnd = document.getElementById("justifyItemsSafeFlexEnd");
+    checkValues(justifyItemsSafeFlexEnd, "justifyItems", "justify-items", "", "safe flex-end");
     var justifyItemsLegacyLeft = document.getElementById("justifyItemsLegacyLeft");
     checkValues(justifyItemsLegacyLeft, "justifyItems", "justify-items", "", "legacy left");
     var justifyItemsLegacyCenter = document.getElementById("justifyItemsLegacyCenter");
@@ -212,10 +219,10 @@
     checkValues(element, "justifyItems", "justify-items",  "center", "center");
 
     element.style.justifyItems = "unsafe start";
-    checkValues(element, "justifyItems", "justify-items",  "start unsafe", "start unsafe");
+    checkValues(element, "justifyItems", "justify-items",  "unsafe start", "unsafe start");
 
-    element.style.justifyItems = "flex-end safe";
-    checkValues(element, "justifyItems", "justify-items",  "flex-end safe", "flex-end safe");
+    element.style.justifyItems = "safe flex-end";
+    checkValues(element, "justifyItems", "justify-items",  "safe flex-end", "safe flex-end");
 
     element.style.justifyItems = "right legacy";
     checkValues(element, "justifyItems", "justify-items",  "legacy right", "legacy right");
@@ -226,6 +233,18 @@
     element.style.justifyItems = "left legacy";
     checkValues(element, "justifyItems", "justify-items",  "legacy left", "legacy left");
 
+    element.style.justifyItems = "right";
+    checkValues(element, "justifyItems", "justify-items",  "right", "right");
+
+    element.style.justifyItems = "center";
+    checkValues(element, "justifyItems", "justify-items",  "center", "center");
+
+    element.style.justifyItems = "self-start";
+    checkValues(element, "justifyItems", "justify-items",  "self-start", "self-start");
+
+    element.style.justifyItems = "normal";
+    checkValues(element, "justifyItems", "justify-items",  "normal", "normal");
+
     element.style.justifyItems = "auto";
     checkValues(element, "justifyItems", "justify-items",  "auto", "normal");
 
@@ -255,8 +274,15 @@
     checkBadValues(element, "justifyItems", "justify-items",  "unsafe auto");
     checkBadValues(element, "justifyItems", "justify-items",  "auto safe");
     checkBadValues(element, "justifyItems", "justify-items",  "auto left");
+    checkBadValues(element, "justifyItems", "justify-items",  "normal unsafe");
+    checkBadValues(element, "justifyItems", "justify-items",  "normal stretch");
+    checkBadValues(element, "justifyItems", "justify-items",  "baseline normal");
     checkBadValues(element, "justifyItems", "justify-items",  "baseline safe");
     checkBadValues(element, "justifyItems", "justify-items",  "baseline center");
+    checkBadValues(element, "justifyItems", "justify-items",  "first baseline center");
+    checkBadValues(element, "justifyItems", "justify-items",  "last baseline center");
+    checkBadValues(element, "justifyItems", "justify-items",  "baseline last");
+    checkBadValues(element, "justifyItems", "justify-items",  "baseline first");
     checkBadValues(element, "justifyItems", "justify-items",  "stretch unsafe");
     checkBadValues(element, "justifyItems", "justify-items",  "stretch right");
     checkBadValues(element, "justifyItems", "justify-items",  "unsafe unsafe");
@@ -276,6 +302,8 @@
     checkBadValues(element, "justifyItems", "justify-items",  "legacy stretch");
     checkBadValues(element, "justifyItems", "justify-items",  "legacy");
     checkBadValues(element, "justifyItems", "justify-items",  "legacy left right");
+    checkBadValues(element, "justifyItems", "justify-items",  "start safe");
+    checkBadValues(element, "justifyItems", "justify-items",  "end unsafe");
 }, "Test bad combinations of justify-items");
 
 test(function() {
@@ -285,18 +313,18 @@
 
 test(function() {
     element.style.display = "grid";
-    checkInitialValues(element, "justifyItems", "justify-items", "left safe", "normal");
+    checkInitialValues(element, "justifyItems", "justify-items", "safe left", "normal");
 }, "Test the value 'initial' for grid containers");
 
 test(function() {
     element.style.display = "flex";
-    checkInitialValues(element, "justifyItems", "justify-items", "right unsafe", "normal");
+    checkInitialValues(element, "justifyItems", "justify-items", "unsafe right", "normal");
 }, "Test the value 'initial' for flex containers");
 
 test(function() {
     checkInheritValues("justifyItems", "justify-items", "end");
-    checkInheritValues("justifyItems", "justify-items", "left safe");
-    checkInheritValues("justifyItems", "justify-items", "legacy center");
+    checkInheritValues("justifyItems", "justify-items", "safe left");
+    checkInheritValues("justifyItems", "justify-items", "unsafe center");
 }, "Test the value 'inherit'");
 
 test(function() {
diff --git a/third_party/WebKit/LayoutTests/fast/alignment/parse-justify-self.html b/third_party/WebKit/LayoutTests/fast/alignment/parse-justify-self.html
index 4e11e1e..7d0cc1b 100644
--- a/third_party/WebKit/LayoutTests/fast/alignment/parse-justify-self.html
+++ b/third_party/WebKit/LayoutTests/fast/alignment/parse-justify-self.html
@@ -56,36 +56,36 @@
     justify-self: flex-end;
 }
 
-#justifySelfEndUnsafe {
-    justify-self: end unsafe;
+#justifySelfUnsafeEnd {
+    justify-self: unsafe end ;
 }
 
-#justifySelfCenterUnsafe {
-    justify-self: center unsafe;
+#justifySelfUnsafeCenter {
+    justify-self: unsafe center ;
 }
 
-#justifySelfSelfEndSafe {
-    justify-self: self-end safe;
+#justifySelfSafeSelfEnd {
+    justify-self: safe self-end;
 }
 
-#justifySelfSelfStartSafe {
-    justify-self: self-start safe;
+#justifySelfSafeSelfStart {
+    justify-self: safe self-start;
 }
 
-#justifySelfRightSafe {
-    justify-self: right safe;
+#justifySelfSafeRight {
+    justify-self: safe right;
 }
 
-#justifySelfLeftUnsafe {
-    justify-self: left unsafe;
+#justifySelfUnsafeLeft {
+    justify-self: unsafe left;
 }
 
-#justifySelfFlexStartUnsafe {
-    justify-self: flex-start unsafe;
+#justifySelfUnsafeFlexStart {
+    justify-self: unsafe flex-start;
 }
 
-#justifySelfFlexEndSafe {
-    justify-self: flex-end safe;
+#justifySelfSafeFlexEnd {
+    justify-self: safe flex-end;
 }
 </style>
 <p>Test that setting and getting justify-self works as expected</p>
@@ -104,14 +104,14 @@
 <div id="justifySelfFlexStart"></div>
 <div id="justifySelfFlexEnd"></div>
 
-<div id="justifySelfEndUnsafe"></div>
-<div id="justifySelfCenterUnsafe"></div>
-<div id="justifySelfSelfEndSafe"></div>
-<div id="justifySelfSelfStartSafe"></div>
-<div id="justifySelfRightSafe"></div>
-<div id="justifySelfLeftUnsafe"></div>
-<div id="justifySelfFlexStartUnsafe"></div>
-<div id="justifySelfFlexEndSafe"></div>
+<div id="justifySelfUnsafeEnd"></div>
+<div id="justifySelfUnsafeCenter"></div>
+<div id="justifySelfSafeSelfEnd"></div>
+<div id="justifySelfSafeSelfStart"></div>
+<div id="justifySelfSafeRight"></div>
+<div id="justifySelfUnsafeLeft"></div>
+<div id="justifySelfUnsafeFlexStart"></div>
+<div id="justifySelfSafeFlexEnd"></div>
 <script src="../../resources/testharness.js"></script>
 <script src="../../resources/testharnessreport.js"></script>
 <script src="resources/alignment-parsing-utils-th.js"></script>
@@ -146,22 +146,22 @@
     var justifySelfFlexEnd = document.getElementById("justifySelfFlexEnd");
     checkValues(justifySelfFlexEnd, "justifySelf", "justify-self", "", "flex-end");
 
-    var justifySelfEndUnsafe = document.getElementById("justifySelfEndUnsafe");
-    checkValues(justifySelfEndUnsafe, "justifySelf", "justify-self", "", "end unsafe");
-    var justifySelfCenterUnsafe = document.getElementById("justifySelfCenterUnsafe");
-    checkValues(justifySelfCenterUnsafe, "justifySelf", "justify-self", "", "center unsafe");
-    var justifySelfSelfEndSafe = document.getElementById("justifySelfSelfEndSafe");
-    checkValues(justifySelfSelfEndSafe, "justifySelf", "justify-self", "", "self-end safe");
-    var justifySelfSelfStartSafe = document.getElementById("justifySelfSelfStartSafe");
-    checkValues(justifySelfSelfStartSafe, "justifySelf", "justify-self", "", "self-start safe");
-    var justifySelfRightSafe = document.getElementById("justifySelfRightSafe");
-    checkValues(justifySelfRightSafe, "justifySelf", "justify-self", "", "right safe");
-    var justifySelfLeftUnsafe = document.getElementById("justifySelfLeftUnsafe");
-    checkValues(justifySelfLeftUnsafe, "justifySelf", "justify-self", "", "left unsafe");
-    var justifySelfFlexStartUnsafe = document.getElementById("justifySelfFlexStartUnsafe");
-    checkValues(justifySelfFlexStartUnsafe, "justifySelf", "justify-self", "", "flex-start unsafe");
-    var justifySelfFlexEndSafe = document.getElementById("justifySelfFlexEndSafe");
-    checkValues(justifySelfFlexEndSafe, "justifySelf", "justify-self", "", "flex-end safe");
+    var justifySelfUnsafeEnd = document.getElementById("justifySelfUnsafeEnd");
+    checkValues(justifySelfUnsafeEnd, "justifySelf", "justify-self", "", "unsafe end");
+    var justifySelfUnsafeCenter = document.getElementById("justifySelfUnsafeCenter");
+    checkValues(justifySelfUnsafeCenter, "justifySelf", "justify-self", "", "unsafe center");
+    var justifySelfSafeSelfEnd = document.getElementById("justifySelfSafeSelfEnd");
+    checkValues(justifySelfSafeSelfEnd, "justifySelf", "justify-self", "", "safe self-end");
+    var justifySelfSafeSelfStart = document.getElementById("justifySelfSafeSelfStart");
+    checkValues(justifySelfSafeSelfStart, "justifySelf", "justify-self", "", "safe self-start");
+    var justifySelfSafeRight = document.getElementById("justifySelfSafeRight");
+    checkValues(justifySelfSafeRight, "justifySelf", "justify-self", "", "safe right");
+    var justifySelfUnsafeLeft = document.getElementById("justifySelfUnsafeLeft");
+    checkValues(justifySelfUnsafeLeft, "justifySelf", "justify-self", "", "unsafe left");
+    var justifySelfUnsafeFlexStart = document.getElementById("justifySelfUnsafeFlexStart");
+    checkValues(justifySelfUnsafeFlexStart, "justifySelf", "justify-self", "", "unsafe flex-start");
+    var justifySelfSafeFlexEnd = document.getElementById("justifySelfSafeFlexEnd");
+    checkValues(justifySelfSafeFlexEnd, "justifySelf", "justify-self", "", "safe flex-end");
 }, "Test getting justify-self set through CSS.");
 
 test(function() {
@@ -179,10 +179,10 @@
     checkValues(element, "justifySelf", "justify-self",  "center", "center");
 
     element.style.justifySelf = "unsafe start";
-    checkValues(element, "justifySelf", "justify-self",  "start unsafe", "start unsafe");
+    checkValues(element, "justifySelf", "justify-self",  "unsafe start", "unsafe start");
 
-    element.style.justifySelf = "flex-end safe";
-    checkValues(element, "justifySelf", "justify-self",  "flex-end safe", "flex-end safe");
+    element.style.justifySelf = "safe flex-end";
+    checkValues(element, "justifySelf", "justify-self",  "safe flex-end", "safe flex-end");
 
     element.style.justifySelf = "right";
     checkValues(element, "justifySelf", "justify-self",  "right", "right");
@@ -222,7 +222,6 @@
     container.appendChild(element);
     document.body.appendChild(container);
 
-    checkBadValues(element, "justifySelf", "justify-self",  "unsafe auto");
     checkBadValues(element, "justifySelf", "justify-self",  "auto safe");
     checkBadValues(element, "justifySelf", "justify-self",  "auto left");
     checkBadValues(element, "justifySelf", "justify-self",  "normal unsafe");
@@ -230,6 +229,10 @@
     checkBadValues(element, "justifySelf", "justify-self",  "baseline normal");
     checkBadValues(element, "justifySelf", "justify-self",  "baseline safe");
     checkBadValues(element, "justifySelf", "justify-self",  "baseline center");
+    checkBadValues(element, "justifySelf", "justify-self",  "first baseline center");
+    checkBadValues(element, "justifySelf", "justify-self",  "last baseline center");
+    checkBadValues(element, "justifySelf", "justify-self",  "baseline last");
+    checkBadValues(element, "justifySelf", "justify-self",  "baseline first");
     checkBadValues(element, "justifySelf", "justify-self",  "stretch unsafe");
     checkBadValues(element, "justifySelf", "justify-self",  "stretch right");
     checkBadValues(element, "justifySelf", "justify-self",  "unsafe unsafe");
@@ -249,6 +252,8 @@
     checkBadValues(element, "justifySelf", "justify-self",  "legacy stretch");
     checkBadValues(element, "justifySelf", "justify-self",  "legacy");
     checkBadValues(element, "justifySelf", "justify-self",  "legacy left right");
+    checkBadValues(element, "justifySelf", "justify-self",  "start safe");
+    checkBadValues(element, "justifySelf", "justify-self",  "end unsafe");
 }, "Test bad combinations of justify-self");
 
 test(function() {
@@ -258,12 +263,12 @@
 
 test(function() {
     container.style.display = "grid";
-    checkInitialValues(element, "justifySelf", "justify-self", "left safe", "auto");
+    checkInitialValues(element, "justifySelf", "justify-self", "safe left", "auto");
 }, "Test the value 'initial' for grid containers");
 
 test(function() {
     container.style.display = "flex";
-    checkInitialValues(element, "justifySelf", "justify-self", "right unsafe", "auto");
+    checkInitialValues(element, "justifySelf", "justify-self", "unsafe right", "auto");
 }, "Test the value 'initial' for flex containers");
 
 test(function() {
@@ -286,7 +291,7 @@
 
 test(function() {
     checkInheritValues("justifySelf", "justify-self", "end");
-    checkInheritValues("justifySelf", "justify-self", "left safe");
-    checkInheritValues("justifySelf", "justify-self", "center unsafe");
+    checkInheritValues("justifySelf", "justify-self", "safe left");
+    checkInheritValues("justifySelf", "justify-self", "unsafe center");
 }, "Test the value 'inherit'");
 </script>
diff --git a/third_party/WebKit/LayoutTests/fast/css-grid-layout/resources/grid-alignment.css b/third_party/WebKit/LayoutTests/fast/css-grid-layout/resources/grid-alignment.css
index f64a9ec..2c5c3b4 100644
--- a/third_party/WebKit/LayoutTests/fast/css-grid-layout/resources/grid-alignment.css
+++ b/third_party/WebKit/LayoutTests/fast/css-grid-layout/resources/grid-alignment.css
@@ -13,10 +13,10 @@
 .alignSelfSelfStart { align-self: self-start; }
 .alignSelfSelfEnd { align-self: self-end; }
 
-.alignSelfCenterSafe { align-self: center safe; }
-.alignSelfCenterUnsafe { align-self: center unsafe; }
-.alignSelfEndSafe { align-self: end safe; }
-.alignSelfEndUnsafe { align-self: end unsafe; }
+.alignSelfCenterSafe { align-self: safe center; }
+.alignSelfCenterUnsafe { align-self: unsafe center; }
+.alignSelfEndSafe { align-self: safe end; }
+.alignSelfEndUnsafe { align-self: unsafe end; }
 
 .alignSelfBaseline { align-self: baseline; }
 
@@ -28,10 +28,10 @@
 .alignItemsEnd { align-items: end; }
 .alignItemsBaseline { align-items: baseline; }
 
-.alignItemsCenterSafe { align-items: center safe; }
-.alignItemsCenterUnsafe { align-items: center unsafe; }
-.alignItemsEndSafe { align-items: end safe; }
-.alignItemsEndUnsafe { align-items: end unsafe; }
+.alignItemsCenterSafe { align-items: safe center; }
+.alignItemsCenterUnsafe { align-items: unsafe center; }
+.alignItemsEndSafe { align-items: safe end; }
+.alignItemsEndUnsafe { align-items: unsafe end; }
 
 /* align-content */
 .alignContentBaseline { align-content: baseline; }
@@ -63,8 +63,8 @@
 .justifySelfSelfStart { justify-self: self-start; }
 .justifySelfSelfEnd { justify-self: self-end; }
 
-.justifySelfCenterSafe { justify-self: center safe; }
-.justifySelfCenterUnsafe { justify-self: center unsafe; }
+.justifySelfCenterSafe { justify-self: safe center; }
+.justifySelfCenterUnsafe { justify-self: unsafe center; }
 
 .justifySelfBaseline { justify-self: baseline; }
 
@@ -75,10 +75,10 @@
 .justifyItemsCenter { justify-items: center; }
 .justifyItemsEnd { justify-items: end; }
 
-.justifyItemsCenterSafe { justify-items: center safe; }
-.justifyItemsCenterUnsafe { justify-items: center unsafe; }
-.justifyItemsEndSafe { justify-items: end safe; }
-.justifyItemsEndUnsafe { justify-items: end unsafe; }
+.justifyItemsCenterSafe { justify-items: safe center; }
+.justifyItemsCenterUnsafe { justify-items: unsafe center; }
+.justifyItemsEndSafe { justify-items: safe end; }
+.justifyItemsEndUnsafe { justify-items: unsafe end; }
 
 .justifyItemsBaseline { justify-items: baseline; }
 
@@ -200,23 +200,23 @@
 }
 
 .contentCenterSafe {
-    align-content: center safe;
-    justify-content: center safe;
+    align-content: safe center;
+    justify-content: safe center;
 }
 
 .contentCenterUnsafe {
-    align-content: center unsafe;
-    justify-content: center unsafe;
+    align-content: unsafe center;
+    justify-content: unsafe center;
 }
 
 .contentEndSafe {
-    align-content: end safe;
-    justify-content: end safe;
+    align-content: safe end;
+    justify-content: safe end;
 }
 
 .contentEndUnsafe {
-    align-content: end unsafe;
-    justify-content: end unsafe;
+    align-content: unsafe end;
+    justify-content: unsafe end;
 }
 
 .contentSpaceBetween {
diff --git a/third_party/WebKit/LayoutTests/fast/css/invalid-font-face-crash.html b/third_party/WebKit/LayoutTests/fast/css/invalid-font-face-crash.html
new file mode 100644
index 0000000..2d8241d
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css/invalid-font-face-crash.html
@@ -0,0 +1,11 @@
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<style id="styleElement">
+@font-face {}
+</style>
+<script>
+test(() => {
+  let fontFaceRule = styleElement.sheet.rules[0];
+  assert_equals(fontFaceRule.style.getPropertyValue('font-display'), "");
+}, "This test should not crash");
+</script>
diff --git a/third_party/WebKit/LayoutTests/fast/dom/HTMLLinkElement/rellist-feature-detection.html b/third_party/WebKit/LayoutTests/fast/dom/HTMLLinkElement/rellist-feature-detection.html
deleted file mode 100644
index 9dd020e..0000000
--- a/third_party/WebKit/LayoutTests/fast/dom/HTMLLinkElement/rellist-feature-detection.html
+++ /dev/null
@@ -1,20 +0,0 @@
-<!DOCTYPE html>
-<script src="../../../resources/testharness.js"></script>
-<script src="../../../resources/testharnessreport.js"></script>
-<script>
-    test(function() {
-        var link = document.createElement("link");
-        // Test that setting rel is also setting relList, for both valid and invalid values
-        link.rel = "whatever";
-        assert_true(link.relList.contains("whatever"));
-        link.rel = "prefetch";
-        assert_true(link.relList.contains("prefetch"));
-        // Test that "add()" works
-        link.relList.add("preloadwhatever");
-        assert_equals(link.rel, "prefetch preloadwhatever");
-        assert_true(link.relList.contains("preloadwhatever"));
-        // Test that "supports()" is returning true for valid values and false for invalid ones
-        assert_false(link.relList.supports("bogus"));
-        assert_true(link.relList.supports("preload"));
-    }, "Make sure that relList based feature detection is working");
-</script>
diff --git a/third_party/WebKit/LayoutTests/fast/dom/margin-height-guarded-crash-expected.txt b/third_party/WebKit/LayoutTests/fast/dom/margin-height-guarded-crash-expected.txt
new file mode 100644
index 0000000..6401436
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/dom/margin-height-guarded-crash-expected.txt
@@ -0,0 +1,5 @@
+CONSOLE ERROR: line 22: Uncaught TypeError: Failed to execute 'appendChild' on 'Node': parameter 1 is not of type 'Node'.
+This is a testharness.js-based test.
+PASS try-trigger-crash
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/fast/dom/margin-height-guarded-crash.html b/third_party/WebKit/LayoutTests/fast/dom/margin-height-guarded-crash.html
new file mode 100644
index 0000000..b0546e4a
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/dom/margin-height-guarded-crash.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<body>
+<!--
+Adapted from clusterfuzz case filed in https://crbug.com/778956.
+This bug was a combination of 2 things:
+  - calling appendChild with an iframe's body as the child causes the
+    iframe body to become null
+  - changing a body's margin height in an event handler reacting a
+    change in the same body's margin width causes a method call on the
+    body without checking if it's null. The change in height does not
+    complete immediately, some of the change is applied to the Node
+    _after_ the handler completes by which point the node (body) has
+    become null.
+-->
+<iframe id=html_iframe></iframe>
+<div id=html_div></div>
+<script>
+function reactToWidthChange() {
+  // null the body
+  html_div.appendChild(html_iframe.contentDocument.body);
+  // change the height
+  html_iframe.marginHeight = "0";
+}
+
+test(() => {
+  window[0].addEventListener("DOMSubtreeModified", reactToWidthChange);
+  html_iframe.marginWidth = "0";
+}, 'try-trigger-crash');
+</script>
+</body>
diff --git a/third_party/WebKit/LayoutTests/fast/forms/checkbox/checkbox-keyboard-event.html b/third_party/WebKit/LayoutTests/fast/forms/checkbox/checkbox-keyboard-event.html
new file mode 100644
index 0000000..1b6f754f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/forms/checkbox/checkbox-keyboard-event.html
@@ -0,0 +1,39 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Checkbox keyboard event</title>
+<link rel=help href="https://html.spec.whatwg.org/#checkbox-state-(type=checkbox)">
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+
+<body>
+<script>
+"use strict";
+
+test(() => {
+  const input = document.createElement("input");
+  input.type = "checkbox";
+  document.body.appendChild(input);
+  const events = [];
+
+  input.addEventListener("change", () => {
+    events.push("change");
+  });
+  input.addEventListener("click", () => {
+    events.push("click");
+  });
+  input.addEventListener("input", () => {
+    events.push("input");
+  });
+
+  assert_false(input.checked);
+
+  if (window.eventSender) {
+    input.focus();
+    eventSender.keyDown(" ");
+
+    assert_true(input.checked);
+    assert_array_equals(events, ["click", "input", "change"]);
+  }
+
+}, "a checkbox input emits click, input, change events in order after keyboard event");
+</script>
diff --git a/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-backtrack-out-of-non-navigable-iframe-expected.txt b/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-backtrack-out-of-non-navigable-iframe-expected.txt
new file mode 100644
index 0000000..f90ad92
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-backtrack-out-of-non-navigable-iframe-expected.txt
@@ -0,0 +1,9 @@
+StartEnd
+PASS successfullyParsed is true
+
+TEST COMPLETE
+PASS gFocusedDocument.activeElement.getAttribute("id") is "end"
+PASS gFocusedDocument.activeElement.getAttribute("id") is "start"
+PASS gFocusedDocument.activeElement.getAttribute("id") is "end"
+PASS gFocusedDocument.activeElement.getAttribute("id") is "start"
+This test tests that an iframe element without any focusable content will be ignored.
diff --git a/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-backtrack-out-of-non-navigable-iframe.html b/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-backtrack-out-of-non-navigable-iframe.html
new file mode 100644
index 0000000..bb511d2
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-backtrack-out-of-non-navigable-iframe.html
@@ -0,0 +1,55 @@
+<!--
+  This test ensures the correctness of a basic aspect of spatial navigation's
+  search for candidates to focus: an iframe element without any focusable content
+  should be ignored.
+
+  * Pre-conditions:
+  1) Run chromium with --enable-spatial-navigation.
+
+  * Navigation steps:
+  1) Loads this page, focus goes to "start" automatically.
+  2) Focus moves from "start" to "end" and return back.
+-->
+<script src="../../resources/js-test.js"></script>
+<script src="resources/spatial-navigation-utils.js"></script>
+<script type="application/javascript">
+
+var resultMap = [
+  ["Down", "end"],
+  ["Up", "start"],
+  ["Left", "end"],
+  ["Right", "start"],
+  ["DONE", "DONE"]
+];
+
+if (window.testRunner) {
+  testRunner.dumpAsText();
+  testRunner.overridePreference("WebKitTabToLinksPreferenceKey", 1);
+  testRunner.overridePreference("WebKitSpatialNavigationEnabled", 1);
+  testRunner.waitUntilDone();
+}
+
+function runTest()
+{
+  // starting the test itself: get to a known place.
+  document.getElementById("start").focus();
+
+  initTest(resultMap, testCompleted);
+}
+
+function testCompleted()
+{
+  if (window.testRunner)
+    testRunner.notifyDone();
+}
+
+window.onload = runTest;
+</script>
+
+<div style="position: relative;">
+  <a id="start" href="#" style="position: absolute; top: 10px; left: 50px;">Start</a>
+  <a id="end" href="#" style="position: absolute; top: 50px; left: 10px;">End</a>
+  <iframe style="position: absolute; top: 50px; left: 50px;" src="data:text/html,"></iframe>
+</div>
+<div id="console"></div>
+<div>This test tests that an iframe element without any focusable content will be ignored.</div>
diff --git a/third_party/WebKit/LayoutTests/media/track/track-webvtt-non-snap-to-lines-expected.html b/third_party/WebKit/LayoutTests/media/track/track-webvtt-non-snap-to-lines-expected.html
deleted file mode 100644
index 877333d7..0000000
--- a/third_party/WebKit/LayoutTests/media/track/track-webvtt-non-snap-to-lines-expected.html
+++ /dev/null
@@ -1,26 +0,0 @@
-<!DOCTYPE html>
-<title>Reference test for track-webvtt-non-snap-to-lines.html.</title>
-<script src="../media-file.js"></script>
-<style>
-.container {
-  position: relative;
-  display: inline-block;
-}
-.cue {
-  position: absolute;
-  top: 48px;
-  font-family: sans-serif;
-  background: green;
-  color: rgba(255, 255, 255, 1);
-  font-size: 12px;
-  padding: 0px 2px;
-}
-</style>
-<div class="container">
-  <video>
-    <script>
-    document.currentScript.parentNode.src = findMediaFile('video', '../content/test');
-    </script>
-  </video>
-  <span class="cue">Bear is Coming!!!!!</div>
-</div>
diff --git a/third_party/WebKit/LayoutTests/media/track/track-webvtt-non-snap-to-lines.html b/third_party/WebKit/LayoutTests/media/track/track-webvtt-non-snap-to-lines.html
deleted file mode 100644
index 3e45b33..0000000
--- a/third_party/WebKit/LayoutTests/media/track/track-webvtt-non-snap-to-lines.html
+++ /dev/null
@@ -1,20 +0,0 @@
-<!DOCTYPE html>
-<title>Tests that position is not adjusted for non snap-to-lines cues.</title>
-<style>
-::cue {
-  background: green;
-}
-</style>
-<script src="../media-file.js"></script>
-<video></video>
-<script>
-var video = document.querySelector("video");
-var track = video.addTextTrack("captions");
-var cue = new VTTCue(0, 1, "Bear is Coming!!!!!");
-cue.snapToLines = false;
-cue.line = 20;
-cue.align = "left";
-track.addCue(cue);
-track.mode = "showing";
-video.src = findMediaFile("video", "../content/test");
-</script>
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/media/track/track-webvtt-two-cue-layout-after-first-end.html b/third_party/WebKit/LayoutTests/media/track/track-webvtt-two-cue-layout-after-first-end.html
deleted file mode 100644
index dd0ef417..0000000
--- a/third_party/WebKit/LayoutTests/media/track/track-webvtt-two-cue-layout-after-first-end.html
+++ /dev/null
@@ -1,26 +0,0 @@
-<!DOCTYPE html>
-<title>WebVTT two-cue layout after the first cue has ended</title>
-<video style="border:1px solid gray">
-  <source src="../content/white.webm" type="video/webm">
-  <source src="../content/white.mp4" type="video/mp4">
-</video>
-<script>
-// Without testRunner.layoutAndPaintAsyncThen there is no guarantee for when the first
-// cue layout is done, so make no attempt to work without testRunner.
-testRunner.waitUntilDone();
-
-// Add two cues, where the first cue ends before the second.
-var video = document.querySelector("video");
-var track = video.addTextTrack("captions");
-track.addCue(new VTTCue(0, 1, "cue 1"));
-track.addCue(new VTTCue(0, 3, "cue 2"));
-track.mode = "showing";
-
-video.onloadeddata = function() {
-  testRunner.layoutAndPaintAsyncThen(function() {
-    // Seek past the end of the first cue. The second cue should not move.
-    video.currentTime = 2;
-    video.onseeked = function() { testRunner.notifyDone(); };
-  });
-};
-</script>
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/overflow/align-items-overflow-change-expected.html b/third_party/WebKit/LayoutTests/paint/invalidation/overflow/align-items-overflow-change-expected.html
index 6ffb231..46726e5 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/overflow/align-items-overflow-change-expected.html
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/overflow/align-items-overflow-change-expected.html
@@ -6,7 +6,7 @@
 #container {
   display: grid;
   grid: 150px 150px / 200px;
-  align-items: end safe;
+  align-items: safe end;
   width: 200px;
   height: 300px;
   background-color: red;
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/overflow/align-items-overflow-change.html b/third_party/WebKit/LayoutTests/paint/invalidation/overflow/align-items-overflow-change.html
index 96480cd3..4154339 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/overflow/align-items-overflow-change.html
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/overflow/align-items-overflow-change.html
@@ -2,7 +2,7 @@
 <script src="../resources/text-based-repaint.js"></script>
 <script>
 function repaintTest() {
-  document.getElementById('container').style.alignItems = 'end safe';
+  document.getElementById('container').style.alignItems = 'safe end';
 }
 onload = runRepaintAndPixelTest;
 </script>
@@ -13,7 +13,7 @@
 #container {
   display: grid;
   grid: 150px 150px / 200px;
-  align-items: end unsafe;
+  align-items: unsafe end;
   width: 200px;
   height: 300px;
   background-color: red;
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/overflow/align-self-overflow-change-expected.html b/third_party/WebKit/LayoutTests/paint/invalidation/overflow/align-self-overflow-change-expected.html
index 1c588d3..5743aa1c 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/overflow/align-self-overflow-change-expected.html
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/overflow/align-self-overflow-change-expected.html
@@ -12,13 +12,13 @@
 .item1 {
   grid-row: 1;
   grid-column: 1;
-  align-self: end safe;
+  align-self: safe end;
   background-color: green;
 }
 .item2 {
   grid-row: 2;
   grid-column: 1;
-  align-self: end safe;
+  align-self: safe end;
   background-color: green;
 </style>
 <p style="height: 20px">Tests invalidation on align-self style change (just overflow). Passes if there is no red.</p>
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/overflow/align-self-overflow-change.html b/third_party/WebKit/LayoutTests/paint/invalidation/overflow/align-self-overflow-change.html
index f5522ed..f1e81e08 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/overflow/align-self-overflow-change.html
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/overflow/align-self-overflow-change.html
@@ -2,8 +2,8 @@
 <script src="../resources/text-based-repaint.js"></script>
 <script>
 function repaintTest() {
-  document.getElementsByClassName('item1')[0].style.alignSelf = 'end safe';
-  document.getElementsByClassName('item2')[0].style.alignSelf = 'end safe';
+  document.getElementsByClassName('item1')[0].style.alignSelf = 'safe end';
+  document.getElementsByClassName('item2')[0].style.alignSelf = 'safe end';
 }
 onload = runRepaintAndPixelTest;
 </script>
@@ -21,13 +21,13 @@
 .item1 {
   grid-row: 1;
   grid-column: 1;
-  align-self: end unsafe;
+  align-self: unsafe end;
   background-color: green;
 }
 .item2 {
   grid-row: 2;
   grid-column: 1;
-  align-self: end unsafe;
+  align-self: unsafe end;
   background-color: green;
 </style>
 <p style="height: 20px">Tests invalidation on align-self style change (just overflow). Passes if there is no red.</p>
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/overflow/justify-items-overflow-change-expected.html b/third_party/WebKit/LayoutTests/paint/invalidation/overflow/justify-items-overflow-change-expected.html
index bb43348f..7b47261 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/overflow/justify-items-overflow-change-expected.html
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/overflow/justify-items-overflow-change-expected.html
@@ -6,7 +6,7 @@
 #container {
   display: grid;
   grid: 300px / 100px 100px;
-  justify-items: end safe;
+  justify-items: safe end;
   width: 200px;
   height: 300px;
   background-color: red;
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/overflow/justify-items-overflow-change.html b/third_party/WebKit/LayoutTests/paint/invalidation/overflow/justify-items-overflow-change.html
index dc81c40..1810dc5 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/overflow/justify-items-overflow-change.html
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/overflow/justify-items-overflow-change.html
@@ -2,7 +2,7 @@
 <script src="../resources/text-based-repaint.js"></script>
 <script>
 function repaintTest() {
-  document.getElementById('container').style.justifyItems = 'end safe';
+  document.getElementById('container').style.justifyItems = 'safe end';
 }
 onload = runRepaintAndPixelTest;
 </script>
@@ -13,7 +13,7 @@
 #container {
   display: grid;
   grid: 300px / 100px 100px;
-  justify-items: end unsafe;
+  justify-items: unsafe end;
   width: 200px;
   height: 300px;
   background-color: red;
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/overflow/justify-self-overflow-change-expected.html b/third_party/WebKit/LayoutTests/paint/invalidation/overflow/justify-self-overflow-change-expected.html
index b42b4aa..476c5be 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/overflow/justify-self-overflow-change-expected.html
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/overflow/justify-self-overflow-change-expected.html
@@ -12,7 +12,7 @@
 .item1 {
   grid-row: 1;
   grid-column: 1;
-  justify-self: end safe;
+  justify-self: safe end;
   background-color: green;
   width: 150px;
 }
@@ -20,7 +20,7 @@
   grid-row: 1;
   grid-column: 2;
   background-color: green;
-  justify-self: end safe;
+  justify-self: safe end;
   width: 50px;
 </style>
 <p style="height: 20px">Tests invalidation on justify-self style change. Passes if there is no red.</p>
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/overflow/justify-self-overflow-change.html b/third_party/WebKit/LayoutTests/paint/invalidation/overflow/justify-self-overflow-change.html
index 5266d459..d493d8c 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/overflow/justify-self-overflow-change.html
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/overflow/justify-self-overflow-change.html
@@ -2,8 +2,8 @@
 <script src="../resources/text-based-repaint.js"></script>
 <script>
 function repaintTest() {
-  document.getElementsByClassName('item1')[0].style.justifySelf = 'end safe';
-  document.getElementsByClassName('item2')[0].style.justifySelf = 'end safe';
+  document.getElementsByClassName('item1')[0].style.justifySelf = 'safe end';
+  document.getElementsByClassName('item2')[0].style.justifySelf = 'safe end';
 }
 onload = runRepaintAndPixelTest;
 </script>
@@ -21,7 +21,7 @@
 .item1 {
   grid-row: 1;
   grid-column: 1;
-  justify-self: end unsafe;
+  justify-self: unsafe end;
   background-color: green;
   width: 150px;
 }
@@ -29,7 +29,7 @@
   grid-row: 1;
   grid-column: 2;
   background-color: green;
-  justify-self: end unsafe;
+  justify-self: unsafe end;
   width: 50px;
 </style>
 <p style="height: 20px">Tests invalidation on justify-self style change. Passes if there is no red.</p>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/syntax/parsing/html5lib_menuitem-element_run_type=uri-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/external/wpt/html/syntax/parsing/html5lib_menuitem-element_run_type=uri-expected.txt
similarity index 100%
copy from third_party/WebKit/LayoutTests/external/wpt/html/syntax/parsing/html5lib_menuitem-element_run_type=uri-expected.txt
copy to third_party/WebKit/LayoutTests/platform/linux/external/wpt/html/syntax/parsing/html5lib_menuitem-element_run_type=uri-expected.txt
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/syntax/parsing/html5lib_menuitem-element_run_type=write_single-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/external/wpt/html/syntax/parsing/html5lib_menuitem-element_run_type=write_single-expected.txt
similarity index 100%
copy from third_party/WebKit/LayoutTests/external/wpt/html/syntax/parsing/html5lib_menuitem-element_run_type=write_single-expected.txt
copy to third_party/WebKit/LayoutTests/platform/linux/external/wpt/html/syntax/parsing/html5lib_menuitem-element_run_type=write_single-expected.txt
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/syntax/parsing/html5lib_tests11_run_type=write_single-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/external/wpt/html/syntax/parsing/html5lib_tests11_run_type=write_single-expected.txt
similarity index 100%
copy from third_party/WebKit/LayoutTests/external/wpt/html/syntax/parsing/html5lib_tests11_run_type=write_single-expected.txt
copy to third_party/WebKit/LayoutTests/platform/linux/external/wpt/html/syntax/parsing/html5lib_tests11_run_type=write_single-expected.txt
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/syntax/parsing/html5lib_webkit02_run_type=uri-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/external/wpt/html/syntax/parsing/html5lib_webkit02_run_type=uri-expected.txt
similarity index 100%
copy from third_party/WebKit/LayoutTests/external/wpt/html/syntax/parsing/html5lib_webkit02_run_type=uri-expected.txt
copy to third_party/WebKit/LayoutTests/platform/linux/external/wpt/html/syntax/parsing/html5lib_webkit02_run_type=uri-expected.txt
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/syntax/parsing/html5lib_menuitem-element_run_type=uri-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/external/wpt/html/syntax/parsing/html5lib_menuitem-element_run_type=uri-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/external/wpt/html/syntax/parsing/html5lib_menuitem-element_run_type=uri-expected.txt
rename to third_party/WebKit/LayoutTests/platform/mac/external/wpt/html/syntax/parsing/html5lib_menuitem-element_run_type=uri-expected.txt
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/syntax/parsing/html5lib_menuitem-element_run_type=write_single-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/external/wpt/html/syntax/parsing/html5lib_menuitem-element_run_type=write_single-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/external/wpt/html/syntax/parsing/html5lib_menuitem-element_run_type=write_single-expected.txt
rename to third_party/WebKit/LayoutTests/platform/mac/external/wpt/html/syntax/parsing/html5lib_menuitem-element_run_type=write_single-expected.txt
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/syntax/parsing/html5lib_tests11_run_type=write_single-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/external/wpt/html/syntax/parsing/html5lib_tests11_run_type=write_single-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/external/wpt/html/syntax/parsing/html5lib_tests11_run_type=write_single-expected.txt
rename to third_party/WebKit/LayoutTests/platform/mac/external/wpt/html/syntax/parsing/html5lib_tests11_run_type=write_single-expected.txt
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/syntax/parsing/html5lib_webkit02_run_type=uri-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/external/wpt/html/syntax/parsing/html5lib_webkit02_run_type=uri-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/external/wpt/html/syntax/parsing/html5lib_webkit02_run_type=uri-expected.txt
rename to third_party/WebKit/LayoutTests/platform/mac/external/wpt/html/syntax/parsing/html5lib_webkit02_run_type=uri-expected.txt
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/syntax/parsing/html5lib_menuitem-element_run_type=uri-expected.txt b/third_party/WebKit/LayoutTests/platform/win7/external/wpt/html/syntax/parsing/html5lib_menuitem-element_run_type=uri-expected.txt
similarity index 100%
copy from third_party/WebKit/LayoutTests/external/wpt/html/syntax/parsing/html5lib_menuitem-element_run_type=uri-expected.txt
copy to third_party/WebKit/LayoutTests/platform/win7/external/wpt/html/syntax/parsing/html5lib_menuitem-element_run_type=uri-expected.txt
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/syntax/parsing/html5lib_menuitem-element_run_type=write_single-expected.txt b/third_party/WebKit/LayoutTests/platform/win7/external/wpt/html/syntax/parsing/html5lib_menuitem-element_run_type=write_single-expected.txt
similarity index 100%
copy from third_party/WebKit/LayoutTests/external/wpt/html/syntax/parsing/html5lib_menuitem-element_run_type=write_single-expected.txt
copy to third_party/WebKit/LayoutTests/platform/win7/external/wpt/html/syntax/parsing/html5lib_menuitem-element_run_type=write_single-expected.txt
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/syntax/parsing/html5lib_tests11_run_type=write_single-expected.txt b/third_party/WebKit/LayoutTests/platform/win7/external/wpt/html/syntax/parsing/html5lib_tests11_run_type=write_single-expected.txt
similarity index 100%
copy from third_party/WebKit/LayoutTests/external/wpt/html/syntax/parsing/html5lib_tests11_run_type=write_single-expected.txt
copy to third_party/WebKit/LayoutTests/platform/win7/external/wpt/html/syntax/parsing/html5lib_tests11_run_type=write_single-expected.txt
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/syntax/parsing/html5lib_webkit02_run_type=uri-expected.txt b/third_party/WebKit/LayoutTests/platform/win7/external/wpt/html/syntax/parsing/html5lib_webkit02_run_type=uri-expected.txt
similarity index 100%
copy from third_party/WebKit/LayoutTests/external/wpt/html/syntax/parsing/html5lib_webkit02_run_type=uri-expected.txt
copy to third_party/WebKit/LayoutTests/platform/win7/external/wpt/html/syntax/parsing/html5lib_webkit02_run_type=uri-expected.txt
diff --git a/third_party/WebKit/LayoutTests/resources/testharnessreport.js b/third_party/WebKit/LayoutTests/resources/testharnessreport.js
index d23b3046..f7d8ea8 100644
--- a/third_party/WebKit/LayoutTests/resources/testharnessreport.js
+++ b/third_party/WebKit/LayoutTests/resources/testharnessreport.js
@@ -109,7 +109,8 @@
             pathAndBase.startsWith('/uievents/') ||
             pathAndBase.startsWith('/pointerlock/') ||
             pathAndBase.startsWith('/html/') ||
-            pathAndBase.startsWith('/input-events/')) {
+            pathAndBase.startsWith('/input-events/') ||
+            pathAndBase.startsWith('/css/selectors/')) {
             // Per-test automation scripts.
             src = automationPath + pathAndBase + '-automation.js';
         } else {
diff --git a/third_party/WebKit/LayoutTests/shadow-dom/css-style-inherit.html b/third_party/WebKit/LayoutTests/shadow-dom/css-style-inherit.html
index 888cb43d..8f89dbce 100644
--- a/third_party/WebKit/LayoutTests/shadow-dom/css-style-inherit.html
+++ b/third_party/WebKit/LayoutTests/shadow-dom/css-style-inherit.html
@@ -31,8 +31,8 @@
 
   assert_equals(getComputedStyle(span0).color, 'rgb(0, 0, 0)',
                 'An element which is not assigned to any slot should not inherit a style from the parent.');
-  assert_equals(getComputedStyle(host.shadowRoot.querySelector('slot')).color, 'rgb(0, 0, 0)',
-                'A slot should not inherit a style from the parent because Blink does not support "slots in the flat tree".');
+  assert_equals(getComputedStyle(host.shadowRoot.querySelector('slot')).color, 'rgb(0, 128, 0)',
+                'A slot should inherit style from the parent.');
 
   assert_equals(getComputedStyle(span1).color, 'rgb(0, 128, 0)',
                 'An element which is assigned to a slot should inherit a style from the slot.');
diff --git a/third_party/WebKit/LayoutTests/vr/resources/mock-vr-service.js b/third_party/WebKit/LayoutTests/vr/resources/mock-vr-service.js
index 1cdefebd..1c6d124c 100644
--- a/third_party/WebKit/LayoutTests/vr/resources/mock-vr-service.js
+++ b/third_party/WebKit/LayoutTests/vr/resources/mock-vr-service.js
@@ -39,6 +39,10 @@
     });
   }
 
+  getSubmitFrameCount() {
+    return this.presentation_provider_.submit_frame_count_;
+  }
+
   forceActivate(reason) {
     this.displayClient_.onActivate(reason);
   }
@@ -64,6 +68,7 @@
   constructor() {
     this.binding_ = new mojo.Binding(device.mojom.VRPresentationProvider, this);
     this.pose_ = null;
+    this.submit_frame_count_ = 0;
   }
 
   bind(client, request) {
@@ -73,6 +78,8 @@
   }
 
   submitFrame(frameId, mailboxHolder, timeWaited) {
+    this.submit_frame_count_++;
+
     // Trigger the submit completion callbacks here. WARNING: The
     // Javascript-based mojo mocks are *not* re-entrant. It's OK to
     // wait for these notifications on the next frame, but waiting
diff --git a/third_party/WebKit/LayoutTests/xr/xrWebGLLayer_dirty_framebuffer.html b/third_party/WebKit/LayoutTests/xr/xrWebGLLayer_dirty_framebuffer.html
new file mode 100644
index 0000000..ccb231b1
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/xr/xrWebGLLayer_dirty_framebuffer.html
@@ -0,0 +1,51 @@
+<!DOCTYPE html>
+<script src="../resources/testharness.js"></script>
+<script src="../resources/testharnessreport.js"></script>
+<script src="../vr/resources/fake-vr-displays.js"></script>
+<script src="file:///gen/layout_test_data/mojo/public/js/mojo_bindings.js"></script>
+<script src="file:///gen/device/vr/vr_service.mojom.js"></script>
+<script src="../vr/resources/mock-vr-service.js"></script>
+<script src="../vr/resources/test-constants.js"></script>
+<canvas id="webgl-canvas"></canvas>
+<script src="../vr/resources/presentation-setup.js"></script>
+<script>
+let fakeDisplays = fakeVRDisplays();
+
+xr_session_test( (t, session, mockService) => {
+  // Session must have a baseLayer or else frame requests will be ignored.
+  let webglLayer = new XRWebGLLayer(session, gl);
+  session.baseLayer = webglLayer;
+  let mockDisplay = mockService.mockVRDisplays_[0];
+  function onSkipFrame(time, xrFrame) {
+    // No GL commands issued
+    session.requestAnimationFrame(onDrawToCanvas);
+  }
+  function onDrawToCanvas(time, xrFrame) {
+    // Ensure the previous step did not submit a frame
+    t.step( () => {
+      assert_equals(mockDisplay.getSubmitFrameCount(), 0);
+    }, "Expecting no frame was submitted during onSkipFrame");
+    // Clear the canvas
+    gl.clear(gl.COLOR_BUFFER_BIT);
+    session.requestAnimationFrame(onDrawToFramebuffer);
+  }
+  function onDrawToFramebuffer(time, xrFrame) {
+    // Ensure the previous step did not submit a frame
+    t.step( () => {
+      assert_equals(mockDisplay.getSubmitFrameCount(), 0);
+    }, "Expecting no frame was submitted during onDrawToCanvas");
+    // Clear the VRWebGLLayer framebuffer
+    gl.bindFramebuffer(gl.FRAMEBUFFER, webglLayer.framebuffer);
+    gl.clear(gl.COLOR_BUFFER_BIT);
+    // After the function returns ensure the frame was submitted.
+    window.setTimeout(() => {
+      t.step( () => {
+        assert_equals(mockDisplay.getSubmitFrameCount(), 1);
+      }, "Expecting one frame was submitted during onDrawToFramebuffer");
+      t.done();
+    }, 100);
+  }
+  session.requestAnimationFrame(onSkipFrame);
+}, fakeDisplays["Pixel"], { exclusive: true },
+"A frame should be submitted if the base layer was written to during requestAnimationFrame");
+</script>
diff --git a/third_party/WebKit/Source/core/animation/README.md b/third_party/WebKit/Source/core/animation/README.md
new file mode 100644
index 0000000..a46695a7
--- /dev/null
+++ b/third_party/WebKit/Source/core/animation/README.md
@@ -0,0 +1,279 @@
+# `Source/core/animation`
+
+This directory contains the main thread animation engine. This implements the
+Web Animations timing model that drives CSS Animations, Transitions and exposes
+the Web Animations API (`element.animate()`) to Javascript.
+
+## Contacts
+
+As of 2018 Blink animations is maintained by the
+[cc/ team](https://cs.chromium.org/chromium/src/cc/OWNERS).
+
+## Specifications Implemented
+
+*   [CSS Animations Level 1](https://www.w3.org/TR/css-animations-1/)
+*   [CSS Transitions](https://www.w3.org/TR/css-transitions-1/)
+*   [Web Animations](https://www.w3.org/TR/web-animations-1/)
+*   [CSS Properties and Values API Level 1 - Animation Behavior of Custom Properties](https://www.w3.org/TR/css-properties-values-api-1/#animation-behavior-of-custom-properties)
+*   Individual CSS property animation behaviour [e.g. transform interolation](https://www.w3.org/TR/css-transforms-1/#interpolation-of-transforms).
+
+## Integration with Chromium
+
+The Blink animation engine has three main integration points:
+
+*   ### [Blink's Style engine](../css)
+
+    The most user visible functionality of the animation engine is animating
+    CSS values. This means animations have a place in the [CSS cascade][] and
+    influence the [ComputedStyle][]s returned by [styleForElement()][].
+
+    The implementation for this lives under [ApplyAnimatedStandardProperties()][]
+    for standard properties and [ApplyAnimatedCustomProperties()][] for custom
+    properties. Custom properties have more complex application logic due to
+    dynamic dependencies introduced by [variable references].
+
+    Animations can be controlled by CSS via the [`animation`](https://www.w3.org/TR/css-animations-1/#animation)
+    and [`transition`](https://www.w3.org/TR/css-transitions-1/#transition-shorthand-property) properties.
+    In code this happens when [styleForElement()][] uses [CalculateAnimationUpdate()][]
+    and [CalculateTransitionUpdate()][] to build a [set of mutations][] to make
+    to the animation engine which gets [applied later][].
+
+[CSS cascade]: https://www.w3.org/TR/css-cascade-3/#cascade-origin
+[ComputedStyle]: https://cs.chromium.org/search/?q=class:blink::ComputedStyle$
+[styleForElement()]: https://cs.chromium.org/search/?q=function:StyleResolver::styleForElement
+[ApplyAnimatedStandardProperties()]: https://cs.chromium.org/?type=cs&q=function:StyleResolver::ApplyAnimatedStandardProperties
+[ApplyAnimatedCustomProperties()]: https://cs.chromium.org/?type=cs&q=function:ApplyAnimatedCustomProperties
+[variable references]: https://www.w3.org/TR/css-variables-1/#using-variables
+[CalculateAnimationUpdate()]: https://cs.chromium.org/search/?q=function:CSSAnimations::CalculateAnimationUpdate
+[CalculateTransitionUpdate()]: https://cs.chromium.org/search/?q=function:CSSAnimations::CalculateTransitionUpdate
+[MaybeApplyPendingUpdate()]: https://cs.chromium.org/search/?q=function:CSSAnimations::MaybeApplyPendingUpdate
+[set of mutations]: https://cs.chromium.org/search/?q=class:CSSAnimationUpdate
+[applied later]: https://cs.chromium.org/search/?q=function:Element::StyleForLayoutObject+MaybeApplyPendingUpdate
+
+*   ### [Chromium's Compositor](../../../../../cc/README.md)
+
+    Blink uses a multi-threaded LayerTreeHost to render websites as a tree of
+    layers. The compositor creates frames on a separate thread which maintains a
+    copy of Blinks layers and can implement some effects without involving Blink
+    (i.e. while Blink is busy). In particular, the
+    [compositor animations infrastructure](../../../../../cc/animations/README.md)
+    is capable of implementing a subset of web animations.
+
+    #### Compositable animations
+
+    A subset of style properties (currently transform, opacity, filter, and
+    backdrop-filter) can be mutated on the compositor thread. Animations that
+    mutates only these properties are a candidate for being accelerated and run
+    on compositor thread which ensures they are isolated from Blink's main
+    thread work.
+
+    Whether or not an animation can be accelerated is determined by
+    [CheckCanStartAnimationOnCompositor()][] which looks at several aspects
+    such as the composite mode, other animations affecting same property, and
+    whether the target element can be promoted and mutated in compositor.
+
+    #### Lifetime of a compositor animation
+
+    Animations that can be accelerated get added to the [PendingAnimations][]
+    list. The pending list is updates as part of document lifecycle and ensures
+    each pending animation gets a corresponding [cc::AnimationPlayer][]
+    representing the animation on the compositor. The player is initialized with
+    appropriate timing values and corresponding effects.
+
+    Note that changing that animation playback rate, start time, or effect,
+    simply adds the animation back on to the pending list and causes the
+    compositor animation to be cancelled and a new one to be started. See
+    [Animation::PreCommit()][] for more details.
+
+    An accelerated animation is still running on main thread ensuring that its
+    effective output is reflected in the Element style. So while the compositor
+    animation updates the visuals the main thread animation updates the computed
+    style. There is a special case logic to ensure updates from such accelerated
+    animations do not cause spurious commits from main to compositor (See
+    [CompositedLayerMapping::UpdateGraphicsLayerGeometry()][])
+
+    A compositor animation provide updates on its playback state changes (e.g.,
+    on start, finish, abort) to its blink counterpart via
+    [CompositorAnimationDelegate][] interface. Blink animation uses the start
+    event callback to obtain an accurate start time for the animation which is
+    important to ensure its output accurately reflects the compositor animation
+    output.
+
+[CheckCanStartAnimationOnCompositor()]: https://cs.chromium.org/search/?q=file:Animation.h+function:CheckCanStartAnimationOnCompositor
+[cc::AnimationPlayer]: https://cs.chromium.org/search/?q=file:src/cc/animation/animation_player.h+class:AnimationPlayer
+[PendingAnimations]: https://cs.chromium.org/search/?q=file:PendingAnimations.h+class:PendingAnimations
+[Animation::PreCommit()]: https://cs.chromium.org/search/?q=file:Animation.h+function:PreCommit
+[CompositorAnimationDelegate]: https://cs.chromium.org/search/?q=file:CompositorAnimationDelegate.h
+[CompositedLayerMapping::UpdateGraphicsLayerGeometry()]: https://cs.chromium.org/search/?q=file:CompositedLayerMapping.h+function:UpdateGraphicsLayerGeometry
+
+*   ### Javascript
+
+    [EffectInput](https://cs.chromium.org/chromium/src/third_party/WebKit/Source/core/animation/EffectInput.cpp)
+    contains the helper functions that are used to
+    [process a keyframe argument](https://drafts.csswg.org/web-animations/#processing-a-keyframes-argument)
+    which can take an argument of either object or array form.
+
+    [PlayStateUpdateScope](https://cs.chromium.org/chromium/src/third_party/WebKit/Source/core/animation/Animation.h?l=323):
+    whenever there is a mutation to the animation engine from JS level, this
+    gets created and the destructor has the logic that handles everything. It
+    keeps the old and new state of the animation, checks the difference and
+    mutate the properties of the animation, at the end it calls
+    SetOutdatedAnimation() to inform the animation timeline that the time state
+    of this animation is dirtied.
+
+    There are a couple of other integration points that are less critical to everyday browsing:
+
+*   ### DevTools
+
+    The animations timeline uses [InspectorAnimationAgent][] to track all active
+    animations. This class has interfaces for pausing, adjusting
+    DocumentTimeline playback rate, and seeking animations.
+
+    InspectorAnimationAgent clones the inspected animation in order to avoid
+    firing animation events, and suppresses the effects of the original
+    animation. From this point on, modifications can be made to the cloned
+    animation without having any effect on the underlying animation or its
+    listeners.
+
+[InspectorAnimationAgent]: https://cs.chromium.org/chromium/src/third_party/WebKit/Source/core/inspector/InspectorAnimationAgent.h
+
+*   ### SVG
+
+    The `element.animate()` API supports targeting SVG attributes in its
+    keyframes. This is an experimental implementation guarded by the
+    WebAnimationsSVG flag and not exposed on the web.
+
+    This feature should provide a high fidelity alternative to our SMIL
+    implementation.
+
+## Architecture
+
+### Animation Timing Model
+
+The animation engine is built around the
+[timing model](https://www.w3.org/TR/web-animations-1/#timing-model) described
+in the Web Animations spec.
+
+This describes a hierarchy of entities:
+*   DocumentTimeline: Represents the wall clock time
+    *   Animation: Represents an individual animation and when it started
+        playing.
+        *   AnimationEffect: Represents the effect an animation has during the
+            animation e.g. updating an elements color property.
+
+Time trickles down from the DocumentTimeline and is transformed at each stage to
+produce some progress fraction that can be used to apply the effects of the
+animations.
+
+For example:
+
+*   DocumentTimeline notifies that the time is 20 seconds.
+    *   Animation was started at 18 seconds and computes that it has a current
+        time of 2 seconds.
+        *   AnimationEffect has a duration of 8 seconds and computes that it has
+            a progress of 25%.
+
+            The effect is animating an element8s transform property from `none`
+            to `rotate(360deg)` so it computes the current effect to be
+            `rotate(90deg)`.
+
+### Life cycle of an animation
+
+1.  An Animation is created via CSS<sup>1</sup> or `element.animate()`.
+2.  At the start of the next frame the Animation and its AnimationEffect are
+    updated with the currentTime of the DocumentTimeline.
+3.  The AnimationEffect gets sampled with its computed localTime, pushes a
+    SampledEffect into its target element s EffectStack and marks the elements
+    style as dirty to ensure it gets updated later in the document lifecycle.
+4.  During the next style resolve on the target element all the SampledEffects
+    in its EffectStack are incorporated into building the element's
+    ComputedStyle.
+
+One key takeaway here is to note that timing updates are done in a separate
+phase to effect application. Effect application must occur during style
+resolution which is a highly complex process with a well defined place in the
+document lifecycle. Updates to animation timing will request style updates
+rather than invoke them directly.
+
+<sup>1</sup> CSS animations and transitions are actually created/destroyed
+during style resolve (step 4). There is special logic for forcing these
+animations to have their timing updated and their effects included in
+the same style resolve. An unfortunate side effect of this is that style
+resolution can cause style to get dirtied, this is currently a
+[code health bug](http://crbug.com/492887).
+
+### KeyframeEffects
+
+TODO: Describe how KeyframeEffects represent an animation's keyframes.
+
+### Keyframe Interpolations
+
+TODO: Describe how interpolation works and where to look for further details.
+
+#### InterpolationTypes
+
+TODO: Describe various interpolation types and where they are defined.
+
+#### Applying a stack of Interpolations
+
+TODO: Describe how interpolations interact with the effect stack.
+
+## Testing pointers
+
+Test new animation features using end to end web-platform-tests to ensure
+cross-browser interoperability. Use unit testing when access to chrome internals
+is required. Test chrome specific features such as compositing of animation
+using LayoutTests or unit tests.
+
+### End to end testing
+
+Features in the Web Animations spec are tested in
+[web-animations][web-animations-tests]. [Writing web platform tests][] has
+pointers for how to get started. If Chrome does not correctly implement the
+spec, add a corresponding -expected.txt file with your test listing the expected
+failure in Chrome.
+
+[Layout tests](../../../../../docs/testing/writing_layout_tests.md) are located
+in [third_party/WebKit/LayoutTests][]. These should be written when needing end
+to end testing but either when testing chrome specific features (i.e.
+non-standardized) such as compositing or when the test requires access to chrome
+internal features not easily tested by web-platform-tests.
+
+[web-animations-tests]: https://cs.chromium.org/chromium/src/third_party/WebKit/LayoutTests/external/wpt/web-animations/
+[Writing web platform tests]: ../../../../../docs/testing/web_platform_tests.md#Writing-tests
+[third_party/WebKit/LayoutTests]: https://cs.chromium.org/chromium/src/third_party/WebKit/LayoutTests/animations/
+
+### Unit testing
+
+Unit testing of animations can range from [extending Test][] when you will
+manually construct an instance of your object to [extending RenderingTest][]
+where you can load HTML, [enable compositing][] if necessary, and run assertions
+about the state.
+
+[extending Test]: https://cs.chromium.org/search/?q=public%5C+::testing::Test+file:core%5C/Animation&sq=package:chromium&type=cs
+[extending RenderingTest]: https://cs.chromium.org/search/?q=public%5C+RenderingTest+file:core%5C/animation&type=cs
+[enable compositing]: https://cs.chromium.org/chromium/src/third_party/WebKit/Source/core/animation/CompositorAnimationsTest.cpp?type=cs&sq=package:chromium&q=file:core%5C/animation%5C/.*Test%5C.cpp+EnableCompositing
+
+## Ongoing work
+
+### Properties And Values API
+
+TODO: Summarize properties and values API.
+
+### Web Animations API
+
+TODO: Summarize Web Animations API.
+
+### [Animation Worklet](../../modules/animationworklet/README.md)
+
+AnimationWorklet is a new primitive for creating high performance procedural
+animations on the web. It is being incubated as part of the
+[CSS Houdini task force](https://github.com/w3c/css-houdini-drafts/wiki), and if
+successful will be transferred to that task force for full standardization.
+
+A [WorkletAnimation][] behaves and exposes the same animation interface as other
+web animation but it allows the animation itself to be highly customized in
+Javascript by providing an `animate` callback. These animations run inside an
+isolated worklet global scope.
+
+[WorkletAnimation]: https://cs.chromium.org/search/?q=file:animationworklet/WorkletAnimation.h+class:WorkletAnimation
diff --git a/third_party/WebKit/Source/core/animation/SampledEffect.cpp b/third_party/WebKit/Source/core/animation/SampledEffect.cpp
index 0b0d3b25..c2b1262 100644
--- a/third_party/WebKit/Source/core/animation/SampledEffect.cpp
+++ b/third_party/WebKit/Source/core/animation/SampledEffect.cpp
@@ -16,6 +16,8 @@
   interpolations_.clear();
 }
 
+// Design doc:
+// https://docs.google.com/document/d/1NomOWRrGQHlynQGO64CgdqRPAAEHhi3fSa8sf0Ip6xE
 bool SampledEffect::WillNeverChange() const {
   return !effect_ || !effect_->GetAnimation();
 }
diff --git a/third_party/WebKit/Source/core/css/AtRuleCSSStyleDeclaration.cpp b/third_party/WebKit/Source/core/css/AtRuleCSSStyleDeclaration.cpp
index 6c56b03..9ab7689 100644
--- a/third_party/WebKit/Source/core/css/AtRuleCSSStyleDeclaration.cpp
+++ b/third_party/WebKit/Source/core/css/AtRuleCSSStyleDeclaration.cpp
@@ -51,7 +51,11 @@
   if (id == AtRuleDescriptorID::Invalid)
     return g_empty_string;
 
-  return descriptor_value_set_->GetPropertyCSSValue(id)->CssText();
+  const CSSValue* value = descriptor_value_set_->GetPropertyCSSValue(id);
+  if (value)
+    return value->CssText();
+
+  return g_empty_string;
 }
 
 String AtRuleCSSStyleDeclaration::getPropertyPriority(
diff --git a/third_party/WebKit/Source/core/css/CSSContentDistributionValue.cpp b/third_party/WebKit/Source/core/css/CSSContentDistributionValue.cpp
index bdb5e2a..9369769 100644
--- a/third_party/WebKit/Source/core/css/CSSContentDistributionValue.cpp
+++ b/third_party/WebKit/Source/core/css/CSSContentDistributionValue.cpp
@@ -33,12 +33,11 @@
       list->Append(*CSSIdentifierValue::Create(preference));
       list->Append(*CSSIdentifierValue::Create(CSSValueBaseline));
     } else {
+      if (overflow_ != CSSValueInvalid)
+        list->Append(*CSSIdentifierValue::Create(overflow_));
       list->Append(*CSSIdentifierValue::Create(position_));
     }
   }
-  if (overflow_ != CSSValueInvalid)
-    list->Append(*CSSIdentifierValue::Create(overflow_));
-
   return list->CustomCSSText();
 }
 
diff --git a/third_party/WebKit/Source/core/css/properties/CSSParsingUtils.cpp b/third_party/WebKit/Source/core/css/properties/CSSParsingUtils.cpp
index 67b7e5a..94ebb6e8 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSParsingUtils.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSParsingUtils.cpp
@@ -84,6 +84,18 @@
       id);
 }
 
+CSSIdentifierValue* ConsumeOverflowPositionKeyword(CSSParserTokenRange& range) {
+  return IsOverflowKeyword(range.Peek().Id())
+             ? CSSPropertyParserHelpers::ConsumeIdent(range)
+             : nullptr;
+}
+
+CSSIdentifierValue* ConsumeContentPositionKeyword(CSSParserTokenRange& range) {
+  return IsContentPositionKeyword(range.Peek().Id())
+             ? CSSPropertyParserHelpers::ConsumeIdent(range)
+             : nullptr;
+}
+
 bool IsBaselineKeyword(CSSValueID id) {
   return CSSPropertyParserHelpers::IdentMatches<CSSValueFirst, CSSValueLast,
                                                 CSSValueBaseline>(id);
@@ -542,19 +554,12 @@
   if (IsBaselineKeyword(id))
     return ConsumeBaselineKeyword(range);
 
-  CSSIdentifierValue* overflow_position =
-      CSSPropertyParserHelpers::ConsumeIdent<CSSValueUnsafe, CSSValueSafe>(
-          range);
+  CSSIdentifierValue* overflow_position = ConsumeOverflowPositionKeyword(range);
   CSSIdentifierValue* self_position = ConsumeSelfPositionKeyword(range);
   if (!self_position)
     return nullptr;
-  if (!overflow_position) {
-    overflow_position =
-        CSSPropertyParserHelpers::ConsumeIdent<CSSValueUnsafe, CSSValueSafe>(
-            range);
-  }
   if (overflow_position) {
-    return CSSValuePair::Create(self_position, overflow_position,
+    return CSSValuePair::Create(overflow_position, self_position,
                                 CSSValuePair::kDropIdenticalValues);
   }
   return self_position;
@@ -588,40 +593,21 @@
         CSSValueInvalid, GetBaselineKeyword(*baseline), CSSValueInvalid);
   }
 
-  CSSValueID distribution = CSSValueInvalid;
-  CSSValueID position = CSSValueInvalid;
-  CSSValueID overflow = CSSValueInvalid;
-  do {
-    if (IsContentDistributionKeyword(id)) {
-      if (distribution != CSSValueInvalid)
-        return nullptr;
-      distribution = id;
-    } else if (IsContentPositionKeyword(id)) {
-      if (position != CSSValueInvalid)
-        return nullptr;
-      position = id;
-    } else if (IsOverflowKeyword(id)) {
-      if (overflow != CSSValueInvalid)
-        return nullptr;
-      overflow = id;
-    } else {
-      return nullptr;
-    }
+  if (IsContentDistributionKeyword(id)) {
     range.ConsumeIncludingWhitespace();
-    id = range.Peek().Id();
-  } while (!range.AtEnd());
+    return CSSContentDistributionValue::Create(id, CSSValueInvalid,
+                                               CSSValueInvalid);
+  }
 
-  // The grammar states that we should have at least <content-distribution> or
-  // <content-position>.
-  if (position == CSSValueInvalid && distribution == CSSValueInvalid)
+  CSSIdentifierValue* overflow = ConsumeOverflowPositionKeyword(range);
+  CSSIdentifierValue* position = ConsumeContentPositionKeyword(range);
+  if (!position)
     return nullptr;
 
-  // The grammar states that <overflow-position> must be associated to
-  // <content-position>.
-  if (overflow != CSSValueInvalid && position == CSSValueInvalid)
-    return nullptr;
-
-  return CSSContentDistributionValue::Create(distribution, position, overflow);
+  CSSValueID overflow_id = overflow ? overflow->GetValueID() : CSSValueInvalid;
+  CSSValueID position_id = position->GetValueID();
+  return CSSContentDistributionValue::Create(CSSValueInvalid, position_id,
+                                             overflow_id);
 }
 
 CSSValue* ConsumeSimplifiedContentPosition(CSSParserTokenRange& range) {
diff --git a/third_party/WebKit/Source/core/css/properties/ComputedStyleUtils.cpp b/third_party/WebKit/Source/core/css/properties/ComputedStyleUtils.cpp
index bc85a76..f671701 100644
--- a/third_party/WebKit/Source/core/css/properties/ComputedStyleUtils.cpp
+++ b/third_party/WebKit/Source/core/css/properties/ComputedStyleUtils.cpp
@@ -640,11 +640,11 @@
                               CSSIdentifierValue::Create(CSSValueBaseline),
                               CSSValuePair::kDropIdenticalValues));
   } else {
+    if (data.GetPosition() >= ItemPosition::kCenter &&
+        data.Overflow() != OverflowAlignment::kDefault)
+      result->Append(*CSSIdentifierValue::Create(data.Overflow()));
     result->Append(*CSSIdentifierValue::Create(data.GetPosition()));
   }
-  if (data.GetPosition() >= ItemPosition::kCenter &&
-      data.Overflow() != OverflowAlignment::kDefault)
-    result->Append(*CSSIdentifierValue::Create(data.Overflow()));
   DCHECK_LE(result->length(), 2u);
   return result;
 }
@@ -672,14 +672,14 @@
                                 CSSValuePair::kDropIdenticalValues));
       break;
     default:
+      // Handle overflow-alignment (only allowed for content-position values)
+      if ((data.GetPosition() >= ContentPosition::kCenter ||
+           data.Distribution() != ContentDistributionType::kDefault) &&
+          data.Overflow() != OverflowAlignment::kDefault)
+        result->Append(*CSSIdentifierValue::Create(data.Overflow()));
       result->Append(*CSSIdentifierValue::Create(data.GetPosition()));
   }
 
-  // Handle overflow-alignment (only allowed for content-position values)
-  if ((data.GetPosition() >= ContentPosition::kCenter ||
-       data.Distribution() != ContentDistributionType::kDefault) &&
-      data.Overflow() != OverflowAlignment::kDefault)
-    result->Append(*CSSIdentifierValue::Create(data.Overflow()));
   DCHECK_GT(result->length(), 0u);
   DCHECK_LE(result->length(), 3u);
   return result;
diff --git a/third_party/WebKit/Source/core/css/resolver/StyleBuilderConverter.cpp b/third_party/WebKit/Source/core/css/resolver/StyleBuilderConverter.cpp
index 188cad7f..1a46f0e 100644
--- a/third_party/WebKit/Source/core/css/resolver/StyleBuilderConverter.cpp
+++ b/third_party/WebKit/Source/core/css/resolver/StyleBuilderConverter.cpp
@@ -698,10 +698,10 @@
                CSSValueLast) {
       alignment_data.SetPosition(ItemPosition::kLastBaseline);
     } else {
-      alignment_data.SetPosition(
-          ToCSSIdentifierValue(pair.First()).ConvertTo<ItemPosition>());
       alignment_data.SetOverflow(
-          ToCSSIdentifierValue(pair.Second()).ConvertTo<OverflowAlignment>());
+          ToCSSIdentifierValue(pair.First()).ConvertTo<OverflowAlignment>());
+      alignment_data.SetPosition(
+          ToCSSIdentifierValue(pair.Second()).ConvertTo<ItemPosition>());
     }
   } else {
     alignment_data.SetPosition(
diff --git a/third_party/WebKit/Source/core/dom/Document.cpp b/third_party/WebKit/Source/core/dom/Document.cpp
index 06cd839..939ffe2 100644
--- a/third_party/WebKit/Source/core/dom/Document.cpp
+++ b/third_party/WebKit/Source/core/dom/Document.cpp
@@ -5048,15 +5048,21 @@
     }
   }
 
-  if (!body())
-    return;
-
-  if (margin_width != owner->MarginWidth())
-    body()->SetIntegralAttribute(marginwidthAttr, margin_width);
-  if (margin_height != owner->MarginHeight())
-    body()->SetIntegralAttribute(marginheightAttr, margin_height);
-  if (scrolling_mode != owner->ScrollingMode() && View())
+  // body() may become null as a result of modification event listeners, so we
+  // check before each call.
+  if (margin_width != owner->MarginWidth()) {
+    if (auto* body_element = body()) {
+      body_element->SetIntegralAttribute(marginwidthAttr, margin_width);
+    }
+  }
+  if (margin_height != owner->MarginHeight()) {
+    if (auto* body_element = body()) {
+      body_element->SetIntegralAttribute(marginheightAttr, margin_height);
+    }
+  }
+  if (scrolling_mode != owner->ScrollingMode() && View()) {
     View()->SetNeedsLayout();
+  }
 }
 
 bool Document::IsInInvisibleSubframe() const {
diff --git a/third_party/WebKit/Source/core/dom/Element.cpp b/third_party/WebKit/Source/core/dom/Element.cpp
index daeae07..d86cd4f7 100644
--- a/third_party/WebKit/Source/core/dom/Element.cpp
+++ b/third_party/WebKit/Source/core/dom/Element.cpp
@@ -2158,24 +2158,21 @@
   if (local_change != kNoChange)
     UpdateCallbackSelectors(old_style.get(), new_style.get());
 
-  if (LayoutObject* layout_object = this->GetLayoutObject()) {
-    if (local_change != kNoChange) {
-      layout_object->SetStyle(new_style.get());
-    } else {
-      // Although no change occurred, we use the new style so that the cousin
-      // style sharing code won't get fooled into believing this style is the
-      // same.
-      // FIXME: We may be able to remove this hack, see discussion in
-      // https://codereview.chromium.org/30453002/
+  if (LayoutObject* layout_object = GetLayoutObject()) {
+    // kNoChange may mean that the computed style didn't change, but there are
+    // additional flags in ComputedStyle which may have changed. For instance,
+    // the AffectedBy* flags. We don't need to go through the visual
+    // invalidation diffing in that case, but we replace the old ComputedStyle
+    // object with the new one to ensure the mentioned flags are up to date.
+    if (local_change == kNoChange)
       layout_object->SetStyleInternal(new_style.get());
-    }
+    else
+      layout_object->SetStyle(new_style.get());
   } else {
-    if (local_change != kNoChange) {
-      if (ShouldStoreNonLayoutObjectComputedStyle(*new_style))
-        StoreNonLayoutObjectComputedStyle(new_style);
-      else if (HasRareData())
-        GetElementRareData()->ClearComputedStyle();
-    }
+    if (ShouldStoreNonLayoutObjectComputedStyle(*new_style))
+      StoreNonLayoutObjectComputedStyle(new_style);
+    else if (HasRareData())
+      GetElementRareData()->ClearComputedStyle();
   }
 
   if (GetStyleChangeType() >= kSubtreeStyleChange)
diff --git a/third_party/WebKit/Source/core/dom/FlatTreeTraversal.h b/third_party/WebKit/Source/core/dom/FlatTreeTraversal.h
index ca7f4d7..383941d 100644
--- a/third_party/WebKit/Source/core/dom/FlatTreeTraversal.h
+++ b/third_party/WebKit/Source/core/dom/FlatTreeTraversal.h
@@ -194,7 +194,7 @@
     const Node& node,
     ParentTraversalDetails* details) {
   if (RuntimeEnabledFeatures::IncrementalShadowDOMEnabled())
-    return FlatTreeTraversalNg::Parent(node);
+    return FlatTreeTraversalNg::Parent(node, details);
   AssertPrecondition(node);
   ContainerNode* result = TraverseParent(node, details);
   AssertPostcondition(result);
diff --git a/third_party/WebKit/Source/core/dom/FlatTreeTraversalTest.cpp b/third_party/WebKit/Source/core/dom/FlatTreeTraversalTest.cpp
index 77d928b7..d96825df3 100644
--- a/third_party/WebKit/Source/core/dom/FlatTreeTraversalTest.cpp
+++ b/third_party/WebKit/Source/core/dom/FlatTreeTraversalTest.cpp
@@ -722,4 +722,21 @@
   EXPECT_EQ(nullptr, FlatTreeTraversal::PreviousSibling(*fallback_x));
 }
 
+TEST_F(FlatTreeTraversalTest, v0ParentDetailsInsertionPoint) {
+  const char* main_html = "<div><span></span></div>";
+  const char* shadow_html = "<content></content>";
+
+  SetupSampleHTML(main_html, shadow_html, 0);
+
+  Element* span = GetDocument().body()->QuerySelector("span");
+  ASSERT_TRUE(span);
+
+  FlatTreeTraversal::ParentTraversalDetails details;
+  EXPECT_FALSE(details.GetInsertionPoint());
+
+  ContainerNode* parent = FlatTreeTraversal::Parent(*span, &details);
+  ASSERT_TRUE(parent);
+  EXPECT_TRUE(details.GetInsertionPoint());
+}
+
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/dom/events/EventPath.cpp b/third_party/WebKit/Source/core/dom/events/EventPath.cpp
index 315c468..6d416f7 100644
--- a/third_party/WebKit/Source/core/dom/events/EventPath.cpp
+++ b/third_party/WebKit/Source/core/dom/events/EventPath.cpp
@@ -269,13 +269,13 @@
                                        EventTarget* related_target) {
   if (!related_target)
     return;
-  Node* related_node = related_target->ToNode();
-  if (!related_node)
+  Node* related_target_node = related_target->ToNode();
+  if (!related_target_node)
     return;
-  if (target.GetDocument() != related_node->GetDocument())
+  if (target.GetDocument() != related_target_node->GetDocument())
     return;
-  RetargetRelatedTarget(*related_node);
-  ShrinkForRelatedTarget(target);
+  RetargetRelatedTarget(*related_target_node);
+  ShrinkForRelatedTarget(target, *related_target_node);
 }
 
 void EventPath::RetargetRelatedTarget(const Node& related_target_node) {
@@ -290,22 +290,37 @@
   }
 }
 
-bool EventPath::ShouldStopEventPath(EventTarget& current_target,
-                                    EventTarget& current_related_target,
-                                    const Node& target) {
-  if (&current_target != &current_related_target)
+namespace {
+
+bool ShouldStopEventPath(EventTarget& adjusted_target,
+                         EventTarget& adjusted_related_target,
+                         const Node& event_target_node,
+                         const Node& event_related_target_node) {
+  if (&adjusted_target != &adjusted_related_target)
     return false;
-  if (event_->isTrusted())
-    return true;
-  Node* current_target_node = current_target.ToNode();
-  if (!current_target_node)
+  Node* adjusted_target_node = adjusted_target.ToNode();
+  if (!adjusted_target_node)
     return false;
-  return current_target_node->GetTreeScope() != target.GetTreeScope();
+  Node* adjusted_related_target_node = adjusted_related_target.ToNode();
+  if (!adjusted_related_target_node)
+    return false;
+  // Events should be dispatched at least until its root even when event's
+  // target and related_target are identical.
+  if (adjusted_target_node->GetTreeScope() ==
+          event_target_node.GetTreeScope() &&
+      adjusted_related_target_node->GetTreeScope() ==
+          event_related_target_node.GetTreeScope())
+    return false;
+  return true;
 }
 
-void EventPath::ShrinkForRelatedTarget(const Node& target) {
+}  // anonymous namespace
+
+void EventPath::ShrinkForRelatedTarget(const Node& event_target_node,
+                                       const Node& event_related_target_node) {
   for (size_t i = 0; i < size(); ++i) {
-    if (ShouldStopEventPath(*at(i).Target(), *at(i).RelatedTarget(), target)) {
+    if (ShouldStopEventPath(*at(i).Target(), *at(i).RelatedTarget(),
+                            event_target_node, event_related_target_node)) {
       Shrink(i);
       break;
     }
diff --git a/third_party/WebKit/Source/core/dom/events/EventPath.h b/third_party/WebKit/Source/core/dom/events/EventPath.h
index 374c6bd..2bb1b74b 100644
--- a/third_party/WebKit/Source/core/dom/events/EventPath.h
+++ b/third_party/WebKit/Source/core/dom/events/EventPath.h
@@ -100,10 +100,6 @@
   void CalculateAdjustedTargets();
   void CalculateTreeOrderAndSetNearestAncestorClosedTree();
 
-  bool ShouldStopEventPath(EventTarget& current_target,
-                           EventTarget& current_related_target,
-                           const Node& target);
-
   void Shrink(size_t new_size) {
     DCHECK(!window_event_context_);
     node_event_contexts_.Shrink(new_size);
@@ -111,7 +107,8 @@
 
   void RetargetRelatedTarget(const Node& related_target_node);
 
-  void ShrinkForRelatedTarget(const Node& target);
+  void ShrinkForRelatedTarget(const Node& event_target_node,
+                              const Node& event_related_target_node);
 
   void AdjustTouchList(const TouchList*,
                        HeapVector<Member<TouchList>> adjusted_touch_list,
diff --git a/third_party/WebKit/Source/core/frame/LocalFrameView.cpp b/third_party/WebKit/Source/core/frame/LocalFrameView.cpp
index 36bd744..2a39742 100644
--- a/third_party/WebKit/Source/core/frame/LocalFrameView.cpp
+++ b/third_party/WebKit/Source/core/frame/LocalFrameView.cpp
@@ -2054,14 +2054,11 @@
   }
 }
 
-bool LocalFrameView::ComputeCompositedSelection(
-    LocalFrame& frame,
-    CompositedSelection& selection) {
+static CompositedSelection ComputeCompositedSelection(LocalFrame& frame) {
   if (!frame.View() || frame.View()->ShouldThrottleRendering())
-    return false;
+    return {};
 
-  selection = RenderedPosition::ComputeCompositedSelection(frame.Selection());
-  return selection.type != kNoSelection;
+  return RenderedPosition::ComputeCompositedSelection(frame.Selection());
 }
 
 void LocalFrameView::UpdateCompositedSelectionIfNeeded() {
@@ -2073,7 +2070,6 @@
   Page* page = GetFrame().GetPage();
   DCHECK(page);
 
-  CompositedSelection selection;
   LocalFrame* focused_frame = page->GetFocusController().FocusedFrame();
   LocalFrame* local_frame =
       (focused_frame &&
@@ -2081,22 +2077,26 @@
           ? focused_frame
           : nullptr;
 
-  if (local_frame && ComputeCompositedSelection(*local_frame, selection)) {
-    page->GetChromeClient().UpdateCompositedSelection(local_frame, selection);
-  } else {
-    if (!local_frame) {
-      // Clearing the mainframe when there is no focused frame (and hence
-      // no localFrame) is legacy behaviour, and implemented here to
-      // satisfy ParameterizedWebFrameTest.CompositedSelectionBoundsCleared's
-      // first check that the composited selection has been cleared even
-      // though no frame has focus yet. If this is not desired, then the
-      // expectation needs to be removed from the test.
-      local_frame = &frame_->LocalFrameRoot();
+  if (local_frame) {
+    const CompositedSelection& selection =
+        ComputeCompositedSelection(*local_frame);
+    if (selection.type != kNoSelection) {
+      page->GetChromeClient().UpdateCompositedSelection(local_frame, selection);
+      return;
     }
-
-    if (local_frame)
-      page->GetChromeClient().ClearCompositedSelection(local_frame);
   }
+
+  if (!local_frame) {
+    // Clearing the mainframe when there is no focused frame (and hence
+    // no localFrame) is legacy behaviour, and implemented here to
+    // satisfy ParameterizedWebFrameTest.CompositedSelectionBoundsCleared's
+    // first check that the composited selection has been cleared even
+    // though no frame has focus yet. If this is not desired, then the
+    // expectation needs to be removed from the test.
+    local_frame = &frame_->LocalFrameRoot();
+  }
+  DCHECK(local_frame);
+  page->GetChromeClient().ClearCompositedSelection(local_frame);
 }
 
 void LocalFrameView::SetNeedsCompositingUpdate(
diff --git a/third_party/WebKit/Source/core/frame/LocalFrameView.h b/third_party/WebKit/Source/core/frame/LocalFrameView.h
index de07c0f1..67f00b2 100644
--- a/third_party/WebKit/Source/core/frame/LocalFrameView.h
+++ b/third_party/WebKit/Source/core/frame/LocalFrameView.h
@@ -95,7 +95,6 @@
 class TransformState;
 class WebPluginContainerImpl;
 struct AnnotatedRegionValue;
-struct CompositedSelection;
 struct IntrinsicSizingInfo;
 struct WebScrollIntoViewParams;
 
@@ -1099,7 +1098,6 @@
 
   void UpdateLayersAndCompositingAfterScrollIfNeeded();
 
-  static bool ComputeCompositedSelection(LocalFrame&, CompositedSelection&);
   void UpdateCompositedSelectionIfNeeded();
   void SetNeedsCompositingUpdate(CompositingUpdateType);
 
diff --git a/third_party/WebKit/Source/core/frame/MHTMLTest.cpp b/third_party/WebKit/Source/core/frame/MHTMLTest.cpp
index cb1fa70..37f992a4 100644
--- a/third_party/WebKit/Source/core/frame/MHTMLTest.cpp
+++ b/third_party/WebKit/Source/core/frame/MHTMLTest.cpp
@@ -157,13 +157,29 @@
     LineReader line_reader(
         std::string(mhtml_data->data(), mhtml_data->length()));
     std::string line;
-    while (line_reader.GetNextLine(&line) && line.length()) {
+    line_reader.GetNextLine(&line);
+    while (line.length()) {
+      // Peek next line to see if it starts with soft line break. If yes, append
+      // to current line.
+      std::string next_line;
+      while (true) {
+        line_reader.GetNextLine(&next_line);
+        if (next_line.length() > 1 &&
+            (next_line[0] == ' ' || next_line[0] == '\t')) {
+          line += &(next_line.at(1));
+          continue;
+        }
+        break;
+      }
+
       std::string::size_type pos = line.find(':');
       if (pos == std::string::npos)
         continue;
       std::string key = line.substr(0, pos);
       std::string value = line.substr(pos + 2);
       mhtml_headers.emplace(key, value);
+
+      line = next_line;
     }
     return mhtml_headers;
   }
@@ -251,14 +267,16 @@
 
   EXPECT_EQ("<Saved by Blink>", mhtml_headers["From"]);
   EXPECT_FALSE(mhtml_headers["Date"].empty());
-  EXPECT_EQ("multipart/related;", mhtml_headers["Content-Type"]);
+  EXPECT_EQ(
+      "multipart/related;type=\"text/html\";boundary=\"boundary-example\"",
+      mhtml_headers["Content-Type"]);
   EXPECT_EQ("abc", mhtml_headers["Subject"]);
   EXPECT_EQ(kURL, mhtml_headers["Snapshot-Content-Location"]);
 }
 
 TEST_F(MHTMLTest, TestMHTMLHeadersWithTitleContainingNonPrintableCharacters) {
   const char kURL[] = "http://www.example.com/";
-  const char kTitle[] = u8"abc=\u261D\U0001F3FB";
+  const char kTitle[] = "abc \t=\xe2\x98\x9d\xf0\x9f\x8f\xbb";
   AddTestResources();
   scoped_refptr<RawData> data =
       Serialize(ToKURL(kURL), String::FromUTF8(kTitle), "text/html",
@@ -268,12 +286,43 @@
 
   EXPECT_EQ("<Saved by Blink>", mhtml_headers["From"]);
   EXPECT_FALSE(mhtml_headers["Date"].empty());
-  EXPECT_EQ("multipart/related;", mhtml_headers["Content-Type"]);
-  EXPECT_EQ("=?utf-8?Q?abc=3D=E2=98=9D=F0=9F=8F=BB?=",
+  EXPECT_EQ(
+      "multipart/related;type=\"text/html\";boundary=\"boundary-example\"",
+      mhtml_headers["Content-Type"]);
+  EXPECT_EQ("=?utf-8?Q?abc=20=09=3D=E2=98=9D=F0=9F=8F=BB?=",
             mhtml_headers["Subject"]);
   EXPECT_EQ(kURL, mhtml_headers["Snapshot-Content-Location"]);
 }
 
+TEST_F(MHTMLTest,
+       TestMHTMLHeadersWithLongTitleContainingNonPrintableCharacters) {
+  const char kURL[] = "http://www.example.com/";
+  const char kTitle[] =
+      "01234567890123456789012345678901234567890123456789"
+      "01234567890123456789012345678901234567890123456789"
+      " \t=\xe2\x98\x9d\xf0\x9f\x8f\xbb";
+  AddTestResources();
+  scoped_refptr<RawData> data =
+      Serialize(ToKURL(kURL), String::FromUTF8(kTitle), "text/html",
+                MHTMLArchive::kUseDefaultEncoding);
+
+  std::map<std::string, std::string> mhtml_headers = ExtractMHTMLHeaders(data);
+
+  EXPECT_EQ("<Saved by Blink>", mhtml_headers["From"]);
+  EXPECT_FALSE(mhtml_headers["Date"].empty());
+  EXPECT_EQ(
+      "multipart/related;type=\"text/html\";boundary=\"boundary-example\"",
+      mhtml_headers["Content-Type"]);
+  EXPECT_EQ(
+      "=?utf-8?Q?012345678901234567890123456789"
+      "012345678901234567890123456789012?="
+      "=?utf-8?Q?345678901234567890123456789"
+      "0123456789=20=09=3D=E2=98=9D=F0=9F?="
+      "=?utf-8?Q?=8F=BB?=",
+      mhtml_headers["Subject"]);
+  EXPECT_EQ(kURL, mhtml_headers["Snapshot-Content-Location"]);
+}
+
 TEST_F(MHTMLTest, TestMHTMLEncoding) {
   const char kURL[] = "http://www.example.com";
   AddTestResources();
@@ -466,4 +515,24 @@
   EXPECT_FALSE(document->getElementById("fm")->IsDisabledFormControl());
 }
 
+TEST_F(MHTMLTest, LoadMHTMLContainingSoftLineBreaks) {
+  const char kURL[] = "http://www.example.com";
+
+  // Register the mocked frame and load it.
+  RegisterMockedURLLoad(kURL, "soft_line_break.mht");
+  LoadURLInTopFrame(ToKURL(kURL));
+  ASSERT_TRUE(GetPage());
+  LocalFrame* frame = ToLocalFrame(GetPage()->MainFrame());
+  ASSERT_TRUE(frame);
+  // We should not have problem to concatenate header lines separated by soft
+  // line breaks.
+  Document* document = frame->GetDocument();
+  ASSERT_TRUE(document);
+
+  // We should not have problem to concatenate body lines separated by soft
+  // line breaks.
+  EXPECT_TRUE(document->getElementById(
+      "AVeryLongID012345678901234567890123456789012345678901234567890End"));
+}
+
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/html/HTMLLinkElement.idl b/third_party/WebKit/Source/core/html/HTMLLinkElement.idl
index 31f7cb0..d9150c5 100644
--- a/third_party/WebKit/Source/core/html/HTMLLinkElement.idl
+++ b/third_party/WebKit/Source/core/html/HTMLLinkElement.idl
@@ -28,7 +28,7 @@
     [Reflect, URL] attribute USVString href;
     [CEReactions, Reflect, ReflectOnly=("anonymous","use-credentials"), ReflectEmpty="anonymous", ReflectInvalid="anonymous"] attribute DOMString? crossOrigin;
     [CEReactions, Reflect] attribute DOMString rel;
-    [CEReactions, PutForwards=value] readonly attribute DOMTokenList relList;
+    [SameObject, PutForwards=value] readonly attribute DOMTokenList relList;
     [CEReactions, Reflect] attribute DOMString media;
     [CEReactions, Reflect] attribute DOMString hreflang;
     [CEReactions, Reflect] attribute DOMString type;
diff --git a/third_party/WebKit/Source/core/html/forms/CheckboxInputType.cpp b/third_party/WebKit/Source/core/html/forms/CheckboxInputType.cpp
index b950719..eef5e5f8 100644
--- a/third_party/WebKit/Source/core/html/forms/CheckboxInputType.cpp
+++ b/third_party/WebKit/Source/core/html/forms/CheckboxInputType.cpp
@@ -86,7 +86,7 @@
     GetElement().setIndeterminate(state.indeterminate);
     GetElement().setChecked(state.checked);
   } else {
-    GetElement().DispatchChangeEventIfNeeded();
+    GetElement().DispatchInputAndChangeEventIfNeeded();
   }
   is_in_click_handler_ = false;
   // The work we did in willDispatchClick was default handling.
diff --git a/third_party/WebKit/Source/core/html/forms/HTMLInputElement.cpp b/third_party/WebKit/Source/core/html/forms/HTMLInputElement.cpp
index 860a7d0..93abefc 100644
--- a/third_party/WebKit/Source/core/html/forms/HTMLInputElement.cpp
+++ b/third_party/WebKit/Source/core/html/forms/HTMLInputElement.cpp
@@ -960,6 +960,14 @@
     DispatchChangeEvent();
 }
 
+void HTMLInputElement::DispatchInputAndChangeEventIfNeeded() {
+  if (isConnected() &&
+      input_type_->ShouldSendChangeEventAfterCheckedChanged()) {
+    DispatchInputEvent();
+    DispatchChangeEvent();
+  }
+}
+
 bool HTMLInputElement::checked() const {
   input_type_->ReadingChecked();
   return is_checked_;
diff --git a/third_party/WebKit/Source/core/html/forms/HTMLInputElement.h b/third_party/WebKit/Source/core/html/forms/HTMLInputElement.h
index 37504496c..a88fdad 100644
--- a/third_party/WebKit/Source/core/html/forms/HTMLInputElement.h
+++ b/third_party/WebKit/Source/core/html/forms/HTMLInputElement.h
@@ -112,6 +112,7 @@
   bool checked() const;
   void setChecked(bool, TextFieldEventBehavior = kDispatchNoEvent);
   void DispatchChangeEventIfNeeded();
+  void DispatchInputAndChangeEventIfNeeded();
 
   // 'indeterminate' is a state independent of the checked state that causes the
   // control to draw in a way that hides the actual state.
diff --git a/third_party/WebKit/Source/core/layout/LayoutInline.cpp b/third_party/WebKit/Source/core/layout/LayoutInline.cpp
index 35bffdc0..d958b72 100644
--- a/third_party/WebKit/Source/core/layout/LayoutInline.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutInline.cpp
@@ -655,6 +655,14 @@
 
 template <typename GeneratorContext>
 void LayoutInline::GenerateLineBoxRects(GeneratorContext& yield) const {
+  if (const NGPhysicalBoxFragment* box_fragment =
+          EnclosingBlockFlowFragmentOf(*this)) {
+    const auto& descendants =
+        NGInlineFragmentTraversal::SelfFragmentsOf(*box_fragment, this);
+    for (const auto& descendant : descendants)
+      yield(descendant.RectInContainerBox().ToLayoutRect());
+    return;
+  }
   if (!AlwaysCreateLineBoxes()) {
     GenerateCulledLineBoxRects(yield, this);
   } else if (InlineFlowBox* curr = FirstLineBox()) {
diff --git a/third_party/WebKit/Source/core/layout/LayoutObject.cpp b/third_party/WebKit/Source/core/layout/LayoutObject.cpp
index c06f4009..36f1b34 100644
--- a/third_party/WebKit/Source/core/layout/LayoutObject.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutObject.cpp
@@ -1624,16 +1624,8 @@
 DISABLE_CFI_PERF
 void LayoutObject::SetStyle(scoped_refptr<ComputedStyle> style) {
   DCHECK(style);
-
-  if (style_ == style) {
-    // We need to run through adjustStyleDifference() for iframes, plugins, and
-    // canvas so style sharing is disabled for them. That should ensure that we
-    // never hit this code path.
-    DCHECK(!IsLayoutIFrame());
-    DCHECK(!IsEmbeddedObject());
-    DCHECK(!IsCanvas());
+  if (style_ == style)
     return;
-  }
 
   StyleDifference diff;
   if (style_)
diff --git a/third_party/WebKit/Source/core/loader/ThreadableLoaderTest.cpp b/third_party/WebKit/Source/core/loader/ThreadableLoaderTest.cpp
index f5e0841..9db8df0 100644
--- a/third_party/WebKit/Source/core/loader/ThreadableLoaderTest.cpp
+++ b/third_party/WebKit/Source/core/loader/ThreadableLoaderTest.cpp
@@ -234,8 +234,7 @@
  public:
   WebWorkerFetchContextForTest(KURL site_for_cookies)
       : site_for_cookies_(site_for_cookies.Copy()) {}
-  void InitializeOnWorkerThread(
-      scoped_refptr<base::SingleThreadTaskRunner>) override {}
+  void InitializeOnWorkerThread() override {}
 
   std::unique_ptr<WebURLLoaderFactory> CreateURLLoaderFactory() override {
     return std::make_unique<WebURLLoaderFactoryWithMock>(
diff --git a/third_party/WebKit/Source/core/loader/WorkerFetchContext.cpp b/third_party/WebKit/Source/core/loader/WorkerFetchContext.cpp
index 0448661..5d607fa2 100644
--- a/third_party/WebKit/Source/core/loader/WorkerFetchContext.cpp
+++ b/third_party/WebKit/Source/core/loader/WorkerFetchContext.cpp
@@ -92,7 +92,7 @@
       loading_task_runner_(
           global_scope_->GetTaskRunner(TaskType::kUnspecedLoading)),
       save_data_enabled_(GetNetworkStateNotifier().SaveDataEnabled()) {
-  web_context_->InitializeOnWorkerThread(loading_task_runner_);
+  web_context_->InitializeOnWorkerThread();
   std::unique_ptr<blink::WebDocumentSubresourceFilter> web_filter =
       web_context_->TakeSubresourceFilter();
   if (web_filter) {
diff --git a/third_party/WebKit/Source/core/page/FocusController.cpp b/third_party/WebKit/Source/core/page/FocusController.cpp
index 33ab688a..0fc19698 100644
--- a/third_party/WebKit/Source/core/page/FocusController.cpp
+++ b/third_party/WebKit/Source/core/page/FocusController.cpp
@@ -1346,7 +1346,11 @@
     Node& container,
     const LayoutRect& starting_rect,
     WebFocusType type,
-    FocusCandidate& closest) {
+    FocusCandidate& closest,
+    const SkipList& already_checked) {
+  if (already_checked.Contains(&container))
+    return;
+
   Element* focused_element =
       (FocusedFrame() && FocusedFrame()->GetDocument())
           ? FocusedFrame()->GetDocument()->FocusedElement()
@@ -1369,6 +1373,9 @@
     if (!element->IsKeyboardFocusable() && !IsNavigableContainer(element, type))
       continue;
 
+    if (already_checked.Contains(element))
+      continue;
+
     FocusCandidate candidate = FocusCandidate(element, type);
     if (candidate.IsNull())
       continue;
@@ -1379,87 +1386,76 @@
 }
 
 bool FocusController::AdvanceFocusDirectionallyInContainer(
-    Node* container,
+    Node* start_container,
     const LayoutRect& starting_rect,
-    WebFocusType type) {
-  if (!container)
+    WebFocusType type,
+    Node* pruned_sub_tree_root) {
+  if (!start_container)
     return false;
 
-  LayoutRect new_starting_rect = starting_rect;
+  HeapVector<Member<Node>> stack;
+  stack.push_back(start_container);
 
-  if (starting_rect.IsEmpty())
-    new_starting_rect =
-        VirtualRectForDirection(type, NodeRectInAbsoluteCoordinates(container));
+  SkipList already_checked;
+  if (pruned_sub_tree_root)
+    already_checked.insert(pruned_sub_tree_root);
 
-  // Find the closest node within current container in the direction of the
-  // navigation.
-  FocusCandidate focus_candidate;
-  FindFocusCandidateInContainer(*container, new_starting_rect, type,
-                                focus_candidate);
+  while (!stack.IsEmpty()) {
+    Node* container = stack.back();
 
-  if (focus_candidate.IsNull()) {
-    // Nothing to focus, scroll if possible.
-    // NOTE: If no scrolling is performed (i.e. scrollInDirection returns
-    // false), the spatial navigation algorithm will skip this container.
-    return ScrollInDirection(container, type);
-  }
+    LayoutRect heuristic_rect =
+        starting_rect.IsEmpty()
+            ? VirtualRectForDirection(type,
+                                      NodeRectInAbsoluteCoordinates(container))
+            : starting_rect;
 
-  if (IsNavigableContainer(focus_candidate.visible_node, type)) {
-    HTMLFrameOwnerElement* frame_element = FrameOwnerElement(focus_candidate);
-    if (frame_element && frame_element->ContentFrame()->IsLocalFrame()) {
-      if (focus_candidate.is_offscreen_after_scrolling) {
-        ScrollInDirection(&focus_candidate.visible_node->GetDocument(), type);
+    FocusCandidate candidate;
+    FindFocusCandidateInContainer(*container, heuristic_rect, type, candidate,
+                                  already_checked);
+
+    if (candidate.IsNull()) {
+      // Nothing to focus in this container, scroll if possible.
+      // NOTE: If no scrolling is performed (i.e. ScrollInDirection returns
+      // false), the spatial navigation algorithm will skip this container.
+      if (ScrollInDirection(container, type))
         return true;
-      }
-      // Navigate into a new frame.
-      LayoutRect rect;
-      Element* focused_element =
-          ToLocalFrame(FocusedOrMainFrame())->GetDocument()->FocusedElement();
-      if (focused_element && !HasOffscreenRect(focused_element)) {
-        rect = NodeRectInAbsoluteCoordinates(focused_element,
-                                             true /* ignore border */);
-      }
+
+      stack.pop_back();
+      continue;
+    }
+
+    if (!IsNavigableContainer(candidate.visible_node, type)) {
+      // We found a new focus node, navigate to it.
+      Element* element = ToElement(candidate.focusable_node);
+      DCHECK(element);
+      element->focus(
+          FocusParams(SelectionBehaviorOnFocus::kReset, type, nullptr));
+      return true;
+    }
+
+    // We now dig into a navigable container.
+
+    HTMLFrameOwnerElement* frame_element = FrameOwnerElement(candidate);
+    if (frame_element && frame_element->ContentFrame()->IsLocalFrame()) {
+      // Navigate into a discovered frame.
       ToLocalFrame(frame_element->ContentFrame())
           ->GetDocument()
           ->UpdateStyleAndLayoutIgnorePendingStylesheets();
-      if (!AdvanceFocusDirectionallyInContainer(
-              ToLocalFrame(frame_element->ContentFrame())->GetDocument(), rect,
-              type)) {
-        // The new frame had nothing interesting, need to find another
-        // candidate.
-        return AdvanceFocusDirectionallyInContainer(
-            container,
-            NodeRectInAbsoluteCoordinates(focus_candidate.visible_node, true),
-            type);
-      }
-      return true;
+
+      // Mark this |already_checked| so we can skip this subtree in case
+      // FindFocusCandidateInContainer() returns it again.
+      already_checked.insert(candidate.visible_node);
+
+      stack.push_back(
+          ToLocalFrame(frame_element->ContentFrame())->GetDocument());
+      continue;
     }
 
-    if (focus_candidate.is_offscreen_after_scrolling) {
-      ScrollInDirection(focus_candidate.visible_node, type);
-      return true;
-    }
-    // Navigate into a new scrollable container.
-    LayoutRect starting_rect;
-    Element* focused_element =
-        ToLocalFrame(FocusedOrMainFrame())->GetDocument()->FocusedElement();
-    if (focused_element && !HasOffscreenRect(focused_element))
-      starting_rect = NodeRectInAbsoluteCoordinates(focused_element, true);
-    return AdvanceFocusDirectionallyInContainer(focus_candidate.visible_node,
-                                                starting_rect, type);
+    // Search sub-container.
+    stack.push_back(candidate.visible_node);
   }
 
-  if (focus_candidate.is_offscreen_after_scrolling) {
-    Node* container = focus_candidate.enclosing_scrollable_box;
-    ScrollInDirection(container, type);
-    return true;
-  }
-
-  // We found a new focus node, navigate to it.
-  Element* element = ToElement(focus_candidate.focusable_node);
-  DCHECK(element);
-  element->focus(FocusParams(SelectionBehaviorOnFocus::kReset, type, nullptr));
-  return true;
+  return ScrollInDirection(start_container, type);
 }
 
 bool FocusController::AdvanceFocusDirectionally(WebFocusType type) {
@@ -1494,15 +1490,16 @@
     container = ScrollableAreaOrDocumentOf(focused_element);
   }
 
+  Node* pruned_sub_tree_root = nullptr;
   bool consumed = false;
   while (!consumed && container) {
-    consumed =
-        AdvanceFocusDirectionallyInContainer(container, starting_rect, type);
+    consumed = AdvanceFocusDirectionallyInContainer(container, starting_rect,
+                                                    type, pruned_sub_tree_root);
     if (consumed)
       break;
 
+    pruned_sub_tree_root = container;
     container = ScrollableAreaOrDocumentOf(container);
-
     if (container && container->IsDocumentNode())
       ToDocument(container)->UpdateStyleAndLayoutIgnorePendingStylesheets();
   }
diff --git a/third_party/WebKit/Source/core/page/FocusController.h b/third_party/WebKit/Source/core/page/FocusController.h
index 7941d8e..01b2386 100644
--- a/third_party/WebKit/Source/core/page/FocusController.h
+++ b/third_party/WebKit/Source/core/page/FocusController.h
@@ -101,6 +101,8 @@
   void Trace(blink::Visitor*);
 
  private:
+  using SkipList = HeapHashSet<Member<Node>>;
+
   explicit FocusController(Page*);
 
   Element* FindFocusableElement(WebFocusType, Element&, OwnerMap&);
@@ -116,13 +118,15 @@
       bool initial_focus,
       InputDeviceCapabilities* source_capabilities);
 
-  bool AdvanceFocusDirectionallyInContainer(Node* container,
+  bool AdvanceFocusDirectionallyInContainer(Node* start_container,
                                             const LayoutRect& starting_rect,
-                                            WebFocusType);
+                                            WebFocusType,
+                                            Node* pruned_sub_tree_root);
   void FindFocusCandidateInContainer(Node& container,
                                      const LayoutRect& starting_rect,
                                      WebFocusType,
-                                     FocusCandidate& closest);
+                                     FocusCandidate& closest,
+                                     const SkipList& already_checked);
 
   void NotifyFocusChangedObservers() const;
 
diff --git a/third_party/WebKit/Source/core/script/ClassicPendingScript.cpp b/third_party/WebKit/Source/core/script/ClassicPendingScript.cpp
index 4a377986..11e8cd3 100644
--- a/third_party/WebKit/Source/core/script/ClassicPendingScript.cpp
+++ b/third_party/WebKit/Source/core/script/ClassicPendingScript.cpp
@@ -148,6 +148,8 @@
   streamer_->Cancel();
   streamer_ = nullptr;
   streamer_done_.Reset();
+  is_currently_streaming_ = false;
+  DCHECK(!IsCurrentlyStreaming());
 }
 
 void ClassicPendingScript::NotifyFinished(Resource* resource) {
@@ -324,6 +326,13 @@
 
   // Streaming-related post conditions:
 
+  // To help diagnose crbug.com/78426, we'll temporarily add some DCHECKs
+  // that are a subset of the DCHECKs below:
+  if (IsCurrentlyStreaming()) {
+    DCHECK(streamer_);
+    DCHECK(!streamer_->IsFinished());
+  }
+
   // IsCurrentlyStreaming should match what streamer_ thinks.
   DCHECK_EQ(IsCurrentlyStreaming(), streamer_ && !streamer_->IsFinished());
   // IsCurrentlyStreaming should match the ready_state_.
diff --git a/third_party/WebKit/Source/core/style/ComputedStyle.h b/third_party/WebKit/Source/core/style/ComputedStyle.h
index 6d1707dd..59dc4b0 100644
--- a/third_party/WebKit/Source/core/style/ComputedStyle.h
+++ b/third_party/WebKit/Source/core/style/ComputedStyle.h
@@ -123,7 +123,7 @@
 // In addition to storing the computed value of every CSS property,
 // ComputedStyle also contains various internal style information. Examples
 // include cached_pseudo_styles_ (for storing pseudo element styles), unique_
-// (for style sharing) and has_simple_underline_ (cached indicator flag of
+// (for style caching) and has_simple_underline_ (cached indicator flag of
 // text-decoration). These are stored on ComputedStyle for two reasons:
 //
 //  1) They share the same lifetime as ComputedStyle, so it is convenient to
diff --git a/third_party/WebKit/Source/core/testing/data/mhtml/soft_line_break.mht b/third_party/WebKit/Source/core/testing/data/mhtml/soft_line_break.mht
new file mode 100644
index 0000000..fdd9c1d3
--- /dev/null
+++ b/third_party/WebKit/Source/core/testing/data/mhtml/soft_line_break.mht
@@ -0,0 +1,27 @@
+From: <Saved by Blink>
+Subject: =?utf-8?Q?012345678901234567890123456789012345678901234567890
+	1234567890123456789012345678901234567890123456789
+	=3D=E2=98=9D=F0=9F=8F=BB?=
+Date: Thu, 4 Oct 2017 21:18:18 -0000
+MIME-Version: 1.0
+Content-Type: multipart/related;
+	type="text/html";
+	boundary="----MultipartBoundary--e77OylKXx1PBMEF67x53AwnQLf4DUmwdt037X9MjPK----"
+
+------MultipartBoundary--e77OylKXx1PBMEF67x53AwnQLf4DUmwdt037X9MjPK----
+Content-Type: text/html
+Content-ID: <frame-31894-fca076b5-329b-490d-a9ee-6974bf0c4bcd@mhtml.blink>
+Content-Transfer-Encoding: quoted-printable
+Content-Location: http://localhost/soft_line_break.html
+
+<html>
+<head><meta http-equiv=3D"Content-Type" content=3D"text/html; charset=
+=3DUTF-8">
+</head>
+<body>
+<div id=3D"AVeryLongID01234567890123456789012345678901234567890123456=
+7890End">
+</div>
+</body>
+</html>
+------MultipartBoundary--e77OylKXx1PBMEF67x53AwnQLf4DUmwdt037X9MjPK------
diff --git a/third_party/WebKit/Source/modules/beacon/NavigatorBeacon.idl b/third_party/WebKit/Source/modules/beacon/NavigatorBeacon.idl
index 469711f..372aa13 100644
--- a/third_party/WebKit/Source/modules/beacon/NavigatorBeacon.idl
+++ b/third_party/WebKit/Source/modules/beacon/NavigatorBeacon.idl
@@ -7,5 +7,5 @@
 [
     ImplementedAs=NavigatorBeacon
 ] partial interface Navigator {
-    [CallWith=ScriptState, MeasureAs=SendBeacon, RaisesException] boolean sendBeacon(DOMString url, optional (ArrayBufferView or Blob or DOMString or FormData)? data = null);
+    [CallWith=ScriptState, MeasureAs=SendBeacon, RaisesException] boolean sendBeacon(USVString url, optional (ArrayBufferView or Blob or DOMString or FormData)? data = null);
 };
diff --git a/third_party/WebKit/Source/modules/csspaint/CSSPaintImageGeneratorImpl.cpp b/third_party/WebKit/Source/modules/csspaint/CSSPaintImageGeneratorImpl.cpp
index 1c38b31..40a880f3 100644
--- a/third_party/WebKit/Source/modules/csspaint/CSSPaintImageGeneratorImpl.cpp
+++ b/third_party/WebKit/Source/modules/csspaint/CSSPaintImageGeneratorImpl.cpp
@@ -60,41 +60,45 @@
   return paint_worklet_->GetDocumentDefinitionMap().Contains(name_);
 }
 
+bool CSSPaintImageGeneratorImpl::GetValidDocumentDefinition(
+    DocumentPaintDefinition*& definition) const {
+  if (!HasDocumentDefinition())
+    return false;
+  definition = paint_worklet_->GetDocumentDefinitionMap().at(name_);
+  return definition != kInvalidDocumentDefinition;
+}
+
 const Vector<CSSPropertyID>&
 CSSPaintImageGeneratorImpl::NativeInvalidationProperties() const {
   DEFINE_STATIC_LOCAL(Vector<CSSPropertyID>, empty_vector, ());
-  if (!HasDocumentDefinition())
+  DocumentPaintDefinition* definition;
+  if (!GetValidDocumentDefinition(definition))
     return empty_vector;
-  DocumentPaintDefinition* definition =
-      paint_worklet_->GetDocumentDefinitionMap().at(name_);
   return definition->NativeInvalidationProperties();
 }
 
 const Vector<AtomicString>&
 CSSPaintImageGeneratorImpl::CustomInvalidationProperties() const {
   DEFINE_STATIC_LOCAL(Vector<AtomicString>, empty_vector, ());
-  if (!HasDocumentDefinition())
+  DocumentPaintDefinition* definition;
+  if (!GetValidDocumentDefinition(definition))
     return empty_vector;
-  DocumentPaintDefinition* definition =
-      paint_worklet_->GetDocumentDefinitionMap().at(name_);
   return definition->CustomInvalidationProperties();
 }
 
 bool CSSPaintImageGeneratorImpl::HasAlpha() const {
-  if (!HasDocumentDefinition())
+  DocumentPaintDefinition* definition;
+  if (!GetValidDocumentDefinition(definition))
     return false;
-  DocumentPaintDefinition* definition =
-      paint_worklet_->GetDocumentDefinitionMap().at(name_);
   return definition->GetPaintRenderingContext2DSettings().alpha();
 }
 
 const Vector<CSSSyntaxDescriptor>&
 CSSPaintImageGeneratorImpl::InputArgumentTypes() const {
   DEFINE_STATIC_LOCAL(Vector<CSSSyntaxDescriptor>, empty_vector, ());
-  if (!HasDocumentDefinition())
+  DocumentPaintDefinition* definition;
+  if (!GetValidDocumentDefinition(definition))
     return empty_vector;
-  DocumentPaintDefinition* definition =
-      paint_worklet_->GetDocumentDefinitionMap().at(name_);
   return definition->InputArgumentTypes();
 }
 
diff --git a/third_party/WebKit/Source/modules/csspaint/CSSPaintImageGeneratorImpl.h b/third_party/WebKit/Source/modules/csspaint/CSSPaintImageGeneratorImpl.h
index 2915a919..154c47a 100644
--- a/third_party/WebKit/Source/modules/csspaint/CSSPaintImageGeneratorImpl.h
+++ b/third_party/WebKit/Source/modules/csspaint/CSSPaintImageGeneratorImpl.h
@@ -16,6 +16,7 @@
 
 class CSSSyntaxDescriptor;
 class Document;
+class DocumentPaintDefinition;
 class Image;
 class PaintWorklet;
 
@@ -47,6 +48,11 @@
   CSSPaintImageGeneratorImpl(PaintWorklet*, const String&);
 
   bool HasDocumentDefinition() const;
+  // This function first checks whether the document definition with |name_|
+  // exists or not. If it does exist, the function fetches the document
+  // definition and checks if it is valid. The function returns true when the
+  // document definition exists and is valid.
+  bool GetValidDocumentDefinition(DocumentPaintDefinition*&) const;
 
   Member<Observer> observer_;
   Member<PaintWorklet> paint_worklet_;
diff --git a/third_party/WebKit/Source/modules/media_controls/resources/modernMediaControls.css b/third_party/WebKit/Source/modules/media_controls/resources/modernMediaControls.css
index cf79ed2c..f59a6ec 100644
--- a/third_party/WebKit/Source/modules/media_controls/resources/modernMediaControls.css
+++ b/third_party/WebKit/Source/modules/media_controls/resources/modernMediaControls.css
@@ -521,7 +521,7 @@
 .state-no-source input[pseudo="-webkit-media-controls-overlay-play-button" i],
 .use-default-poster div[pseudo="-internal-media-controls-button-panel" i],
 .use-default-poster input[pseudo="-webkit-media-controls-timeline" i] {
-  display: none;
+  visibility: hidden;
 }
 
 /**
diff --git a/third_party/WebKit/Source/modules/webgl/WebGLFramebuffer.h b/third_party/WebKit/Source/modules/webgl/WebGLFramebuffer.h
index 30c749f..d7fc1a1 100644
--- a/third_party/WebKit/Source/modules/webgl/WebGLFramebuffer.h
+++ b/third_party/WebKit/Source/modules/webgl/WebGLFramebuffer.h
@@ -101,6 +101,9 @@
 
   bool HasStencilBuffer() const;
 
+  bool HaveContentsChanged() { return contents_changed_; }
+  void SetContentsChanged(bool changed) { contents_changed_ = changed; }
+
   bool Opaque() const { return opaque_; }
   void MarkOpaqueBufferComplete(bool complete) { opaque_complete_ = complete; }
 
@@ -156,6 +159,7 @@
 
   bool has_ever_been_bound_;
   bool web_gl1_depth_stencil_consistent_;
+  bool contents_changed_ = false;
   const bool opaque_;
   bool opaque_complete_ = false;
 
diff --git a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp
index 53da727..1dde3422 100644
--- a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp
+++ b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp
@@ -1293,9 +1293,14 @@
 
 void WebGLRenderingContextBase::MarkContextChanged(
     ContentChangeType change_type) {
-  if (framebuffer_binding_ || isContextLost())
+  if (isContextLost())
     return;
 
+  if (framebuffer_binding_) {
+    framebuffer_binding_->SetContentsChanged(true);
+    return;
+  }
+
   if (!GetDrawingBuffer()->MarkContentsChanged() && marked_canvas_dirty_) {
     return;
   }
diff --git a/third_party/WebKit/Source/modules/xr/XRFrameProvider.cpp b/third_party/WebKit/Source/modules/xr/XRFrameProvider.cpp
index f3cd855..116b5e01 100644
--- a/third_party/WebKit/Source/modules/xr/XRFrameProvider.cpp
+++ b/third_party/WebKit/Source/modules/xr/XRFrameProvider.cpp
@@ -5,14 +5,19 @@
 #include "modules/xr/XRFrameProvider.h"
 
 #include "bindings/core/v8/ScriptPromiseResolver.h"
+#include "build/build_config.h"
 #include "core/dom/DOMException.h"
 #include "core/dom/Document.h"
 #include "core/dom/FrameRequestCallbackCollection.h"
 #include "core/frame/LocalFrame.h"
+#include "core/imagebitmap/ImageBitmap.h"
 #include "modules/xr/XR.h"
 #include "modules/xr/XRDevice.h"
 #include "modules/xr/XRSession.h"
+#include "modules/xr/XRViewport.h"
+#include "modules/xr/XRWebGLLayer.h"
 #include "platform/WebTaskRunner.h"
+#include "platform/graphics/gpu/XRFrameTransport.h"
 #include "platform/instrumentation/tracing/TraceEvent.h"
 #include "platform/transforms/TransformationMatrix.h"
 #include "platform/wtf/Time.h"
@@ -29,12 +34,7 @@
       : frame_provider_(frame_provider) {}
   ~XRFrameProviderRequestCallback() override = default;
   void Invoke(double high_res_time_ms) override {
-    // TODO(bajones): Eventually exclusive vsyncs won't be handled here.
-    if (frame_provider_->exclusive_session()) {
-      frame_provider_->OnExclusiveVSync(high_res_time_ms / 1000.0);
-    } else {
-      frame_provider_->OnNonExclusiveVSync(high_res_time_ms / 1000.0);
-    }
+    frame_provider_->OnNonExclusiveVSync(high_res_time_ms / 1000.0);
   }
 
   virtual void Trace(blink::Visitor* visitor) {
@@ -98,13 +98,32 @@
 
   pending_exclusive_session_resolver_ = resolver;
 
-  // TODO(bajones): Request a XRPresentationProviderPtr to use for presenting
-  // frames, delay call to OnPresentComplete till the connection is established.
-  OnPresentComplete(true);
+  // Establish the connection with the VSyncProvider if needed.
+  if (!presentation_provider_.is_bound()) {
+    frame_transport_ = new XRFrameTransport();
+
+    // Set up RequestPresentOptions based on canvas properties.
+    device::mojom::blink::VRRequestPresentOptionsPtr options =
+        device::mojom::blink::VRRequestPresentOptions::New();
+    options->preserve_drawing_buffer = false;
+
+    device_->xrDisplayHostPtr()->RequestPresent(
+        frame_transport_->GetSubmitFrameClient(),
+        mojo::MakeRequest(&presentation_provider_), std::move(options),
+        WTF::Bind(&XRFrameProvider::OnPresentComplete, WrapPersistent(this)));
+
+    presentation_provider_.set_connection_error_handler(
+        WTF::Bind(&XRFrameProvider::OnPresentationProviderConnectionError,
+                  WrapWeakPersistent(this)));
+  }
 }
 
-void XRFrameProvider::OnPresentComplete(bool success) {
+void XRFrameProvider::OnPresentComplete(
+    bool success,
+    device::mojom::blink::VRDisplayFrameTransportOptionsPtr transport_options) {
   if (success) {
+    frame_transport_->SetTransportOptions(std::move(transport_options));
+    frame_transport_->PresentChange();
     pending_exclusive_session_resolver_->Resolve(exclusive_session_);
   } else {
     exclusive_session_->ForceEnd();
@@ -119,17 +138,39 @@
   pending_exclusive_session_resolver_ = nullptr;
 }
 
+void XRFrameProvider::OnPresentationProviderConnectionError() {
+  if (pending_exclusive_session_resolver_) {
+    DOMException* exception = DOMException::Create(
+        kNotAllowedError,
+        "Error occured while requesting exclusive XRSession.");
+    pending_exclusive_session_resolver_->Reject(exception);
+    pending_exclusive_session_resolver_ = nullptr;
+  }
+
+  presentation_provider_.reset();
+  if (vsync_connection_failed_)
+    return;
+  exclusive_session_->ForceEnd();
+  vsync_connection_failed_ = true;
+}
+
 // Called by the exclusive session when it is ended.
 void XRFrameProvider::OnExclusiveSessionEnded() {
   if (!exclusive_session_)
     return;
 
-  // TODO(bajones): Call device_->xrDisplayHostPtr()->ExitPresent();
+  device_->xrDisplayHostPtr()->ExitPresent();
 
   exclusive_session_ = nullptr;
   pending_exclusive_vsync_ = false;
   frame_id_ = -1;
 
+  if (presentation_provider_.is_bound()) {
+    presentation_provider_.reset();
+  }
+
+  frame_transport_ = nullptr;
+
   // When we no longer have an active exclusive session schedule all the
   // outstanding frames that were requested while the exclusive session was
   // active.
@@ -161,21 +202,10 @@
   if (pending_exclusive_vsync_)
     return;
 
-  // TODO(bajones): This should acquire frames through a XRPresentationProvider
-  // instead of duplicating the non-exclusive path.
-  LocalFrame* frame = device_->xr()->GetFrame();
-  if (!frame)
-    return;
-
-  Document* doc = frame->GetDocument();
-  if (!doc)
-    return;
-
   pending_exclusive_vsync_ = true;
 
-  device_->xrMagicWindowProviderPtr()->GetPose(WTF::Bind(
-      &XRFrameProvider::OnNonExclusivePose, WrapWeakPersistent(this)));
-  doc->RequestAnimationFrame(new XRFrameProviderRequestCallback(this));
+  presentation_provider_->GetVSync(
+      WTF::Bind(&XRFrameProvider::OnExclusiveVSync, WrapWeakPersistent(this)));
 }
 
 void XRFrameProvider::ScheduleNonExclusiveFrame() {
@@ -197,14 +227,28 @@
   doc->RequestAnimationFrame(new XRFrameProviderRequestCallback(this));
 }
 
-void XRFrameProvider::OnExclusiveVSync(double timestamp) {
+void XRFrameProvider::OnExclusiveVSync(
+    device::mojom::blink::VRPosePtr pose,
+    WTF::TimeDelta time_delta,
+    int16_t frame_id,
+    device::mojom::blink::VRPresentationProvider::VSyncStatus status) {
   DVLOG(2) << __FUNCTION__;
-
-  pending_exclusive_vsync_ = false;
+  vsync_connection_failed_ = false;
+  switch (status) {
+    case device::mojom::blink::VRPresentationProvider::VSyncStatus::SUCCESS:
+      break;
+    case device::mojom::blink::VRPresentationProvider::VSyncStatus::CLOSING:
+      return;
+  }
 
   // We may have lost the exclusive session since the last VSync request.
-  if (!exclusive_session_)
+  if (!exclusive_session_) {
     return;
+  }
+
+  frame_pose_ = std::move(pose);
+  frame_id_ = frame_id;
+  pending_exclusive_vsync_ = false;
 
   // Post a task to handle scheduled animations after the current
   // execution context finishes, so that we yield to non-mojo tasks in
@@ -213,7 +257,7 @@
   // multiple frames without yielding, see crbug.com/701444.
   Platform::Current()->CurrentThread()->GetWebTaskRunner()->PostTask(
       FROM_HERE, WTF::Bind(&XRFrameProvider::ProcessScheduledFrame,
-                           WrapWeakPersistent(this), timestamp));
+                           WrapWeakPersistent(this), time_delta.InSecondsF()));
 }
 
 void XRFrameProvider::OnNonExclusiveVSync(double timestamp) {
@@ -262,9 +306,76 @@
   }
 }
 
+void XRFrameProvider::SubmitWebGLLayer(XRWebGLLayer* layer) {
+  DCHECK(layer);
+  DCHECK(layer->session() == exclusive_session_);
+  DCHECK(presentation_provider_);
+
+  TRACE_EVENT1("gpu", "XRFrameProvider::SubmitWebGLLayer", "frame", frame_id_);
+
+  WebGLRenderingContextBase* webgl_context = layer->context();
+
+  frame_transport_->FramePreImage(webgl_context->ContextGL());
+
+  scoped_refptr<Image> image_ref = layer->TransferToStaticBitmapImage();
+  if (!image_ref)
+    return;
+
+  // Hardware-accelerated rendering should always be texture backed. Ensure this
+  // is the case, don't attempt to render if using an unexpected drawing path.
+  if (!image_ref->IsTextureBacked()) {
+    NOTREACHED() << "WebXR requires hardware-accelerated rendering to texture";
+    return;
+  }
+
+  // TODO(bajones): Remove this when the Windows path has been updated to no
+  // longer require a texture copy.
+  bool needs_copy = device_->external();
+
+  frame_transport_->FrameSubmit(presentation_provider_.get(),
+                                webgl_context->ContextGL(), webgl_context,
+                                std::move(image_ref), frame_id_, needs_copy);
+
+  // Reset our frame id, since anything we'd want to do (resizing/etc) can
+  // no-longer happen to this frame.
+  frame_id_ = -1;
+}
+
+// TODO(bajones): This only works because we're restricted to a single layer at
+// the moment. Will need an overhaul when we get more robust layering support.
+void XRFrameProvider::UpdateWebGLLayerViewports(XRWebGLLayer* layer) {
+  DCHECK(layer->session() == exclusive_session_);
+  DCHECK(presentation_provider_);
+
+  XRViewport* left = layer->GetViewport(XRView::kEyeLeft);
+  XRViewport* right = layer->GetViewport(XRView::kEyeRight);
+  float width = layer->framebufferWidth();
+  float height = layer->framebufferHeight();
+
+  WebFloatRect left_coords(
+      static_cast<float>(left->x()) / width,
+      static_cast<float>(height - (left->y() + left->height())) / height,
+      static_cast<float>(left->width()) / width,
+      static_cast<float>(left->height()) / height);
+  WebFloatRect right_coords(
+      static_cast<float>(right->x()) / width,
+      static_cast<float>(height - (right->y() + right->height())) / height,
+      static_cast<float>(right->width()) / width,
+      static_cast<float>(right->height()) / height);
+
+  presentation_provider_->UpdateLayerBounds(
+      frame_id_, left_coords, right_coords, WebSize(width, height));
+}
+
+void XRFrameProvider::Dispose() {
+  presentation_provider_.reset();
+  // TODO(bajones): Do something for outstanding frame requests?
+}
+
 void XRFrameProvider::Trace(blink::Visitor* visitor) {
   visitor->Trace(device_);
   visitor->Trace(pending_exclusive_session_resolver_);
+  visitor->Trace(frame_transport_);
   visitor->Trace(exclusive_session_);
   visitor->Trace(requesting_sessions_);
 }
diff --git a/third_party/WebKit/Source/modules/xr/XRFrameProvider.h b/third_party/WebKit/Source/modules/xr/XRFrameProvider.h
index 3f6b2fe2..7c2e6b8 100644
--- a/third_party/WebKit/Source/modules/xr/XRFrameProvider.h
+++ b/third_party/WebKit/Source/modules/xr/XRFrameProvider.h
@@ -16,6 +16,8 @@
 class ScriptPromiseResolver;
 class XRDevice;
 class XRSession;
+class XRFrameTransport;
+class XRWebGLLayer;
 
 // This class manages requesting and dispatching frame updates, which includes
 // pose information for a given XRDevice.
@@ -31,29 +33,41 @@
 
   void RequestFrame(XRSession*);
 
-  void OnExclusiveVSync(double timestamp);
   void OnNonExclusiveVSync(double timestamp);
 
-  void SubmitFrame(gpu::MailboxHolder);
+  void SubmitWebGLLayer(XRWebGLLayer*);
+  void UpdateWebGLLayerViewports(XRWebGLLayer*);
+
+  void Dispose();
 
   virtual void Trace(blink::Visitor*);
 
  private:
+  void OnExclusiveVSync(
+      device::mojom::blink::VRPosePtr,
+      WTF::TimeDelta,
+      int16_t frame_id,
+      device::mojom::blink::VRPresentationProvider::VSyncStatus);
   void OnNonExclusivePose(device::mojom::blink::VRPosePtr);
 
   void ScheduleExclusiveFrame();
   void ScheduleNonExclusiveFrame();
 
-  void OnPresentComplete(bool success);
+  void OnPresentComplete(
+      bool success,
+      device::mojom::blink::VRDisplayFrameTransportOptionsPtr);
+  void OnPresentationProviderConnectionError();
   void ProcessScheduledFrame(double timestamp);
 
   const Member<XRDevice> device_;
   Member<XRSession> exclusive_session_;
   Member<ScriptPromiseResolver> pending_exclusive_session_resolver_;
+  Member<XRFrameTransport> frame_transport_;
 
   // Non-exclusive Sessions which have requested a frame update.
   HeapVector<Member<XRSession>> requesting_sessions_;
 
+  device::mojom::blink::VRPresentationProviderPtr presentation_provider_;
   device::mojom::blink::VRMagicWindowProviderPtr magic_window_provider_;
   device::mojom::blink::VRPosePtr frame_pose_;
 
@@ -64,10 +78,6 @@
   bool pending_exclusive_vsync_ = false;
   bool pending_non_exclusive_vsync_ = false;
   bool vsync_connection_failed_ = false;
-  double timebase_ = -1;
-
-  bool pending_submit_frame_ = false;
-  bool pending_previous_frame_render_ = false;
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/modules/xr/XRWebGLLayer.cpp b/third_party/WebKit/Source/modules/xr/XRWebGLLayer.cpp
index eb8a70b..653c91bd 100644
--- a/third_party/WebKit/Source/modules/xr/XRWebGLLayer.cpp
+++ b/third_party/WebKit/Source/modules/xr/XRWebGLLayer.cpp
@@ -11,6 +11,7 @@
 #include "modules/webgl/WebGLFramebuffer.h"
 #include "modules/webgl/WebGLRenderingContext.h"
 #include "modules/xr/XRDevice.h"
+#include "modules/xr/XRFrameProvider.h"
 #include "modules/xr/XRSession.h"
 #include "modules/xr/XRView.h"
 #include "modules/xr/XRViewport.h"
@@ -170,6 +171,8 @@
         new XRViewport(framebuffer_width * 0.5 * viewport_scale_, 0,
                        framebuffer_width * 0.5 * viewport_scale_,
                        framebuffer_height * viewport_scale_);
+
+    session()->device()->frameProvider()->UpdateWebGLLayerViewports(this);
   } else {
     left_viewport_ = new XRViewport(0, 0, framebuffer_width * viewport_scale_,
                                     framebuffer_height * viewport_scale_);
@@ -178,10 +181,19 @@
 
 void XRWebGLLayer::OnFrameStart() {
   framebuffer_->MarkOpaqueBufferComplete(true);
+  framebuffer_->SetContentsChanged(false);
 }
 
 void XRWebGLLayer::OnFrameEnd() {
   framebuffer_->MarkOpaqueBufferComplete(false);
+  // Exit early if the framebuffer contents have not changed.
+  if (!framebuffer_->HaveContentsChanged())
+    return;
+
+  // Submit the frame to the XR compositor.
+  if (session()->exclusive()) {
+    session()->device()->frameProvider()->SubmitWebGLLayer(this);
+  }
 }
 
 void XRWebGLLayer::OnResize() {
diff --git a/third_party/WebKit/Source/platform/mhtml/MHTMLArchive.cpp b/third_party/WebKit/Source/platform/mhtml/MHTMLArchive.cpp
index f485212..16a7882 100644
--- a/third_party/WebKit/Source/platform/mhtml/MHTMLArchive.cpp
+++ b/third_party/WebKit/Source/platform/mhtml/MHTMLArchive.cpp
@@ -48,9 +48,78 @@
 
 namespace blink {
 
-const char* const kQuotedPrintable = "quoted-printable";
-const char* const kBase64 = "base64";
-const char* const kBinary = "binary";
+namespace {
+
+const size_t kMaximumLineLength = 76;
+const char kCrlfLineEnding[] = "\r\n";
+
+const char kRFC2047EncodingPrefix[] = "=?utf-8?Q?";
+const size_t kRFC2047EncodingPrefixLength = 10;
+const char kRFC2047EncodingSuffix[] = "?=";
+const size_t kRFC2047EncodingSuffixLength = 2;
+
+const char kQuotedPrintable[] = "quoted-printable";
+const char kBase64[] = "base64";
+const char kBinary[] = "binary";
+
+}  // namespace
+
+// Controls quoted-printable encoding characters in body, per RFC 2045.
+class QuotedPrintableEncodeBodyDelegate : public QuotedPrintableEncodeDelegate {
+ public:
+  QuotedPrintableEncodeBodyDelegate() = default;
+  ~QuotedPrintableEncodeBodyDelegate() override = default;
+
+  size_t GetMaxLineLengthForEncodedContent() const override {
+    return kMaximumLineLength;
+  }
+
+  bool ShouldEncodeWhiteSpaceCharacters(bool end_of_line) const override {
+    // They should be encoded only if they appear at the end of a body line.
+    return end_of_line;
+  }
+
+  void DidStartLine(Vector<char>& out) override {
+    // Nothing to add.
+  }
+
+  void DidFinishLine(bool last_line, Vector<char>& out) override {
+    if (!last_line) {
+      out.push_back('=');
+      out.Append(kCrlfLineEnding, strlen(kCrlfLineEnding));
+    }
+  }
+};
+
+// Controls quoted-printable encoding characters in headers, per RFC 2047.
+class QuotedPrintableEncodeHeaderDelegate
+    : public QuotedPrintableEncodeDelegate {
+ public:
+  QuotedPrintableEncodeHeaderDelegate() = default;
+  ~QuotedPrintableEncodeHeaderDelegate() override = default;
+
+  size_t GetMaxLineLengthForEncodedContent() const override {
+    return kMaximumLineLength - kRFC2047EncodingPrefixLength -
+           kRFC2047EncodingSuffixLength;
+  }
+
+  bool ShouldEncodeWhiteSpaceCharacters(bool end_of_line) const override {
+    // They should always be encoded if they appear anywhere in the header.
+    return true;
+  }
+
+  void DidStartLine(Vector<char>& out) override {
+    out.Append(kRFC2047EncodingPrefix, kRFC2047EncodingPrefixLength);
+  }
+
+  void DidFinishLine(bool last_line, Vector<char>& out) override {
+    out.Append(kRFC2047EncodingSuffix, kRFC2047EncodingSuffixLength);
+    if (!last_line) {
+      out.Append(kCrlfLineEnding, strlen(kCrlfLineEnding));
+      out.push_back(' ');
+    }
+  }
+};
 
 static String ConvertToPrintableCharacters(const String& text) {
   // If the text contains all printable ASCII characters, no need for encoding.
@@ -70,9 +139,11 @@
   // where, "utf-8" is the chosen charset to represent the text and "Q" is the
   // Quoted-Printable format to convert to 7-bit printable ASCII characters.
   CString utf8_text = text.Utf8();
+  QuotedPrintableEncodeHeaderDelegate header_delegate;
   Vector<char> encoded_text;
-  QuotedPrintableEncode(utf8_text.data(), utf8_text.length(), encoded_text);
-  return "=?utf-8?Q?" + String(encoded_text.data(), encoded_text.size()) + "?=";
+  QuotedPrintableEncode(utf8_text.data(), utf8_text.length(), &header_delegate,
+                        encoded_text);
+  return String(encoded_text.data(), encoded_text.size());
 }
 
 MHTMLArchive::MHTMLArchive() = default;
@@ -245,7 +316,8 @@
     size_t data_length = flat_data.size();
     Vector<char> encoded_data;
     if (!strcmp(content_encoding, kQuotedPrintable)) {
-      QuotedPrintableEncode(data, data_length, encoded_data);
+      QuotedPrintableEncodeBodyDelegate body_delegate;
+      QuotedPrintableEncode(data, data_length, &body_delegate, encoded_data);
       output_buffer.Append(encoded_data.data(), encoded_data.size());
       output_buffer.Append("\r\n", 2u);
     } else {
@@ -253,7 +325,6 @@
       // We are not specifying insertLFs = true below as it would cut the lines
       // with LFs and MHTML requires CRLFs.
       Base64Encode(data, data_length, encoded_data);
-      const size_t kMaximumLineLength = 76;
       size_t index = 0;
       size_t encoded_data_length = encoded_data.size();
       do {
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.cc b/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.cc
index 97c6844..8ba52e58 100644
--- a/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.cc
+++ b/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.cc
@@ -599,12 +599,6 @@
   return ipc_task_queue_;
 }
 
-scoped_refptr<base::SingleThreadTaskRunner>
-RendererSchedulerImpl::LoadingTaskRunner() {
-  helper_.CheckOnValidThread();
-  return default_loading_task_queue_;
-}
-
 scoped_refptr<MainThreadTaskQueue> RendererSchedulerImpl::DefaultTaskQueue() {
   return helper_.DefaultMainThreadTaskQueue();
 }
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.h b/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.h
index 67cdaa3..a854e58 100644
--- a/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.h
+++ b/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.h
@@ -305,7 +305,6 @@
   // Use *TaskQueue internally.
   scoped_refptr<base::SingleThreadTaskRunner> DefaultTaskRunner() override;
   scoped_refptr<base::SingleThreadTaskRunner> CompositorTaskRunner() override;
-  scoped_refptr<base::SingleThreadTaskRunner> LoadingTaskRunner() override;
 
  private:
   friend class RenderWidgetSchedulingState;
diff --git a/third_party/WebKit/Source/platform/scheduler/test/fake_renderer_scheduler.cc b/third_party/WebKit/Source/platform/scheduler/test/fake_renderer_scheduler.cc
index 0c84bd30..b157fb0b 100644
--- a/third_party/WebKit/Source/platform/scheduler/test/fake_renderer_scheduler.cc
+++ b/third_party/WebKit/Source/platform/scheduler/test/fake_renderer_scheduler.cc
@@ -30,11 +30,6 @@
   return nullptr;
 }
 
-scoped_refptr<base::SingleThreadTaskRunner>
-FakeRendererScheduler::LoadingTaskRunner() {
-  return nullptr;
-}
-
 scoped_refptr<SingleThreadIdleTaskRunner>
 FakeRendererScheduler::IdleTaskRunner() {
   return nullptr;
diff --git a/third_party/WebKit/Source/platform/text/QuotedPrintable.cpp b/third_party/WebKit/Source/platform/text/QuotedPrintable.cpp
index e0fe466..9f80140 100644
--- a/third_party/WebKit/Source/platform/text/QuotedPrintable.cpp
+++ b/third_party/WebKit/Source/platform/text/QuotedPrintable.cpp
@@ -34,8 +34,6 @@
 
 namespace blink {
 
-static const size_t kMaximumLineLength = 76;
-
 static const char kCrlfLineEnding[] = "\r\n";
 
 static size_t LengthOfLineEndingAtIndex(const char* input,
@@ -54,15 +52,13 @@
   return 0;
 }
 
-void QuotedPrintableEncode(const Vector<char>& in, Vector<char>& out) {
-  QuotedPrintableEncode(in.data(), in.size(), out);
-}
-
 void QuotedPrintableEncode(const char* input,
                            size_t input_length,
+                           QuotedPrintableEncodeDelegate* delegate,
                            Vector<char>& out) {
   out.clear();
   out.ReserveCapacity(input_length);
+  delegate->DidStartLine(out);
   size_t current_line_length = 0;
   for (size_t i = 0; i < input_length; ++i) {
     bool is_last_character = (i == input_length - 1);
@@ -74,13 +70,14 @@
         current_character != '\t')
       requires_encoding = true;
 
-    // Space and tab characters have to be encoded if they appear at the end of
-    // a line.
+    // Decide if space and tab characters need to be encoded.
     if (!requires_encoding &&
-        (current_character == '\t' || current_character == ' ') &&
-        (is_last_character ||
-         LengthOfLineEndingAtIndex(input, input_length, i + 1)))
-      requires_encoding = true;
+        (current_character == '\t' || current_character == ' ')) {
+      bool end_of_line = is_last_character ||
+                         LengthOfLineEndingAtIndex(input, input_length, i + 1);
+      requires_encoding =
+          delegate->ShouldEncodeWhiteSpaceCharacters(end_of_line);
+    }
 
     // End of line should be converted to CR-LF sequences.
     if (!is_last_character) {
@@ -103,10 +100,10 @@
 
     // Insert a soft line break if necessary.
     if (current_line_length + length_of_encoded_character >
-        kMaximumLineLength) {
-      out.push_back('=');
-      out.Append(kCrlfLineEnding, strlen(kCrlfLineEnding));
+        delegate->GetMaxLineLengthForEncodedContent()) {
+      delegate->DidFinishLine(false /*last_line*/, out);
       current_line_length = 0;
+      delegate->DidStartLine(out);
     }
 
     // Finally, insert the actual character(s).
@@ -120,6 +117,7 @@
       current_line_length++;
     }
   }
+  delegate->DidFinishLine(true /*last_line*/, out);
 }
 
 void QuotedPrintableDecode(const Vector<char>& in, Vector<char>& out) {
diff --git a/third_party/WebKit/Source/platform/text/QuotedPrintable.h b/third_party/WebKit/Source/platform/text/QuotedPrintable.h
index c37293e..2036970 100644
--- a/third_party/WebKit/Source/platform/text/QuotedPrintable.h
+++ b/third_party/WebKit/Source/platform/text/QuotedPrintable.h
@@ -36,10 +36,38 @@
 
 namespace blink {
 
-PLATFORM_EXPORT void QuotedPrintableEncode(const Vector<char>&, Vector<char>&);
-PLATFORM_EXPORT void QuotedPrintableEncode(const char*, size_t, Vector<char>&);
+// Delegate for controling the behavior of quoted-printable encoding. The
+// original characters may be encoded a bit differently depending on where
+// they live, header or body. For example, "=CRLF" should be used to break
+// long line in body while "CRLF+SPACE" should be used to break long line in
+// header.
+class PLATFORM_EXPORT QuotedPrintableEncodeDelegate {
+ public:
+  QuotedPrintableEncodeDelegate() = default;
+  virtual ~QuotedPrintableEncodeDelegate() = default;
 
-PLATFORM_EXPORT void QuotedPrintableDecode(const Vector<char>&, Vector<char>&);
+  // Returns maximum number of characters allowed for an encoded line, excluding
+  // prefix and soft line break.
+  virtual size_t GetMaxLineLengthForEncodedContent() const = 0;
+
+  // Returns true if space and tab characters need to be encoded.
+  virtual bool ShouldEncodeWhiteSpaceCharacters(bool end_of_line) const = 0;
+
+  // Called when an encoded line starts. The delegate can take this chance to
+  // add any prefix.
+  virtual void DidStartLine(Vector<char>& out) = 0;
+
+  // Called when an encoded line ends. The delegate can take this chance to add
+  // any suffix. If it is not last line, a soft line break should also
+  // be added after the suffix.
+  virtual void DidFinishLine(bool last_line, Vector<char>& out) = 0;
+};
+
+PLATFORM_EXPORT void QuotedPrintableEncode(const char*,
+                                           size_t,
+                                           QuotedPrintableEncodeDelegate*,
+                                           Vector<char>&);
+
 PLATFORM_EXPORT void QuotedPrintableDecode(const char*, size_t, Vector<char>&);
 
 }  // namespace blink
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_importer.py b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_importer.py
index fc392ae2..3049b09e 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_importer.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_importer.py
@@ -133,7 +133,8 @@
 
         self._generate_manifest()
 
-        self._delete_orphaned_baselines()
+        # TODO(crbug.com/800570 robertma): Re-enable it once we fix the bug.
+        # self._delete_orphaned_baselines()
 
         # TODO(qyearsley): Consider running the imported tests with
         # `run-webkit-tests --reset-results external/wpt` to get some baselines
diff --git a/third_party/WebKit/public/platform/WebWorkerFetchContext.h b/third_party/WebKit/public/platform/WebWorkerFetchContext.h
index 0dd49f17..3382eb6 100644
--- a/third_party/WebKit/public/platform/WebWorkerFetchContext.h
+++ b/third_party/WebKit/public/platform/WebWorkerFetchContext.h
@@ -12,10 +12,6 @@
 #include "public/platform/WebDocumentSubresourceFilter.h"
 #include "public/platform/WebURL.h"
 
-namespace base {
-class SingleThreadTaskRunner;
-}
-
 namespace blink {
 
 class WebURLLoaderFactory;
@@ -31,8 +27,7 @@
  public:
   virtual ~WebWorkerFetchContext() = default;
 
-  virtual void InitializeOnWorkerThread(
-      scoped_refptr<base::SingleThreadTaskRunner>) = 0;
+  virtual void InitializeOnWorkerThread() = 0;
 
   // Returns a new WebURLLoaderFactory which is associated with the worker
   // context. It can be called only once.
diff --git a/third_party/WebKit/public/platform/scheduler/renderer/renderer_scheduler.h b/third_party/WebKit/public/platform/scheduler/renderer/renderer_scheduler.h
index 4bf0d79..ef0d8e1 100644
--- a/third_party/WebKit/public/platform/scheduler/renderer/renderer_scheduler.h
+++ b/third_party/WebKit/public/platform/scheduler/renderer/renderer_scheduler.h
@@ -59,10 +59,6 @@
   // Creates a WebThread implementation for the renderer main thread.
   virtual std::unique_ptr<WebThread> CreateMainThread() = 0;
 
-  // Returns the loading task runner.  This queue is intended for tasks related
-  // to resource dispatch, foreground HTML parsing, etc...
-  virtual scoped_refptr<base::SingleThreadTaskRunner> LoadingTaskRunner() = 0;
-
   // Returns a new RenderWidgetSchedulingState.  The signals from this will be
   // used to make scheduling decisions.
   virtual std::unique_ptr<RenderWidgetSchedulingState>
diff --git a/third_party/WebKit/public/platform/scheduler/test/fake_renderer_scheduler.h b/third_party/WebKit/public/platform/scheduler/test/fake_renderer_scheduler.h
index ac139d0..9faed00 100644
--- a/third_party/WebKit/public/platform/scheduler/test/fake_renderer_scheduler.h
+++ b/third_party/WebKit/public/platform/scheduler/test/fake_renderer_scheduler.h
@@ -23,7 +23,6 @@
   std::unique_ptr<WebThread> CreateMainThread() override;
   scoped_refptr<base::SingleThreadTaskRunner> DefaultTaskRunner() override;
   scoped_refptr<base::SingleThreadTaskRunner> CompositorTaskRunner() override;
-  scoped_refptr<base::SingleThreadTaskRunner> LoadingTaskRunner() override;
   scoped_refptr<SingleThreadIdleTaskRunner> IdleTaskRunner() override;
   scoped_refptr<base::SingleThreadTaskRunner> IPCTaskRunner() override;
   std::unique_ptr<RenderWidgetSchedulingState> NewRenderWidgetSchedulingState()
diff --git a/tools/licenses.py b/tools/licenses.py
index 8c834e8..4fcdb469 100755
--- a/tools/licenses.py
+++ b/tools/licenses.py
@@ -25,7 +25,7 @@
 import tempfile
 
 # TODO(agrieve): Move build_utils.WriteDepFile into a non-android directory.
-_REPOSITORY_ROOT = os.path.dirname(os.path.dirname(__file__))
+_REPOSITORY_ROOT = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))
 sys.path.append(os.path.join(_REPOSITORY_ROOT, 'build/android/gyp/util'))
 import build_utils
 
@@ -481,12 +481,17 @@
     Note that it always returns the direct sub-directory of third_party
     where README.chromium and LICENSE files are, so that it can be passed to
     ParseDir(). e.g.:
-        .../third_party/cld_3/src/src/BUILD.gn -> .../third_party/cld_3
+        third_party/cld_3/src/src/BUILD.gn -> third_party/cld_3
+
+    It returns relative paths from _REPOSITORY_ROOT, not absolute paths.
     """
     third_party_deps = set()
-    for build_dep in gn_deps.split():
-        m = re.search(r'^(.+/third_party/[^/]+)/(.+/)?BUILD\.gn$', build_dep)
-        if m and not os.path.join('build', 'secondary') in build_dep:
+    for absolute_build_dep in gn_deps.split():
+        relative_build_dep = os.path.relpath(
+            absolute_build_dep, _REPOSITORY_ROOT)
+        m = re.search(
+            r'^((.+/)?third_party/[^/]+)/(.+/)?BUILD\.gn$', relative_build_dep)
+        if m and not os.path.join('build', 'secondary') in relative_build_dep:
             third_party_deps.add(m.group(1))
     return third_party_deps
 
diff --git a/tools/metrics/actions/actions.xml b/tools/metrics/actions/actions.xml
index 1e1ca1d..e063fc7 100644
--- a/tools/metrics/actions/actions.xml
+++ b/tools/metrics/actions/actions.xml
@@ -1894,16 +1894,19 @@
 </action>
 
 <action name="AppList_SearchedBySpeech">
+  <obsolete>App list doesn't have voice search anymore.</obsolete>
   <owner>Please list the metric's owners. Add more owner tags as needed.</owner>
   <description>Please enter the description of this user action.</description>
 </action>
 
 <action name="AppList_VoiceSearchCanceled">
+  <obsolete>App list doesn't have voice search anymore.</obsolete>
   <owner>Please list the metric's owners. Add more owner tags as needed.</owner>
   <description>Please enter the description of this user action.</description>
 </action>
 
 <action name="AppList_VoiceSearchStartedManually">
+  <obsolete>App list doesn't have voice search anymore.</obsolete>
   <owner>Please list the metric's owners. Add more owner tags as needed.</owner>
   <description>Please enter the description of this user action.</description>
 </action>
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index b9c9b94..78c90db9 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -25502,6 +25502,7 @@
   <int value="-1377186702" label="DesktopIOSPromotion:disabled"/>
   <int value="-1376510363" label="ServiceWorkerScriptFullCodeCache:disabled"/>
   <int value="-1375111024" label="enable-fixed-position-compositing"/>
+  <int value="-1373705581" label="ManualSaving:enabled"/>
   <int value="-1365503870" label="enable-simplified-fullscreen-ui"/>
   <int value="-1363709707" label="MaterialDesignHistory:disabled"/>
   <int value="-1358669137" label="enable-supervised-user-blacklist"/>
@@ -25737,7 +25738,6 @@
   <int value="-772679248" label="MojoVideoEncodeAccelerator:enabled"/>
   <int value="-771080109" label="GrantNotificationsToDSE:disabled"/>
   <int value="-770319039" label="enable-touch-editing"/>
-  <int value="-765715931" label="ash-disable-v1-app-back-button"/>
   <int value="-763759697" label="enable-audio-support-for-desktop-share"/>
   <int value="-759830869" label="enable-tab-discarding"/>
   <int value="-757946835"
@@ -25771,6 +25771,7 @@
   <int value="-684223908" label="enable-android-wallpapers-app"/>
   <int value="-680787130" label="ExperimentalVRFeatures:disabled"/>
   <int value="-680589442" label="MacRTL:disabled"/>
+  <int value="-674804217" label="SoleIntegration:enabled"/>
   <int value="-671992446" label="TranslateRankerEnforcement:disabled"/>
   <int value="-670188266" label="enable-zip-archiver-unpacker"/>
   <int value="-667517406" label="overscroll-history-navigation"/>
@@ -26093,6 +26094,7 @@
   <int value="200347243" label="WebVRExperimentalRendering:disabled"/>
   <int value="201343576" label="enable-password-change-support:enabled"/>
   <int value="203776499" label="enable-virtual-keyboard-overscroll"/>
+  <int value="218890378" label="ManualSaving:disabled"/>
   <int value="219117936" label="AllowReaderForAccessibility:enabled"/>
   <int value="223662457" label="BackgroundLoadingForDownloads:enabled"/>
   <int value="237964589"
@@ -26250,6 +26252,7 @@
   <int value="636425179" label="mhtml-generator-option"/>
   <int value="637396292" label="AllBookmarks:enabled"/>
   <int value="637452937" label="ChromeHomeSurvey:enabled"/>
+  <int value="642037198" label="SoleIntegration:disabled"/>
   <int value="643725031" label="disable-touch-feedback"/>
   <int value="644189071" label="PermissionsBlacklist:enabled"/>
   <int value="646252875" label="ReadItLaterInMenu:enabled"/>
@@ -33023,6 +33026,15 @@
   <int value="2" label="No thanks"/>
 </enum>
 
+<enum name="PasswordCertificateError">
+  <int value="0" label="No error"/>
+  <int value="1" label="Other error"/>
+  <int value="2" label="Authority invalid (e.g., self-signed certificates)"/>
+  <int value="3" label="Date invalid (e.g., expired)"/>
+  <int value="4" label="Common name invalid"/>
+  <int value="5" label="Weak signature algorithm"/>
+</enum>
+
 <enum name="PasswordFormQueryVolume">
   <int value="0" label="New password query"/>
   <int value="1" label="Current query"/>
@@ -43486,6 +43498,7 @@
   <int value="113553577" label="certificate_verifier"/>
   <int value="114468207" label="ssl_name_mismatch_lookup"/>
   <int value="115188287" label="chrome_variations_service"/>
+  <int value="115192205" label="cast_socket"/>
   <int value="115907811" label="safe_browsing_cache_collector"/>
   <int value="116426676" label="gaia_auth_log_out"/>
   <int value="116443055" label="renderer_initiated_download"/>
@@ -43514,6 +43527,7 @@
   <int value="133982351" label="gaia_auth_revoke_token"/>
   <int value="134289752" label="gaia_auth_exchange_cookies"/>
   <int value="134729048" label="chrome_feedback_report_app"/>
+  <int value="134755844" label="cast_keep_alive_delegate"/>
   <int value="135118587" label="parallel_download_job"/>
   <int value="135251783" label="thumbnail_source"/>
   <int value="135636011" label="devtools_handle_front_end_messages"/>
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 166bf4f7..e1204b4 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -34595,6 +34595,25 @@
   </summary>
 </histogram>
 
+<histogram name="Media.Engagement.PreloadList.LoadTime" units="ms">
+  <owner>mlamouri@chromium.org</owner>
+  <owner>media-dev@chromium.org</owner>
+  <summary>
+    Time taken to load the Media Engagement Preloaded List. It should be
+    recorded once per load of the list which will be once per start up with
+    additional loads when the list is updated while running.
+  </summary>
+</histogram>
+
+<histogram name="Media.Engagement.PreloadList.LookupTime" units="ms">
+  <owner>mlamouri@chromium.org</owner>
+  <owner>media-dev@chromium.org</owner>
+  <summary>
+    Time taken to lookup an entry in the Media Engagement Preloaded List. This
+    is recorded for every lookup, regardless of its success.
+  </summary>
+</histogram>
+
 <histogram name="Media.Engagement.ScoreAtPlayback" units="%">
   <owner>beccahughes@chromium.org</owner>
   <owner>media-dev@chromium.org</owner>
@@ -60229,6 +60248,20 @@
   </summary>
 </histogram>
 
+<histogram name="PasswordManager.CertificateErrorsWhileSeeingForms"
+    enum="PasswordCertificateError">
+  <owner>battre@chromium.org</owner>
+  <owner>vabr@chromium.org</owner>
+  <summary>
+    When the password manager sees new forms on the page, it records in this
+    histogram whether there were any SSL certificate errors. The presence of SSL
+    errors likely means that the password manger will stop working, so the
+    reporting is done at the last point when password manager is still
+    guaranteed to be active. Some particular errors are distinguished, with the
+    rest being reported in a catch-all bucket.
+  </summary>
+</histogram>
+
 <histogram name="PasswordManager.EditsInSaveBubble"
     enum="PasswordManagerEditsInSaveBubbleEnum">
   <owner>battre@chromium.org</owner>
diff --git a/tools/perf/contrib/leak_detection/page_sets.py b/tools/perf/contrib/leak_detection/page_sets.py
index 9d193ab3..1929ab4 100644
--- a/tools/perf/contrib/leak_detection/page_sets.py
+++ b/tools/perf/contrib/leak_detection/page_sets.py
@@ -61,7 +61,6 @@
       'http://www.amazon.com',
       'http://www.twitter.com',
       # websites which were found to be leaking in the past
-      'https://www.macys.com',
       'https://www.prezi.com',
       'http://www.time.com',
       'http://infomoney.com.br',
@@ -74,6 +73,7 @@
     resource_loading_urls_list = [
       'https://www.yahoo.com',
       'http://www.quora.com',
+      'https://www.macys.com',
     ]
     for url in urls_list:
       self.AddStory(LeakDetectionPage(url, self, url))
diff --git a/tools/perf/core/trybot_command.py b/tools/perf/core/trybot_command.py
index 089e6dc..3cfeec0 100644
--- a/tools/perf/core/trybot_command.py
+++ b/tools/perf/core/trybot_command.py
@@ -2,615 +2,24 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import argparse
-import base64
-import collections
-import gzip
-import io
-import json
-import logging
-import os
-import platform
-import subprocess
-import tempfile
-import urllib
-import urllib2
-
-
-from core import benchmark_finders
-from core import path_util
-
 from telemetry.util import command_line
-from telemetry.util import matching
 
 
-ALL_CONFIG_BOTS = [
-    'all',
-    'all-win',
-    'all-mac',
-    'all-linux',
-    'all-android'
-]
-
-# Default try bot to use incase builbot is unreachable.
-DEFAULT_TRYBOTS = [
-    'linux_perf_bisect',
-    'mac_10_11_perf_bisect',
-    'winx64_10_perf_bisect',
-    'android_s5_perf_bisect',
-]
-
-CHROMIUM_SRC_PATH = path_util.GetChromiumSrcDir()
-# Mapping of repo to its root path and git remote URL.
-# Values for 'src' key in the map are related to path to the repo in the
-# DEPS file, These values are to used create the DEPS patch along with patch
-# that is being tried.
-REPO_INFO_MAP = {
-    'src': {
-        'src': 'src',
-        'url': 'https://chromium.googlesource.com/chromium/src.git',
-    },
-    'v8': {
-        'src': 'src/v8',
-        'url': 'https://chromium.googlesource.com/v8/v8.git',
-    },
-    'skia': {
-        'src': 'src/third_party/skia',
-        'url': 'https://chromium.googlesource.com/skia.git',
-    },
-    'angle': {
-        'src': 'src/third_party/angle',
-        'url': 'https://chromium.googlesource.com/angle/angle.git',
-    },
-    'catapult': {
-        'src': 'src/third_party/catapult',
-        'url': ('https://chromium.googlesource.com/external/github.com/'
-                'catapult-project/catapult.git')
-    }
-}
-
-_MILO_MASTER_ENDPOINT = ('https://luci-milo.appspot.com/prpc/milo.Buildbot/'
-                        'GetCompressedMasterJSON')
-
-_MILO_RESPONSE_PREFIX = ')]}\'\n'
-
-_DEPRECATED_MESSAGE = ('\nWARNING: This command is deprecated and will be '
-  'REMOVED shortly.\n\nPlease visit https://chromium.googlesource.com/chromium/'
+_DEPRECATED_MESSAGE = ('\nERROR: This command has been removed.'
+  '\n\nPlease visit https://chromium.googlesource.com/chromium/'
   'src/+/master/docs/speed/perf_trybots.md for up-to-date information on '
   'running perf try jobs.\n\n')
 
 
-def _IsPerfBisectBot(builder):
-  return (
-      builder.endswith('_perf_bisect') and
-      # Bisect FYI bots are not meant for testing actual perf regressions.
-      # Hardware configuration on these bots is different from actual bisect bot
-      # and these bots runs E2E integration tests for auto-bisect
-      # using dummy benchmarks.
-      not builder.endswith('fyi_perf_bisect')
-      # Individual bisect bots may be blacklisted here.
-  )
-
-
-assert all(_IsPerfBisectBot(builder) for builder in DEFAULT_TRYBOTS), (
-    'A default trybot is being exluded by the perf bisect bot filter.')
-
-
-class TrybotError(Exception):
-
-  def __str__(self):
-    return '(ERROR) Perf Try Job: %s' % self.args[0]
-
-
-def _ProcessMiloData(data):
-  if not data.startswith(_MILO_RESPONSE_PREFIX):
-    return None
-  data = data[len(_MILO_RESPONSE_PREFIX):]
-
-  try:
-    response_data = json.loads(data)
-  except Exception:
-    return None
-
-  try:
-    decoded_data = base64.b64decode(response_data.get('data'))
-  except Exception:
-    return None
-
-  try:
-    with io.BytesIO(decoded_data) as compressed_file:
-      with gzip.GzipFile(fileobj=compressed_file) as decompressed_file:
-        data_json = decompressed_file.read()
-  except Exception:
-    return None
-
-  return json.loads(data_json)
-
-
-def _GetTrybotList(builders):
-  builders = ['%s' % bot.replace('_perf_bisect', '').replace('_', '-')
-              for bot in builders]
-  builders.extend(ALL_CONFIG_BOTS)
-  return sorted(builders)
-
-
-def _GetBotPlatformFromTrybotName(trybot_name):
-  os_names = ['linux', 'android', 'mac', 'win']
-  try:
-    return next(b for b in os_names if b in trybot_name)
-  except StopIteration:
-    raise TrybotError('Trybot "%s" unsupported for tryjobs.' % trybot_name)
-
-
-def _GetPlatformVariantFromBuilderName(builder):
-  bot_platform = _GetBotPlatformFromTrybotName(builder)
-  # Special case for platform variants that need special configs.
-  if bot_platform == 'win' and 'x64' in builder:
-    return 'win-x64'
-  elif bot_platform == 'android' and 'webview' in builder:
-    return 'android-webview'
-  else:
-    return bot_platform
-
-
-def _GetBuilderNames(trybot_name, builders):
-  """Return platform and its available bot name as dictionary."""
-  if trybot_name in ALL_CONFIG_BOTS:
-    platform_prefix = trybot_name[4:]
-    platform_and_bots = collections.defaultdict(list)
-    for builder in builders:
-      bot_platform = _GetPlatformVariantFromBuilderName(builder)
-      if bot_platform.startswith(platform_prefix):
-        platform_and_bots[bot_platform].append(builder)
-    return platform_and_bots
-  else:
-    builder = '%s_perf_bisect' % trybot_name.replace('-', '_')
-    bot_platform = _GetPlatformVariantFromBuilderName(builder)
-    return {bot_platform: [builder]}
-
-
-_GIT_CMD = 'git'
-
-
-if platform.system() == 'Windows':
-  # On windows, the git command is installed as 'git.bat'
-  _GIT_CMD = 'git.bat'
-
-
-def RunGit(cmd, msg_on_error='', ignore_return_code=False):
-  """Runs the git command with the given arguments.
-
-  Args:
-    cmd: git command arguments.
-    msg_on_error: Message to be displayed on git command error.
-    ignore_return_code: Ignores the return code for git command.
-
-  Returns:
-    The output of the git command as string.
-
-  Raises:
-    TrybotError: This exception is raised when git command fails.
-  """
-  proc = subprocess.Popen(
-      [_GIT_CMD] + cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
-  output, err = proc.communicate()
-  returncode = proc.poll()
-  if returncode:
-    if ignore_return_code:
-      return None
-    raise TrybotError('%s. \n%s \n%s' % (msg_on_error, err, output))
-
-  return output.strip()
-
-
 class Trybot(command_line.ArgParseCommand):
   """Run telemetry perf benchmark on trybot."""
 
   usage = 'botname benchmark_name [<benchmark run options>]'
-  _builders = None
 
   def __init__(self):
-    self._builder_names = None
-
-  @classmethod
-  def _GetBuilderList(cls):
-    if not cls._builders:
-      try:
-        headers = {
-            'Accept': 'application/json',
-            'Content-Type': 'application/json',
-        }
-        values = {'name': 'tryserver.chromium.perf'}
-        data = urllib.urlencode(values)
-        req = urllib2.Request(_MILO_MASTER_ENDPOINT, None, headers)
-        f = urllib2.urlopen(req, json.dumps(values), timeout=10)
-      # In case of any kind of exception, allow tryjobs to use default trybots.
-      # Possible exception are ssl.SSLError, urllib2.URLError,
-      # socket.timeout, socket.error.
-      except Exception:  # pylint: disable=broad-except
-        # Incase of any exception return default trybots.
-        print ('WARNING: Unable to reach builbot to retrieve trybot '
-               'information, tryjob will use default trybots.')
-        cls._builders = DEFAULT_TRYBOTS
-      else:
-        data = _ProcessMiloData(f.read())
-        builders = data.get('builders', {}).keys()
-        # Exclude unsupported bots like win xp and some dummy bots.
-        cls._builders = [bot for bot in builders if _IsPerfBisectBot(bot)]
-
-    return cls._builders
-
-  def _InitializeBuilderNames(self, trybot):
-    self._builder_names = _GetBuilderNames(trybot, self._GetBuilderList())
-
-  @classmethod
-  def CreateParser(cls):
-    parser = argparse.ArgumentParser(
-        ('Run telemetry benchmarks on trybot. You can add all the benchmark '
-         'options available except the --browser option'),
-        formatter_class=argparse.RawTextHelpFormatter)
-    return parser
-
-  @classmethod
-  def ProcessCommandLineArgs(cls, parser, options, extra_args, environment):
-    del environment  # unused
-    for arg in extra_args:
-      if arg == '--browser' or arg.startswith('--browser='):
-        parser.error('--browser=... is not allowed when running trybot.')
-    all_benchmarks = benchmark_finders.GetAllPerfBenchmarks()
-    all_benchmarks.extend(benchmark_finders.GetAllContribBenchmarks())
-    all_benchmark_names = [b.Name() for b in all_benchmarks]
-    all_benchmarks_by_names = {b.Name(): b for b in all_benchmarks}
-    benchmark_class = all_benchmarks_by_names.get(options.benchmark_name, None)
-    if not benchmark_class:
-      possible_benchmark_names = matching.GetMostLikelyMatchedObject(
-          all_benchmark_names, options.benchmark_name)
-      parser.error(
-          'No benchmark named "%s". Do you mean any of those benchmarks '
-          'below?\n%s' % (
-              options.benchmark_name, '\n'.join(possible_benchmark_names)))
-    is_benchmark_disabled, reason = cls.IsBenchmarkDisabledOnTrybotPlatform(
-        benchmark_class, options.trybot)
-    also_run_disabled_option = '--also-run-disabled-tests'
-    if is_benchmark_disabled and also_run_disabled_option not in extra_args:
-      parser.error('%s To run the benchmark on trybot anyway, add '
-                   '%s option.' % (reason, also_run_disabled_option))
-
-  @classmethod
-  def IsBenchmarkDisabledOnTrybotPlatform(cls, benchmark_class, trybot_name):
-    """Return whether benchmark will be disabled on trybot platform.
-
-    Note that we cannot tell with certainty whether the benchmark will be
-    disabled on the trybot platform since the disable logic can be very dynamic
-    and can only be verified on the trybot server platform.
-
-    We are biased on the side of enabling the benchmark, and attempt to
-    early discover whether the benchmark will be disabled as our best.
-
-    It should never be the case that the benchmark will be enabled on the test
-    platform but this method returns True.
-
-    Returns:
-      A tuple (is_benchmark_disabled, reason) whereas |is_benchmark_disabled| is
-      a boolean that tells whether we are sure that the benchmark will be
-      disabled, and |reason| is a string that shows the reason why we think the
-      benchmark is disabled for sure.
-    """
-    # TODO(rnephew): This method has been a noop for awhile now. Decorators and
-    # ShouldDisable() are deprecated in favor of StoryExpectations(). That
-    # is in turn being replaced by 1-click disabling via SoM. Once 1-click
-    # diabling is ready this should be updated to use it.
-    del benchmark_class, trybot_name  # unused until updated.
-    return False, ''
-
-  @classmethod
-  def AddCommandLineArgs(cls, parser, environment):
-    del environment  # unused
-    available_bots = _GetTrybotList(cls._GetBuilderList())
-    parser.add_argument(
-        'trybot', choices=available_bots,
-        help=('specify which bots to run telemetry benchmarks on. '
-              ' Allowed values are:\n' + '\n'.join(available_bots)),
-        metavar='<trybot name>')
-    parser.add_argument(
-        'benchmark_name', type=str,
-        help=('specify which benchmark to run. To see all available benchmarks,'
-              ' run `run_benchmark list`'),
-        metavar='<benchmark name>')
-    parser.add_argument(
-        '--repo_path', type=str, default=CHROMIUM_SRC_PATH,
-        help=("""specify the repo path where the patch is created.'
-This argument should only be used if the changes are made outside chromium repo.
-E.g.,
-1) Assume you are running run_benchmarks command from $HOME/cr/src/ directory:'
-  a) If your changes are in $HOME/cr/src/v8, then --repo_path=v8 or
-     --repo-path=$HOME/cr/src/v8
-  b) If your changes are in $HOME/cr/src/third_party/catapult, then
-     --repo_path=third_party/catapult or
-     --repo_path = $HOME/cr/src/third_party/catapult'
-  c) If your changes are not relative to src/ e.g. you created changes in some
-     other directory say $HOME/mydir/v8/v8/, then the
-     --repo_path=$HOME/mydir/v8/v8
-2) Assume you are running run_benchmarks command not relative to src i.e.,
-   you are running from $HOME/mydir/ directory:'
-   a) If your changes are in $HOME/cr/src/v8, then --repo-path=$HOME/cr/src/v8
-   b) If your changes are in $HOME/cr/src/third_party/catapult, then
-      --repo_path=$HOME/cr/src/third_party/catapult'
-  c) If your changes are in $HOME/mydir/v8/v8/, then the
-     --repo_path=$HOME/mydir/v8/v8 or --repo_path=v8/v8"""),
-        metavar='<repo path>')
-    parser.add_argument(
-        '--deps_revision', type=str, default=None,
-        help=('specify DEPS revision to modify DEPS entry in Chromium to a '
-              'certain pushed revision.\n'
-              'This revision overrides value in DEPS on TOT Chromium for the '
-              'repo specified in --repo_path.\nIt is applied for both with and '
-              'wihout patch.'),
-        metavar='<deps revision>')
+    pass
 
   def Run(self, options, extra_args=None):
-    """Sends a tryjob to a perf trybot.
-
-    This creates a branch, telemetry-tryjob, switches to that branch, edits
-    the bisect config, commits it, uploads the CL, and runs a
-    tryjob on the given bot.
-    """
-    if extra_args is None:
-      extra_args = []
-    self._InitializeBuilderNames(options.trybot)
-
     print _DEPRECATED_MESSAGE
 
-    return self._AttemptTryjob(options, extra_args)
-
-  def _GetPerfConfig(self, bot_platform, arguments):
-    """Generates the perf config for try job.
-
-    Args:
-      bot_platform: Name of the platform to be generated.
-      arguments: Command line arguments.
-
-    Returns:
-      A dictionary with perf config parameters.
-    """
-    # To make sure that we don't mutate the original args
-    arguments = arguments[:]
-
-    # Always set verbose logging for later debugging
-    if '-v' not in arguments and '--verbose' not in arguments:
-      arguments.append('--verbose')
-
-    # Generate the command line for the perf trybots
-    target_arch = 'ia32'
-    if any(arg == '--chrome-root' or arg.startswith('--chrome-root=') for arg
-           in arguments):
-      raise ValueError(
-          'Trybot does not suport --chrome-root option set directly '
-          'through command line since it may contain references to your local '
-          'directory')
-
-    arguments.insert(0, 'src/tools/perf/run_benchmark')
-    if bot_platform == 'android':
-      arguments.insert(1, '--browser=android-chromium')
-    elif bot_platform == 'android-webview':
-      arguments.insert(1, '--browser=android-webview')
-    elif bot_platform == 'win-x64':
-      arguments.insert(1, '--browser=release_x64')
-      target_arch = 'x64'
-    else:
-      arguments.insert(1, '--browser=release')
-
-    dummy_parser = argparse.ArgumentParser()
-    dummy_parser.add_argument('--output-format', action='append')
-    args, _ = dummy_parser.parse_known_args(arguments)
-    if not args.output_format or 'html' not in args.output_format:
-      arguments.append('--output-format=html')
-
-    command = ' '.join(arguments)
-
-    return {
-        'command': command,
-        'repeat_count': '1',
-        'max_time_minutes': '120',
-        'truncate_percent': '0',
-        'target_arch': target_arch,
-    }
-
-  def _GetRepoAndBranchName(self, repo_path):
-    """Gets the repository name and working branch name.
-
-    Args:
-      repo_path: Path to the repository.
-
-    Returns:
-      Repository name and branch name as tuple.
-
-    Raises:
-      TrybotError: This exception is raised for the following cases:
-        1. Try job is for non-git repository or in invalid branch.
-        2. Un-committed changes in the current branch.
-        3. No local commits in the current branch.
-    """
-    # If command runs successfully, then the output will be repo root path.
-    # and current branch name.
-    output = RunGit(['rev-parse', '--abbrev-ref', '--show-toplevel', 'HEAD'],
-                    ('%s is not a git repository, must be in a git repository '
-                     'to send changes to trybots' % os.getcwd()))
-
-    repo_info = output.split()
-    # Assuming the base directory name is same as repo project name set in
-    # codereviews.settings file.
-    repo_name = os.path.basename(repo_info[0]).strip()
-    branch_name = repo_info[1].strip()
-
-    if branch_name == 'HEAD':
-      raise TrybotError('Not on a valid branch, looks like branch '
-                        'is dettached. [branch:%s]' % branch_name)
-
-    # Check if the tree is dirty: make sure the index is up to date and then
-    # run diff-index
-    RunGit(['update-index', '--refresh', '-q'], ignore_return_code=True)
-    output = RunGit(['diff-index', 'HEAD'])
-    if output:
-      raise TrybotError(
-          'Cannot send a try job with a dirty tree.\nPlease commit locally and '
-          'upload your changes for review in %s repository.' % repo_path)
-
-    return (repo_name, branch_name)
-
-  def _GetBaseGitHashForRepo(self, branch_name, git_url):
-    """Gets the base revision for the repo on which local changes are made.
-
-    Finds the upstream of the current branch that it is set to and gets
-    the HEAD revision from upstream. This also checks if the remote URL on
-    the upstream is supported by Perf Try job.
-
-    Args:
-      branch_name: Current working branch name.
-      git_url: Remote URL of the repo.
-
-    Returns:
-      Git hash of the HEAD revision from the upstream branch.
-
-    Raises:
-      TrybotError: This exception is raised when a GIT command fails or if the
-      remote URL of the repo found is not supported.
-    """
-    # Check if there is any upstream branch associated with current working
-    # branch, Once the upstream branch is found i.e., then validates the
-    # remote URL and then returns the HEAD revision from the remote branch.
-    while not self._IsRepoSupported(branch_name, git_url):
-      branch_name = RunGit(
-          ['rev-parse', '--abbrev-ref', '%s@{upstream}' % branch_name],
-          'Failed to get upstream branch name.')
-
-    return RunGit(
-        ['rev-parse', '%s@{upstream}' % branch_name],
-        'Failed to get base revision hash on upstream.')
-
-  def _IsRepoSupported(self, current_branch, repo_git_url):
-    cur_remote = RunGit(
-        ['config', 'branch.%s.remote'% current_branch],
-        'Failed to get branch.%s.remote from git config' % current_branch)
-    cur_remote = cur_remote.strip()
-    if cur_remote == '.':
-      return False
-    cur_remote_url = RunGit(
-        ['config', 'remote.%s.url' % cur_remote],
-        'Failed to get remote.%s.url from git config' % cur_remote)
-    if cur_remote_url.lower() == repo_git_url:
-      return True
-    raise TrybotError('URL %s on remote %s is not recognized on branch.'% (
-        cur_remote_url, cur_remote))
-
-  def _GetChangeList(self):
-    """Gets the codereview URL for the current changes."""
-    temp_file = None
-    json_output = None
-    try:
-      fd, temp_file = tempfile.mkstemp(suffix='.json', prefix='perf_try_cl')
-      os.close(fd)
-      RunGit(['cl', 'issue', '--json', temp_file],
-              'Failed to run "git cl issue" command.')
-      with open(temp_file, 'r') as f:
-        json_output = json.load(f)
-    finally:
-      try:
-        if temp_file:
-          os.remove(temp_file)
-      except OSError:
-        pass
-
-    if not json_output.get('issue'):
-      raise TrybotError(
-          'PLEASE NOTE: The workflow for Perf Try jobs is changed. '
-          'In order to run the perf try job, you must first upload your '
-          'changes for review.')
-    return json_output.get('issue_url')
-
-  def _AttemptTryjob(self, options, extra_args):
-    """Attempts to run a tryjob from a repo directory.
-
-    Args:
-      options: Command line arguments to run benchmark.
-      extra_args: Extra arugments to run benchmark.
-
-    Returns:
-     If successful returns 0, otherwise 1.
-    """
-    original_workdir = os.getcwd()
-    repo_path = os.path.abspath(options.repo_path)
-    try:
-      # Check the existence of repo path.
-      if not os.path.exists(repo_path):
-        raise TrybotError('Repository path "%s" does not exist, please check '
-                          'the value of <repo_path> argument.' % repo_path)
-      # Change to the repo directory.
-      os.chdir(repo_path)
-      repo_name, branch_name = self._GetRepoAndBranchName(repo_path)
-
-      repo_info = REPO_INFO_MAP.get(repo_name, None)
-      if not repo_info:
-        raise TrybotError('Unsupported repository %s' % repo_name)
-
-      deps_override = None
-      if repo_name != 'src':
-        if not options.deps_revision:
-          options.deps_revision = self._GetBaseGitHashForRepo(
-              branch_name, repo_info.get('url'))
-        deps_override = {repo_info.get('src'): options.deps_revision}
-
-      review_url = self._GetChangeList()
-      print ('\nRunning try job....\nview progress here %s.'
-             '\n\tRepo Name: %s\n\tPath: %s\n\tBranch: %s' % (
-                 review_url, repo_name, repo_path, branch_name))
-
-      for bot_platform in self._builder_names:
-        if not self._builder_names[bot_platform]:
-          logging.warning('No builder is found for %s', bot_platform)
-          continue
-        try:
-          arguments = [options.benchmark_name] + extra_args
-          self._RunTryJob(bot_platform, arguments, deps_override)
-        # Even if git cl try throws TrybotError exception for any platform,
-        # keep sending try jobs to other platforms.
-        except TrybotError, err:
-          print err
-    except TrybotError, error:
-      print error
-      return 1
-    finally:
-      # Restore to original working directory.
-      os.chdir(original_workdir)
     return 0
-
-  def _RunTryJob(self, bot_platform, arguments, deps_override):
-    """Executes perf try job with benchmark test properties.
-
-    Args:
-      bot_platform: Name of the platform to be generated.
-      arguments: Command line arguments.
-      deps_override: DEPS revision if needs to be overridden.
-
-    Raises:
-      TrybotError: When trybot fails to upload CL or run git try.
-    """
-    config = self._GetPerfConfig(bot_platform, arguments)
-
-    # Generate git try command for available bots.
-    git_try_command = ['cl', 'try', '-m', 'tryserver.chromium.perf']
-
-     # Add Perf Test config to git try --properties arg.
-    git_try_command.extend(['-p', 'perf_try_config=%s' % json.dumps(config)])
-
-    error_msg_on_fail = 'Could not try CL for %s' % bot_platform
-    # Add deps overrides to git try --properties arg.
-    if deps_override:
-      git_try_command.extend([
-          '-p', 'deps_revision_overrides=%s' % json.dumps(deps_override)])
-      error_msg_on_fail += ' with DEPS override (%s)' % deps_override
-    for bot in self._builder_names[bot_platform]:
-      git_try_command.extend(['-b', bot])
-
-    RunGit(git_try_command, error_msg_on_fail)
-    print 'Perf Try job started for %s platform.' % bot_platform
diff --git a/tools/perf/core/trybot_command_unittest.py b/tools/perf/core/trybot_command_unittest.py
deleted file mode 100644
index 07dacc96..0000000
--- a/tools/perf/core/trybot_command_unittest.py
+++ /dev/null
@@ -1,931 +0,0 @@
-# Copyright 2015 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-import argparse
-import base64
-import io
-import gzip
-import json
-import logging
-import os
-import StringIO
-import sys
-import tempfile
-import unittest
-
-from core import trybot_command
-import mock
-
-
-class FakeProcess(object):
-
-  def __init__(self, expected_responses):
-    self._communicate = expected_responses[1:]
-    self._poll = expected_responses[0]
-
-  def communicate(self):
-    return self._communicate
-
-  def poll(self):
-    return self._poll
-
-
-class TrybotCommandTest(unittest.TestCase):
-
-  # pylint: disable=protected-access
-
-  def setUp(self):
-    self.log_output = StringIO.StringIO()
-    self.stream_handler = logging.StreamHandler(self.log_output)
-    logging.getLogger().addHandler(self.stream_handler)
-    self._subprocess_patcher = mock.patch('core.trybot_command.subprocess')
-    self._mock_subprocess = self._subprocess_patcher.start()
-    self._urllib2_patcher = mock.patch('core.trybot_command.urllib2')
-    self._urllib2_mock = self._urllib2_patcher.start()
-    self._tempfile_patcher =  mock.patch('core.trybot_command.tempfile')
-    self._tempfile_mock = self._tempfile_patcher.start()
-    # Always set git command to 'git' to simplify testing across platforms.
-    self._original_git_cmd = trybot_command._GIT_CMD
-    trybot_command._GIT_CMD = 'git'
-
-  def tearDown(self):
-    logging.getLogger().removeHandler(self.stream_handler)
-    self.log_output.close()
-    self._subprocess_patcher.stop()
-    self._urllib2_patcher.stop()
-    self._tempfile_patcher.stop()
-    # Reset the cached builders in trybot_command
-    trybot_command.Trybot._builders = None
-    trybot_command._GIT_CMD = self._original_git_cmd
-
-  def _ExpectProcesses(self, expected_args_list):
-    counter = [-1]
-    def side_effect(args, **kwargs):
-      if not expected_args_list:
-        self.fail(
-            'Not expect any Popen() call but got a Popen call with %s\n' % args)
-      del kwargs  # unused
-      counter[0] += 1
-      expected_args, expected_responses = expected_args_list[counter[0]]
-      self.assertEquals(
-          expected_args, args,
-          'Popen() is called with unexpected args.\n Actual: %s.\n'
-          'Expecting (index %i): %s' % (args, counter[0], expected_args))
-      return FakeProcess(expected_responses)
-    self._mock_subprocess.Popen.side_effect = side_effect
-
-  def _MockBuilderList(self):
-    excluded_bots = trybot_command.EXCLUDED_BOTS
-    builders = [bot for bot in self._builder_list if bot not in excluded_bots]
-    return builders
-
-  def _MockTryserverJson(self, bots_dict):
-    data_to_compress = json.dumps({'builders': bots_dict})
-
-    with io.BytesIO() as dst:
-      with gzip.GzipFile(fileobj=dst, mode='wb') as src:
-        src.write(data_to_compress)
-      compressed_data = dst.getvalue()
-
-    milo_data = {'data': base64.b64encode(compressed_data)}
-    milo_data = json.dumps(milo_data)
-    milo_data = trybot_command._MILO_RESPONSE_PREFIX + milo_data
-
-    data = mock.Mock()
-    data.read.return_value = milo_data
-    self._urllib2_mock.urlopen.return_value = data
-
-  def _MockTempFile(self, issue, issue_url):
-    fd, temp_file = tempfile.mkstemp(suffix='.json', prefix='cl')
-    with open(temp_file, 'w') as f:
-      json.dump({"issue": issue, "issue_url": issue_url}, f)
-    self._tempfile_mock.mkstemp.return_value = (fd, temp_file)
-    return temp_file
-
-  def _AssertTryBotExceptions(self, message, func, *args):
-    with self.assertRaises(trybot_command.TrybotError) as e:
-      func(*args)
-    self.assertIn(message, e.exception.message)
-
-  def _SetupTrybotCommand(
-      self, try_json_dict, trybot, benchmark_name='sunspider',
-      repo_path=trybot_command.CHROMIUM_SRC_PATH, deps_revision=None):
-    self._MockTryserverJson(try_json_dict)
-    command = trybot_command.Trybot()
-    command._InitializeBuilderNames(trybot)
-    opts = argparse.Namespace(
-        trybot=trybot, benchmark_name=benchmark_name, repo_path=repo_path,
-        deps_revision=deps_revision)
-
-    return command, opts
-
-  def _GetConfigForTrybot(self, name, platform, extra_benchmark_args=None,
-                          repo_path=trybot_command.CHROMIUM_SRC_PATH,
-                          deps_revision=None):
-    bot = '%s_perf_bisect' % name.replace('', '').replace('-', '_')
-    command, options = self._SetupTrybotCommand(
-        {bot: 'stuff'}, name, repo_path=repo_path, deps_revision=deps_revision)
-    extra_benchmark_args = extra_benchmark_args or []
-    arguments = [options.benchmark_name] + extra_benchmark_args
-    cfg = command._GetPerfConfig(platform, arguments)
-
-    return cfg, command
-
-  def _ExpectedGitTryTestArgs(self, test_name, browser, target_arch='ia32'):
-    return ('perf_try_config={'
-            '"repeat_count": "1", "command": "src/tools/perf/run_benchmark '
-            '--browser=%s %s --verbose --output-format=html", '
-            '"max_time_minutes": "120", '
-            '"target_arch": "%s", "truncate_percent": "0"}' % (
-                browser, test_name, target_arch))
-
-  def testFindAllBrowserTypesList(self):
-    self._MockTryserverJson({
-        'android_nexus4_perf_bisect': 'stuff',
-        'mac_10_9_perf_bisect': 'otherstuff',
-        'win_perf_bisect_builder': 'not a trybot',
-    })
-    expected_trybots_list = [
-        'all',
-        'all-android',
-        'all-linux',
-        'all-mac',
-        'all-win',
-        'android-nexus4',
-        'mac-10-9'
-    ]
-    parser = trybot_command.Trybot.CreateParser()
-    trybot_command.Trybot.AddCommandLineArgs(parser, None)
-    trybot_action = [a for a in parser._actions if a.dest == 'trybot'][0]
-    self.assertEquals(
-        expected_trybots_list,
-        sorted(trybot_action.choices))
-
-  def testFindAllBrowserTypesTrybot(self):
-    self._MockTryserverJson({
-        'android_nexus4_perf_bisect': 'stuff',
-        'mac_10_9_perf_bisect': 'otherstuff',
-        'win_perf_bisect_builder': 'not a trybot',
-        'android_fyi_perf_bisect': 'not meant for actual perf testing'
-    })
-    expected_trybots_list = [
-        'all',
-        'all-android',
-        'all-linux',
-        'all-mac',
-        'all-win',
-        'android-nexus4',
-        'mac-10-9'
-    ]
-
-    parser = trybot_command.Trybot.CreateParser()
-    trybot_command.Trybot.AddCommandLineArgs(parser, None)
-    trybot_action = [a for a in parser._actions if a.dest == 'trybot'][0]
-    self.assertEquals(expected_trybots_list, sorted(trybot_action.choices))
-
-  def testFindAllBrowserTypesNonTrybotBrowser(self):
-    self._MockTryserverJson({})
-    parser = trybot_command.Trybot.CreateParser()
-    trybot_command.Trybot.AddCommandLineArgs(parser, None)
-    trybot_action = [a for a in parser._actions if a.dest == 'trybot'][0]
-    self.assertEquals(
-        ['all', 'all-android', 'all-linux', 'all-mac', 'all-win'],
-        sorted(trybot_action.choices))
-
-  def testConstructor(self):
-    self._MockTryserverJson({
-        'android_nexus4_perf_bisect': 'stuff',
-        'mac_10_9_perf_bisect': 'otherstuff',
-        'win_perf_bisect_builder': 'not a trybot',
-    })
-    command = trybot_command.Trybot()
-    command._InitializeBuilderNames('android-nexus4')
-    self.assertTrue('android' in command._builder_names)
-    self.assertEquals(['android_nexus4_perf_bisect'],
-                      command._builder_names.get('android'))
-
-  def testConstructorTrybotAll(self):
-    self._MockTryserverJson({
-        'android_nexus4_perf_bisect': 'stuff',
-        'android_nexus5_perf_bisect': 'stuff2',
-        'android_webview_nexus6_aosp_perf_bisect': 'stuff3',
-        'mac_10_9_perf_bisect': 'otherstuff',
-        'mac_perf_bisect': 'otherstuff1',
-        'win_perf_bisect': 'otherstuff2',
-        'linux_perf_bisect': 'otherstuff3',
-        'win_x64_perf_bisect': 'otherstuff4',
-        'win_perf_bisect_builder': 'not a trybot',
-    })
-    command = trybot_command.Trybot()
-    command._InitializeBuilderNames('all')
-    self.assertEquals(
-        ['android', 'android-webview', 'linux', 'mac', 'win', 'win-x64'],
-        sorted(command._builder_names))
-    self.assertEquals(
-        ['android_nexus4_perf_bisect', 'android_nexus5_perf_bisect'],
-        sorted(command._builder_names.get('android')))
-    self.assertEquals(
-        ['android_webview_nexus6_aosp_perf_bisect'],
-        sorted(command._builder_names.get('android-webview')))
-    self.assertEquals(
-        ['mac_10_9_perf_bisect', 'mac_perf_bisect'],
-        sorted(command._builder_names.get('mac')))
-    self.assertEquals(
-        ['linux_perf_bisect'], sorted(command._builder_names.get('linux')))
-    self.assertEquals(
-        ['win_perf_bisect'], sorted(command._builder_names.get('win')))
-    self.assertEquals(
-        ['win_x64_perf_bisect'], sorted(command._builder_names.get('win-x64')))
-
-  def testConstructorTrybotAllWin(self):
-    self._MockTryserverJson({
-        'android_nexus4_perf_bisect': 'stuff',
-        'android_nexus5_perf_bisect': 'stuff2',
-        'win_8_perf_bisect': 'otherstuff',
-        'win_perf_bisect': 'otherstuff2',
-        'linux_perf_bisect': 'otherstuff3',
-        'win_x64_perf_bisect': 'otherstuff4',
-        'win_perf_bisect_builder': 'not a trybot',
-        'win_x64_10_perf_bisect': 'otherstuff4',
-        'winx64ati_perf_bisect': 'not a trybot',
-        'winx64nvidia_perf_bisect': 'not a trybot',
-    })
-    command = trybot_command.Trybot()
-    command._InitializeBuilderNames('all-win')
-    self.assertEquals(
-        ['win', 'win-x64'],
-        sorted(command._builder_names))
-    self.assertEquals(
-        ['win_8_perf_bisect', 'win_perf_bisect'],
-        sorted(command._builder_names.get('win')))
-    self.assertNotIn(
-        'win_x64_perf_bisect',
-        sorted(command._builder_names.get('win')))
-    self.assertEquals(
-        sorted(['win_x64_perf_bisect', 'win_x64_10_perf_bisect',
-                'winx64ati_perf_bisect', 'winx64nvidia_perf_bisect']),
-        sorted(command._builder_names.get('win-x64')))
-
-  def testConstructorTrybotAllAndroid(self):
-    self._MockTryserverJson({
-        'android_nexus4_perf_bisect': 'stuff',
-        'android_nexus5_perf_bisect': 'stuff2',
-        'android_webview_nexus6_aosp_perf_bisect': 'stuff3',
-        'win_8_perf_bisect': 'otherstuff',
-        'win_perf_bisect': 'otherstuff2',
-        'linux_perf_bisect': 'otherstuff3',
-        'win_x64_perf_bisect': 'otherstuff4',
-        'win_perf_bisect_builder': 'not a trybot',
-    })
-    command = trybot_command.Trybot()
-    command._InitializeBuilderNames('all-android')
-    self.assertEquals(
-        ['android_nexus4_perf_bisect', 'android_nexus5_perf_bisect'],
-        sorted(command._builder_names.get('android')))
-    self.assertEquals(
-        ['android_webview_nexus6_aosp_perf_bisect'],
-        sorted(command._builder_names.get('android-webview')))
-
-  def testConstructorTrybotAllMac(self):
-    self._MockTryserverJson({
-        'android_nexus4_perf_bisect': 'stuff',
-        'win_8_perf_bisect': 'otherstuff',
-        'mac_perf_bisect': 'otherstuff2',
-        'win_perf_bisect_builder': 'not a trybot',
-    })
-    command = trybot_command.Trybot()
-    command._InitializeBuilderNames('all-mac')
-    self.assertEquals(
-        ['mac'],
-        sorted(command._builder_names))
-    self.assertEquals(
-        ['mac_perf_bisect'],
-        sorted(command._builder_names.get('mac')))
-
-  def testConstructorTrybotAllLinux(self):
-    self._MockTryserverJson({
-        'android_nexus4_perf_bisect': 'stuff',
-        'linux_perf_bisect': 'stuff1',
-        'win_8_perf_bisect': 'otherstuff',
-        'mac_perf_bisect': 'otherstuff2',
-        'win_perf_bisect_builder': 'not a trybot',
-    })
-    command = trybot_command.Trybot()
-    command._InitializeBuilderNames('all-linux')
-    self.assertEquals(
-        ['linux'],
-        sorted(command._builder_names))
-    self.assertEquals(
-        ['linux_perf_bisect'],
-        sorted(command._builder_names.get('linux')))
-
-  @mock.patch('core.trybot_command.os.path.abspath',
-              mock.MagicMock(return_value='/dummy/path'))
-  @mock.patch('core.trybot_command.os.path.exists',
-              mock.MagicMock(return_value=False))
-  def testRepoPathExists(self):
-    command, options = self._SetupTrybotCommand(
-        {'linux_perf_bisect': 'stuff'}, 'linux', repo_path='/dummy/path')
-    command.Run(options)
-    self.assertIn((
-        '(ERROR) Perf Try Job: Repository path "/dummy/path" does not exist, '
-        'please check the value of <repo_path> argument.'),
-                      sys.stdout.getvalue().strip())
-
-  def testNoGit(self):
-    command, options = self._SetupTrybotCommand({'linux_perf_bisect': 'stuff'},
-                                                'linux')
-    self._ExpectProcesses((
-        (['git', 'rev-parse', '--abbrev-ref', '--show-toplevel', 'HEAD'],
-         (128, None, None)),
-    ))
-    self._AssertTryBotExceptions(
-        ('%s is not a git repository, must be in a git repository to send '
-         'changes to trybots.' % os.getcwd()),
-        command._GetRepoAndBranchName,
-        options.repo_path
-    )
-
-  def testDettachedBranch(self):
-    command, options = self._SetupTrybotCommand({'linux_perf_bisect': 'stuff'},
-                                                'linux')
-    self._ExpectProcesses((
-        (['git', 'rev-parse', '--abbrev-ref', '--show-toplevel', 'HEAD'],
-         (0, '/root/path_to/repo/src\nHEAD\n', None)),
-    ))
-    self._AssertTryBotExceptions(
-        'Not on a valid branch, looks like branch is dettached. [branch:HEAD]',
-        command._GetRepoAndBranchName,
-        options.repo_path
-    )
-
-  def testDirtyTree(self):
-    command, options = self._SetupTrybotCommand({'linux_perf_bisect': 'stuff'},
-                                                'linux')
-    self._ExpectProcesses((
-        (['git', 'rev-parse', '--abbrev-ref', '--show-toplevel', 'HEAD'],
-         (0, '/root/path_to/repo/src\nbr\n', None)),
-        (['git', 'update-index', '--refresh', '-q'], (0, '', None,)),
-        (['git', 'diff-index', 'HEAD'], (0, 'dirty tree', None)),
-    ))
-    self._AssertTryBotExceptions(
-        'Cannot send a try job with a dirty tree.',
-        command._GetRepoAndBranchName,
-        options.repo_path
-    )
-
-  def testGetRepoAndBranchName(self):
-    command, options = self._SetupTrybotCommand({'linux_perf_bisect': 'stuff'},
-                                                'linux')
-    self._ExpectProcesses((
-        (['git', 'rev-parse', '--abbrev-ref', '--show-toplevel', 'HEAD'],
-         (0, '/root/path_to/repo/src\nbr\n', None)),
-        (['git', 'update-index', '--refresh', '-q'], (0, '', None,)),
-        (['git', 'diff-index', 'HEAD'], (0, '', None)),
-    ))
-    self.assertEquals(
-        command._GetRepoAndBranchName(options.repo_path), ('src', 'br'))
-
-  def testErrorOnBrowserArgSpecified(self):
-    parser = trybot_command.Trybot.CreateParser()
-    options, extra_args = parser.parse_known_args(
-        ['sunspider', '--trybot=android-all', '--browser=mac'])
-    with self.assertRaises(SystemExit):
-      trybot_command.Trybot.ProcessCommandLineArgs(
-          parser, options, extra_args, None)
-
-  def testConfigAndroid(self):
-    config, _ = self._GetConfigForTrybot('android-nexus4', 'android')
-    self.assertEquals(
-        {'command': ('src/tools/perf/run_benchmark '
-                     '--browser=android-chromium sunspider --verbose '
-                     '--output-format=html'),
-         'max_time_minutes': '120',
-         'repeat_count': '1',
-         'target_arch': 'ia32',
-         'truncate_percent': '0'
-        }, config)
-
-  def testConfigAndroidWebview(self):
-    config, _ = self._GetConfigForTrybot(
-        'android-webview-nexus6-aosp', 'android-webview')
-    self.assertEquals(
-        {'command': ('src/tools/perf/run_benchmark '
-                     '--browser=android-webview sunspider --verbose '
-                     '--output-format=html'),
-         'max_time_minutes': '120',
-         'repeat_count': '1',
-         'target_arch': 'ia32',
-         'truncate_percent': '0'
-        }, config)
-
-  def testConfigMac(self):
-    config, _ = self._GetConfigForTrybot('mac-10-9', 'mac')
-    self.assertEquals(
-        {'command': ('src/tools/perf/run_benchmark '
-                     '--browser=release sunspider --verbose '
-                     '--output-format=html'),
-         'max_time_minutes': '120',
-         'repeat_count': '1',
-         'target_arch': 'ia32',
-         'truncate_percent': '0'
-        }, config)
-
-  def testConfigWinX64(self):
-    config, _ = self._GetConfigForTrybot('win-x64', 'win-x64')
-
-    self.assertEquals(
-        {'command': ('src/tools/perf/run_benchmark '
-                     '--browser=release_x64 sunspider --verbose '
-                     '--output-format=html'),
-         'max_time_minutes': '120',
-         'repeat_count': '1',
-         'target_arch': 'x64',
-         'truncate_percent': '0'
-        }, config)
-
-  def testVerboseOptionIsNotAddedTwice(self):
-    config, _ = self._GetConfigForTrybot(
-        'win-x64', 'win-x64', extra_benchmark_args=['-v'])
-    self.assertEquals(
-        {'command': ('src/tools/perf/run_benchmark '
-                     '--browser=release_x64 sunspider -v '
-                     '--output-format=html'),
-         'max_time_minutes': '120',
-         'repeat_count': '1',
-         'target_arch': 'x64',
-         'truncate_percent': '0'
-        }, config)
-
-  def testConfigWinX64WithNoHyphen(self):
-    config, _ = self._GetConfigForTrybot('winx64nvidia', 'win-x64')
-    self.assertEquals(
-        {'command': ('src/tools/perf/run_benchmark '
-                     '--browser=release_x64 sunspider --verbose '
-                     '--output-format=html'),
-         'max_time_minutes': '120',
-         'repeat_count': '1',
-         'target_arch': 'x64',
-         'truncate_percent': '0'
-        }, config)
-
-  def testUnsupportedTrybot(self):
-    self.assertRaises(
-        trybot_command.TrybotError,
-        trybot_command._GetBuilderNames,
-        'arms-nvidia',
-        {'win_perf_bisect': 'stuff'}
-    )
-
-  def testConfig_EmptyOutputFormat_AddsHtml(self):
-    config, _ = self._GetConfigForTrybot('android-nexus4', 'android')
-    self.assertEquals(
-        {'command': ('src/tools/perf/run_benchmark '
-                     '--browser=android-chromium sunspider --verbose '
-                     '--output-format=html'),
-         'max_time_minutes': '120',
-         'repeat_count': '1',
-         'target_arch': 'ia32',
-         'truncate_percent': '0'
-        }, config)
-
-  def testConfig_OtherOutputFormat_AddsHtml(self):
-    config, _ = self._GetConfigForTrybot('android-nexus4', 'android',
-        extra_benchmark_args=['--output-format=foo'])
-    self.assertEquals(
-        {'command': ('src/tools/perf/run_benchmark '
-                     '--browser=android-chromium sunspider --output-format=foo '
-                     '--verbose --output-format=html'),
-         'max_time_minutes': '120',
-         'repeat_count': '1',
-         'target_arch': 'ia32',
-         'truncate_percent': '0'
-        }, config)
-
-  def testConfig_HtmlOutputFormat_Skipped(self):
-    config, _ = self._GetConfigForTrybot('android-nexus4', 'android',
-        extra_benchmark_args=['--output-format', 'html'])
-    self.assertEquals(
-        {'command': ('src/tools/perf/run_benchmark '
-                     '--browser=android-chromium sunspider '
-                     '--output-format html --verbose'),
-         'max_time_minutes': '120',
-         'repeat_count': '1',
-         'target_arch': 'ia32',
-         'truncate_percent': '0'
-        }, config)
-
-  def testConfig_HtmlOutputFormat_UsesEquals_Skipped(self):
-    config, _ = self._GetConfigForTrybot('android-nexus4', 'android',
-        extra_benchmark_args=['--output-format=html'])
-    self.assertEquals(
-        {'command': ('src/tools/perf/run_benchmark '
-                     '--browser=android-chromium sunspider '
-                     '--output-format=html --verbose'),
-         'max_time_minutes': '120',
-         'repeat_count': '1',
-         'target_arch': 'ia32',
-         'truncate_percent': '0'
-        }, config)
-
-  def testGetChangeListCommandError(self):
-    temp_file = self._MockTempFile(None, None)
-    command, _ = self._SetupTrybotCommand(
-        {'linux_perf_bisect': 'stuff'}, 'linux')
-    self._ExpectProcesses((
-        (['git', 'cl', 'issue', '--json', temp_file], (128, None, None)),
-    ))
-    self._AssertTryBotExceptions(
-        'Failed to run "git cl issue" command.',
-        command._GetChangeList)
-
-  def testGetChangeListNoIssues(self):
-    temp_file = self._MockTempFile(None, None)
-    command, _ = self._SetupTrybotCommand(
-        {'linux_perf_bisect': 'stuff'}, 'linux')
-    self._ExpectProcesses((
-        (['git', 'cl', 'issue', '--json', temp_file],
-         (0, 'Issue number: None (None)', None)),
-    ))
-    self._AssertTryBotExceptions(
-        ('PLEASE NOTE: The workflow for Perf Try jobs is changed. '
-         'In order to run the perf try job, you must first upload your '
-         'changes for review.'),
-        command._GetChangeList)
-
-  def testGetChangeListWithIssue(self):
-    temp_file = self._MockTempFile(
-        12345, 'https://chromium-review.googlesource.com/c/12345')
-    command, _ = self._SetupTrybotCommand(
-        {'linux_perf_bisect': 'stuff'}, 'linux')
-    self._ExpectProcesses((
-        (['git', 'cl', 'issue', '--json', temp_file],
-         (0,
-          'stuff https://chromium-review.googlesource.com/c/12345 stuff',
-          None)),
-    ))
-    self.assertEquals('https://chromium-review.googlesource.com/c/12345',
-                      command._GetChangeList())
-
-  def testRunTryJobFailed(self):
-    test_args = self._ExpectedGitTryTestArgs('sunspider', 'release')
-    command, options = self._SetupTrybotCommand(
-        {'linux_perf_bisect': 'stuff'}, 'linux', repo_path='path_to_repo/src')
-    arguments = [options.benchmark_name] + []
-    self._ExpectProcesses((
-        (['git', 'cl', 'try', '-m', 'tryserver.chromium.perf',
-          '-p', test_args,
-          '-b',
-          'linux_perf_bisect'], (128, None, None)),))
-    self._AssertTryBotExceptions(
-        'Could not try CL for linux',
-        command._RunTryJob, 'linux', arguments, None)
-
-  def testRunTryJobWithDepsOverrideFailed(self):
-    test_args = self._ExpectedGitTryTestArgs('sunspider', 'release')
-    deps_override_arg = 'deps_revision_overrides={"src/v8": "feedbeed"}'
-
-    command, options = self._SetupTrybotCommand(
-        {'linux_perf_bisect': 'stuff'}, 'linux', repo_path='path_to_repo/v8',
-        deps_revision='feedbeed')
-    arguments = [options.benchmark_name] + []
-    self._ExpectProcesses((
-        (['git', 'cl', 'try', '-m', 'tryserver.chromium.perf',
-          '-p', test_args,
-          '-p', deps_override_arg,
-          '-b',
-          'linux_perf_bisect'], (128, None, None)),))
-    self._AssertTryBotExceptions(
-        'Could not try CL for linux with DEPS override',
-        command._RunTryJob, 'linux', arguments, {'src/v8': 'feedbeed'})
-
-  def testRunTryJobSuccess(self):
-    test_args = self._ExpectedGitTryTestArgs('sunspider', 'release')
-    command, options = self._SetupTrybotCommand(
-        {'linux_perf_bisect': 'stuff'}, 'linux', repo_path='path_to_repo/src')
-    arguments = [options.benchmark_name] + []
-    self._ExpectProcesses((
-        (['git', 'cl', 'try', '-m', 'tryserver.chromium.perf',
-          '-p', test_args,
-          '-b',
-          'linux_perf_bisect'], (0, '', None)),))
-    command._RunTryJob('linux', arguments, None)
-    self.assertEquals('Perf Try job started for linux platform.',
-                      sys.stdout.getvalue().strip())
-
-  def testNoUpstream(self):
-    command, _ = self._SetupTrybotCommand({'linux_perf_bisect': 'stuff'},
-                                          'linux')
-    self._ExpectProcesses((
-        (['git', 'config', 'branch.br.remote'], (0, '.', None)),
-        (['git', 'rev-parse', '--abbrev-ref', 'br@{upstream}'],
-         (128, 'None', None,)),
-    ))
-    self._AssertTryBotExceptions(
-        'Failed to get upstream branch name.',
-        command._GetBaseGitHashForRepo, 'br', 'http://repo/git/url.git')
-
-  def testGitConfigBranchRemote(self):
-    command, _ = self._SetupTrybotCommand({'linux_perf_bisect': 'stuff'},
-                                          'linux')
-    self._ExpectProcesses((
-        (['git', 'config', 'branch.br.remote'],
-         (128, 'None', None)),
-    ))
-    self._AssertTryBotExceptions(
-        'Failed to get branch.br.remote from git config',
-        command._GetBaseGitHashForRepo, 'br', 'http://repo/git/url.git')
-
-  def testGitConfigBranchRemoteUrl(self):
-    command, _ = self._SetupTrybotCommand({'linux_perf_bisect': 'stuff'},
-                                          'linux')
-    self._ExpectProcesses((
-        (['git', 'config', 'branch.br.remote'], (0, '.', None)),
-        (['git', 'rev-parse', '--abbrev-ref', 'br@{upstream}'],
-         (0, 'br1', None,)),
-        (['git', 'config', 'branch.br1.remote'], (0, 'origin', None)),
-        (['git', 'config', 'remote.origin.url'], (128, 'None', None)),
-    ))
-    self._AssertTryBotExceptions(
-        'Failed to get remote.origin.url from git config',
-        command._GetBaseGitHashForRepo, 'br', 'http://repo/git/url.git')
-
-  def testGetBaseGitHashForRemoteURLMatchFound(self):
-    command, _ = self._SetupTrybotCommand({'linux_perf_bisect': 'stuff'},
-                                          'linux')
-    self._ExpectProcesses((
-        (['git', 'config', 'branch.br.remote'],
-         (0, '.', None)),
-        (['git', 'rev-parse', '--abbrev-ref', 'br@{upstream}'],
-         (0, 'br1', None,)),
-        (['git', 'config', 'branch.br1.remote'], (0, 'origin', None)),
-        (['git', 'config', 'remote.origin.url'],
-         (0, 'http://repo/git/url.git', None)),
-        (['git', 'rev-parse', 'br1@{upstream}'], (0, 'feedbeed', None)),
-    ))
-    self.assertEquals(
-        command._GetBaseGitHashForRepo('br', 'http://repo/git/url.git'),
-        'feedbeed')
-
-  def testGetBaseGitHashForRemoteUrlNoMatchFound(self):
-    command, _ = self._SetupTrybotCommand({'linux_perf_bisect': 'stuff'},
-                                          'linux')
-    self._ExpectProcesses((
-        (['git', 'config', 'branch.br.remote'],
-         (0, '.', None)),
-        (['git', 'rev-parse', '--abbrev-ref', 'br@{upstream}'],
-         (0, 'br1', None,)),
-        (['git', 'config', 'branch.br1.remote'],
-         (0, 'origin', None)),
-        (['git', 'config', 'remote.origin.url'],
-         (0, 'http://non_maching_repo/git/url.git', None)),
-        (['git', 'rev-parse', 'br1@{upstream}'],
-         (0, 'feedbeed', None)),
-    ))
-    self._AssertTryBotExceptions(
-        ('URL http://non_maching_repo/git/url.git on remote origin is not '
-         'recognized on branch'),
-        command._GetBaseGitHashForRepo, 'br', 'http://repo/git/url.git')
-
-  @mock.patch('core.trybot_command.os.chdir', mock.MagicMock())
-  @mock.patch('core.trybot_command.os.path.exists',
-              mock.MagicMock(return_value=True))
-  def testAttemptTryjobForCrRepo(self):
-    test_args = self._ExpectedGitTryTestArgs('sunspider', 'release')
-    command, options = self._SetupTrybotCommand({'linux_perf_bisect': 'stuff'},
-                                                'linux')
-    temp_file = self._MockTempFile(
-        12345, 'https://chromium-review.googlesource.com/c/12345')
-
-    self._ExpectProcesses((
-        (['git', 'rev-parse', '--abbrev-ref', '--show-toplevel', 'HEAD'],
-         (0, '/root/path_to/repo/src\nbr\n', None)),
-        (['git', 'update-index', '--refresh', '-q'], (0, '', None,)),
-        (['git', 'diff-index', 'HEAD'], (0, '', None)),
-        (['git', 'cl', 'issue', '--json', temp_file],
-         (0,
-          'stuff https://chromium-review.googlesource.com/c/12345 stuff',
-          None)),
-        (['git', 'cl', 'try', '-m', 'tryserver.chromium.perf',
-          '-p', test_args, '-b', 'linux_perf_bisect'], (0, '', None))
-    ))
-
-    with mock.patch('core.trybot_command.os.path.abspath',
-                    return_value=trybot_command.CHROMIUM_SRC_PATH):
-      command._AttemptTryjob(options, [])
-
-    output = (
-        'Running try job....\n'
-        'view progress here https://chromium-review.googlesource.com/c/12345.\n'
-        '\tRepo Name: src\n'
-        '\tPath: %s\n'
-        '\tBranch: br\n'
-        'Perf Try job started for linux platform.') % (
-            options.repo_path)
-    self.assertEquals(output, sys.stdout.getvalue().strip())
-
-  @mock.patch('core.trybot_command.os.chdir', mock.MagicMock())
-  @mock.patch('core.trybot_command.os.path.exists',
-              mock.MagicMock(return_value='True'))
-  def testAttemptTryjobAllForCrRepo(self):
-    default_config = self._ExpectedGitTryTestArgs('sunspider', 'release')
-    winx64_config = self._ExpectedGitTryTestArgs(
-        'sunspider', 'release_x64', 'x64')
-    android_config = self._ExpectedGitTryTestArgs(
-        'sunspider', 'android-chromium', 'ia32')
-    command, options = self._SetupTrybotCommand(
-        {'linux_perf_bisect': 'stuff',
-         'win_perf_bisect': 'stuff',
-         'winx64_perf_bisect': 'stuff',
-         'android_perf_bisect': 'stuff',
-         'mac_perf_bisect': 'stuff'}, 'all')
-    temp_file = self._MockTempFile(
-        12345, 'https://chromium-review.googlesource.com/c/12345')
-
-    self._ExpectProcesses((
-        (['git', 'rev-parse', '--abbrev-ref', '--show-toplevel', 'HEAD'],
-         (0, '/root/path_to/repo/src\nbr\n', None)),
-        (['git', 'update-index', '--refresh', '-q'], (0, '', None,)),
-        (['git', 'diff-index', 'HEAD'], (0, '', None)),
-        (['git', 'cl', 'issue', '--json', temp_file],
-         (0,
-          'stuff https://chromium-review.googlesource.com/c/12345 stuff',
-          None)),
-        (['git', 'cl', 'try', '-m', 'tryserver.chromium.perf',
-          '-p', default_config, '-b', 'win_perf_bisect'], (0, '', None)),
-        (['git', 'cl', 'try', '-m', 'tryserver.chromium.perf',
-          '-p', android_config, '-b', 'android_perf_bisect'], (0, '', None)),
-        (['git', 'cl', 'try', '-m', 'tryserver.chromium.perf',
-          '-p', winx64_config, '-b', 'winx64_perf_bisect'], (0, '', None)),
-        (['git', 'cl', 'try', '-m', 'tryserver.chromium.perf',
-          '-p', default_config, '-b', 'mac_perf_bisect'], (0, '', None)),
-        (['git', 'cl', 'try', '-m', 'tryserver.chromium.perf',
-          '-p', default_config, '-b', 'linux_perf_bisect'], (0, '', None)),
-    ))
-
-    with mock.patch('core.trybot_command.os.path.abspath',
-                    return_value=trybot_command.CHROMIUM_SRC_PATH):
-      command._AttemptTryjob(options, [])
-
-    output = (
-        'Running try job....\n'
-        'view progress here https://chromium-review.googlesource.com/c/12345.\n'
-        '\tRepo Name: src\n'
-        '\tPath: %s\n'
-        '\tBranch: br\n'
-        'Perf Try job started for win platform.\n'
-        'Perf Try job started for android platform.\n'
-        'Perf Try job started for win-x64 platform.\n'
-        'Perf Try job started for mac platform.\n'
-        'Perf Try job started for linux platform.') % (
-            options.repo_path)
-    self.assertEquals(output, sys.stdout.getvalue().strip())
-
-  @mock.patch('core.trybot_command.os.chdir', mock.MagicMock())
-  @mock.patch('core.trybot_command.os.path.exists',
-              mock.MagicMock(return_value='True'))
-  def testAttemptTryjobForDepsRepo(self):
-    test_args = self._ExpectedGitTryTestArgs('sunspider', 'release')
-    deps_override_arg = 'deps_revision_overrides={"src/v8": "feedbeed"}'
-    command, options = self._SetupTrybotCommand(
-        {'linux_perf_bisect': 'stuff'}, 'linux',
-        repo_path='root/path_to/repo/v8')
-    temp_file = self._MockTempFile(
-        12345, 'https://chromium-review.googlesource.com/c/12345')
-
-    self._ExpectProcesses((
-        (['git', 'rev-parse', '--abbrev-ref', '--show-toplevel', 'HEAD'],
-         (0, 'root/path_to/repo/v8\nbr\n', None)),
-        (['git', 'update-index', '--refresh', '-q'], (0, '', None,)),
-        (['git', 'diff-index', 'HEAD'], (0, '', None)),
-        (['git', 'config', 'branch.br.remote'], (0, '.', None)),
-        (['git', 'rev-parse', '--abbrev-ref', 'br@{upstream}'],
-         (0, 'br1', None,)),
-        (['git', 'config', 'branch.br1.remote'], (0, 'origin', None)),
-        (['git', 'config', 'remote.origin.url'],
-         (0, 'https://chromium.googlesource.com/v8/v8.git', None)),
-        (['git', 'rev-parse', 'br1@{upstream}'], (0, 'feedbeed', None)),
-        (['git', 'cl', 'issue', '--json', temp_file],
-         (0,
-          'stuff https://chromium-review.googlesource.com/c/12345 stuff',
-          None)),
-        (['git', 'cl', 'try', '-m', 'tryserver.chromium.perf',
-          '-p', test_args, '-p', deps_override_arg,
-          '-b', 'linux_perf_bisect'], (0, '', None))
-    ))
-
-    with mock.patch('core.trybot_command.os.path.abspath',
-                    return_value='root/path_to/repo/v8'):
-      command._AttemptTryjob(options, [])
-
-    output = (
-        'Running try job....\n'
-        'view progress here https://chromium-review.googlesource.com/c/12345.\n'
-        '\tRepo Name: v8\n'
-        '\tPath: root/path_to/repo/v8\n'
-        '\tBranch: br\n'
-        'Perf Try job started for linux platform.')
-    self.assertEquals(output, sys.stdout.getvalue().strip())
-
-  @mock.patch('core.trybot_command.os.chdir', mock.MagicMock())
-  @mock.patch('core.trybot_command.os.path.exists',
-              mock.MagicMock(return_value='True'))
-  def testAttemptTryjobAllForDepsRepo(self):
-    default_config = self._ExpectedGitTryTestArgs('sunspider', 'release')
-    deps_override_arg = 'deps_revision_overrides={"src/v8": "feedbeed"}'
-    winx64_config = self._ExpectedGitTryTestArgs(
-        'sunspider', 'release_x64', 'x64')
-    android_config = self._ExpectedGitTryTestArgs(
-        'sunspider', 'android-chromium', 'ia32')
-    command, options = self._SetupTrybotCommand(
-        {'linux_perf_bisect': 'stuff',
-         'winx64_perf_bisect': 'stuff',
-         'android_perf_bisect': 'stuff'},
-        'all', repo_path='root/path_to/repo/v8')
-    temp_file = self._MockTempFile(
-        12345, 'https://chromium-review.googlesource.com/c/12345')
-
-    self._ExpectProcesses((
-        (['git', 'rev-parse', '--abbrev-ref', '--show-toplevel', 'HEAD'],
-         (0, 'root/path_to/repo/v8\nbr\n', None)),
-        (['git', 'update-index', '--refresh', '-q'], (0, '', None,)),
-        (['git', 'diff-index', 'HEAD'], (0, '', None)),
-        (['git', 'config', 'branch.br.remote'], (0, '.', None)),
-        (['git', 'rev-parse', '--abbrev-ref', 'br@{upstream}'],
-         (0, 'br1', None,)),
-        (['git', 'config', 'branch.br1.remote'], (0, 'origin', None)),
-        (['git', 'config', 'remote.origin.url'],
-         (0, 'https://chromium.googlesource.com/v8/v8.git', None)),
-        (['git', 'rev-parse', 'br1@{upstream}'],
-         (0, 'feedbeed', None)),
-        (['git', 'cl', 'issue', '--json', temp_file],
-         (0,
-          'stuff https://chromium-review.googlesource.com/c/12345 stuff',
-          None)),
-        (['git', 'cl', 'try', '-m', 'tryserver.chromium.perf',
-          '-p', android_config, '-p', deps_override_arg,
-          '-b', 'android_perf_bisect'], (0, '', None)),
-        (['git', 'cl', 'try', '-m', 'tryserver.chromium.perf',
-          '-p', winx64_config, '-p', deps_override_arg,
-          '-b', 'winx64_perf_bisect'], (0, '', None)),
-        (['git', 'cl', 'try', '-m', 'tryserver.chromium.perf',
-          '-p', default_config, '-p', deps_override_arg,
-          '-b', 'linux_perf_bisect'], (0, '', None)),
-    ))
-
-    with mock.patch('core.trybot_command.os.path.abspath',
-                    return_value='root/path_to/repo/v8'):
-      command._AttemptTryjob(options, [])
-
-    output = (
-        'Running try job....\n'
-        'view progress here https://chromium-review.googlesource.com/c/12345.\n'
-        '\tRepo Name: v8\n'
-        '\tPath: root/path_to/repo/v8\n'
-        '\tBranch: br\n'
-        'Perf Try job started for android platform.\n'
-        'Perf Try job started for win-x64 platform.\n'
-        'Perf Try job started for linux platform.')
-    self.assertEquals(output, sys.stdout.getvalue().strip())
-
-  @mock.patch('core.trybot_command.os.chdir', mock.MagicMock())
-  @mock.patch('core.trybot_command.os.path.exists',
-              mock.MagicMock(return_value='True'))
-  def testAttemptTryjobWithDepsRevisionArg(self):
-    test_args = self._ExpectedGitTryTestArgs('sunspider', 'release')
-    deps_override_arg = 'deps_revision_overrides={"src/v8": "feedbeed"}'
-    command, options = self._SetupTrybotCommand(
-        {'linux_perf_bisect': 'stuff'}, 'linux',
-        repo_path='root/path_to/repo/v8', deps_revision='feedbeed')
-    temp_file = self._MockTempFile(
-        12345, 'https://chromium-review.googlesource.com/c/12345')
-
-    self._ExpectProcesses((
-        (['git', 'rev-parse', '--abbrev-ref', '--show-toplevel', 'HEAD'],
-         (0, 'root/path_to/repo/v8\nbr\n', None)),
-        (['git', 'update-index', '--refresh', '-q'], (0, '', None,)),
-        (['git', 'diff-index', 'HEAD'], (0, '', None)),
-        (['git', 'cl', 'issue', '--json', temp_file],
-         (0,
-          'stuff https://chromium-review.googlesource.com/c/12345 stuff',
-          None)),
-        (['git', 'cl', 'try', '-m', 'tryserver.chromium.perf',
-          '-p', test_args, '-p', deps_override_arg,
-          '-b', 'linux_perf_bisect'], (0, '', None))
-    ))
-    with mock.patch('core.trybot_command.os.path.abspath',
-                    return_value='root/path_to/repo/v8'):
-      command._AttemptTryjob(options, [])
-
-    output = (
-        'Running try job....\n'
-        'view progress here https://chromium-review.googlesource.com/c/12345.\n'
-        '\tRepo Name: v8\n'
-        '\tPath: root/path_to/repo/v8\n'
-        '\tBranch: br\n'
-        'Perf Try job started for linux platform.')
-    self.assertEquals(output, sys.stdout.getvalue().strip())
-
-
-# TODO(rnephew): Add unittests for IsBenchmarkDisabledOnTrybotPlatform when it
-# uses the current method of disabling benchmarks to determine if it should run.
diff --git a/tools/perf/scripts_smoke_unittest.py b/tools/perf/scripts_smoke_unittest.py
index da2e82a..67c0321 100644
--- a/tools/perf/scripts_smoke_unittest.py
+++ b/tools/perf/scripts_smoke_unittest.py
@@ -39,12 +39,6 @@
     self.assertIn('No benchmark named "foo"', stdout)
     self.assertNotEquals(return_code, 0)
 
-  def testRunTrybotWithTypo(self):
-    return_code, stdout = self.RunPerfScript('run_benchmark try linux octaenz')
-    self.assertIn('No benchmark named "octaenz"', stdout)
-    self.assertIn('octane', stdout)
-    self.assertNotEqual(return_code, 0)
-
   def testRunRecordWprHelp(self):
     return_code, stdout = self.RunPerfScript('record_wpr')
     self.assertEquals(return_code, 0, stdout)
diff --git a/tools/traffic_annotation/summary/annotations.xml b/tools/traffic_annotation/summary/annotations.xml
index 793136b7..85f62d4 100644
--- a/tools/traffic_annotation/summary/annotations.xml
+++ b/tools/traffic_annotation/summary/annotations.xml
@@ -28,6 +28,8 @@
  <item id="bluetooth_socket" hash_code="94099818" type="0" content_hash_code="30932349" os_list="linux,windows" file_path="device/bluetooth/bluetooth_socket_net.cc"/>
  <item id="brandcode_config" hash_code="109679553" type="0" content_hash_code="128843792" os_list="linux,windows" file_path="chrome/browser/profile_resetter/brandcode_config_fetcher.cc"/>
  <item id="captive_portal_service" hash_code="88754904" type="0" content_hash_code="70737580" os_list="linux,windows" file_path="chrome/browser/captive_portal/captive_portal_service.cc"/>
+ <item id="cast_keep_alive_delegate" hash_code="134755844" type="0" content_hash_code="66118796" os_list="linux,windows" file_path="components/cast_channel/keep_alive_delegate.cc"/>
+ <item id="cast_socket" hash_code="115192205" type="0" content_hash_code="63056899" os_list="linux,windows" file_path="components/cast_channel/cast_socket.cc"/>
  <item id="cast_udp_transport" hash_code="5576536" type="0" content_hash_code="107643273" os_list="linux,windows" file_path="media/cast/net/udp_transport.cc"/>
  <item id="certificate_verifier" hash_code="113553577" type="0" content_hash_code="62346354" os_list="linux,windows" file_path="net/cert_net/cert_net_fetcher_impl.cc"/>
  <item id="chrome_apps_socket_api" hash_code="8591273" type="0" content_hash_code="70868355" os_list="linux,windows" file_path="extensions/browser/api/socket/socket.cc"/>
diff --git a/ui/android/java/src/org/chromium/ui/base/DeviceFormFactor.java b/ui/android/java/src/org/chromium/ui/base/DeviceFormFactor.java
index fb4e107..9c538a8 100644
--- a/ui/android/java/src/org/chromium/ui/base/DeviceFormFactor.java
+++ b/ui/android/java/src/org/chromium/ui/base/DeviceFormFactor.java
@@ -23,12 +23,15 @@
     public static final int MINIMUM_TABLET_WIDTH_DP = 600;
 
     /**
-     * @return Whether the app should currently treat the device as a tablet for layout. This method
-     *         is not affected by Android N multi-window, but can change for external displays.
-     *         E.g. http://developer.samsung.com/samsung-dex/testing
+     * @return Whether the app should treat the device as a tablet for layout. This method is not
+     *         affected by Android N multi-window.
      */
     @CalledByNative
     public static boolean isTablet() {
+        // On some devices, OEM modifications have been made to the resource loader that cause the
+        // DeviceFormFactor calculation of whether a device is using tablet resources to be
+        // incorrect. Check which resources were actually loaded rather than look at screen size.
+        // See crbug.com/662338.
         return ContextUtils.getApplicationContext().getResources().getBoolean(R.bool.is_tablet);
     }
 
diff --git a/ui/app_list/BUILD.gn b/ui/app_list/BUILD.gn
index a626d5dc..37b5eac84 100644
--- a/ui/app_list/BUILD.gn
+++ b/ui/app_list/BUILD.gn
@@ -64,8 +64,6 @@
     "views/indicator_chip_view.cc",
     "views/indicator_chip_view.h",
     "views/page_switcher.h",
-    "views/page_switcher_horizontal.cc",
-    "views/page_switcher_horizontal.h",
     "views/page_switcher_vertical.cc",
     "views/page_switcher_vertical.h",
     "views/pulsing_block_view.cc",
@@ -90,8 +88,6 @@
     "views/search_result_tile_item_view.h",
     "views/search_result_view.cc",
     "views/search_result_view.h",
-    "views/speech_view.cc",
-    "views/speech_view.h",
     "views/suggestions_container_view.cc",
     "views/suggestions_container_view.h",
     "views/top_icon_animation_view.cc",
@@ -135,7 +131,6 @@
   public_deps = [
     "//ash/app_list/model:app_list_model",
     "//ash/app_list/model:search_model",
-    "//ash/app_list/model:speech_ui_model",
     "//ash/public/cpp:cpp",
   ]
 }
@@ -211,7 +206,6 @@
     "views/search_result_list_view_unittest.cc",
     "views/search_result_page_view_unittest.cc",
     "views/search_result_tile_item_list_view_unittest.cc",
-    "views/speech_view_unittest.cc",
   ]
 
   configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
diff --git a/ui/app_list/app_list_switches.cc b/ui/app_list/app_list_switches.cc
index da1477b..a22d2c8 100644
--- a/ui/app_list/app_list_switches.cc
+++ b/ui/app_list/app_list_switches.cc
@@ -35,11 +35,6 @@
 // list hasn't been enabled (as in kEnableAppList) yet.
 const char kResetAppListInstallState[] = "reset-app-list-install-state";
 
-bool IsVoiceSearchEnabled() {
-  // Speech recognition in AppList is only for ChromeOS right now.
-  return true;
-}
-
 bool IsTouchableAppContextMenuEnabled() {
   return base::CommandLine::ForCurrentProcess()->HasSwitch(
       kEnableTouchableAppContextMenu);
diff --git a/ui/app_list/app_list_switches.h b/ui/app_list/app_list_switches.h
index 8f92d4f6..181aed3e 100644
--- a/ui/app_list/app_list_switches.h
+++ b/ui/app_list/app_list_switches.h
@@ -24,8 +24,6 @@
 
 bool APP_LIST_EXPORT IsFolderUIEnabled();
 
-bool APP_LIST_EXPORT IsVoiceSearchEnabled();
-
 bool APP_LIST_EXPORT IsTouchableAppContextMenuEnabled();
 
 // Determines whether the app list should not be dismissed on focus loss.
diff --git a/ui/app_list/app_list_view_delegate.h b/ui/app_list/app_list_view_delegate.h
index 4b03dff2..2aadc79 100644
--- a/ui/app_list/app_list_view_delegate.h
+++ b/ui/app_list/app_list_view_delegate.h
@@ -31,7 +31,6 @@
 class AppListViewDelegateObserver;
 class SearchModel;
 class SearchResult;
-class SpeechUIModel;
 
 class APP_LIST_EXPORT AppListViewDelegate {
  public:
@@ -46,9 +45,6 @@
   // Note: Don't call this method under //chrome/browser/.
   virtual SearchModel* GetSearchModel() = 0;
 
-  // Gets the SpeechUIModel for the app list. Owned by the AppListViewDelegate.
-  virtual SpeechUIModel* GetSpeechUI() = 0;
-
   // Invoked to start a new search. This collects a list of search results
   // matching the raw query, which is an unhandled string typed into the search
   // box by the user.
@@ -74,17 +70,10 @@
   // Invoked when the app list is closing.
   virtual void ViewClosing() = 0;
 
-  // Invoked to toggle the status of speech recognition.
-  virtual void StartSpeechRecognition() = 0;
-  virtual void StopSpeechRecognition() = 0;
-
   // Creates the web view for the start page. The caller takes the ownership of
   // the returned view.
   virtual views::View* CreateStartPageWebView(const gfx::Size& size) = 0;
 
-  // Returns true if the delegate supports speech recognition.
-  virtual bool IsSpeechRecognitionEnabled() = 0;
-
   // Gets the wallpaper prominent colors.
   virtual void GetWallpaperProminentColors(std::vector<SkColor>* colors) = 0;
 
diff --git a/ui/app_list/presenter/app_list_presenter_delegate.h b/ui/app_list/presenter/app_list_presenter_delegate.h
index dbbe74d..c87e71d 100644
--- a/ui/app_list/presenter/app_list_presenter_delegate.h
+++ b/ui/app_list/presenter/app_list_presenter_delegate.h
@@ -47,9 +47,6 @@
   // Called when app list is dismissed
   virtual void OnDismissed() = 0;
 
-  // Update app list bounds if necessary.
-  virtual void UpdateBounds() = 0;
-
   // Returns the offset vector by which the app list window should animate
   // when it gets shown or hidden.
   virtual gfx::Vector2d GetVisibilityAnimationOffset(
diff --git a/ui/app_list/presenter/app_list_presenter_impl.cc b/ui/app_list/presenter/app_list_presenter_impl.cc
index eec7859b..bb575c4 100644
--- a/ui/app_list/presenter/app_list_presenter_impl.cc
+++ b/ui/app_list/presenter/app_list_presenter_impl.cc
@@ -192,7 +192,6 @@
   view_ = view;
   views::Widget* widget = view_->GetWidget();
   widget->AddObserver(this);
-  widget->GetNativeView()->GetRootWindow()->AddObserver(this);
   aura::client::GetFocusClient(widget->GetNativeView())->AddObserver(this);
   view_->GetAppsPaginationModel()->AddObserver(this);
   view_->ShowWhenReady();
@@ -206,7 +205,6 @@
   widget->RemoveObserver(this);
   GetLayer(widget)->GetAnimator()->RemoveObserver(this);
   presenter_delegate_.reset();
-  widget->GetNativeView()->GetRootWindow()->RemoveObserver(this);
   aura::client::GetFocusClient(widget->GetNativeView())->RemoveObserver(this);
 
   view_->GetAppsPaginationModel()->RemoveObserver(this);
@@ -272,17 +270,6 @@
 }
 
 ////////////////////////////////////////////////////////////////////////////////
-// AppListPresenterImpl,  aura::WindowObserver implementation:
-void AppListPresenterImpl::OnWindowBoundsChanged(
-    aura::Window* root,
-    const gfx::Rect& old_bounds,
-    const gfx::Rect& new_bounds,
-    ui::PropertyChangeReason reason) {
-  if (presenter_delegate_)
-    presenter_delegate_->UpdateBounds();
-}
-
-////////////////////////////////////////////////////////////////////////////////
 // AppListPresenterImpl, ui::ImplicitAnimationObserver implementation:
 
 void AppListPresenterImpl::OnImplicitAnimationsCompleted() {
diff --git a/ui/app_list/presenter/app_list_presenter_impl.h b/ui/app_list/presenter/app_list_presenter_impl.h
index 07fd022..ad748cc8 100644
--- a/ui/app_list/presenter/app_list_presenter_impl.h
+++ b/ui/app_list/presenter/app_list_presenter_impl.h
@@ -42,7 +42,6 @@
 // for laying out the app list UI to ash::AppListLayoutDelegate.
 class APP_LIST_PRESENTER_EXPORT AppListPresenterImpl
     : public aura::client::FocusChangeObserver,
-      public aura::WindowObserver,
       public ui::ImplicitAnimationObserver,
       public views::WidgetObserver,
       public PaginationModelObserver {
@@ -106,12 +105,6 @@
   void OnWindowFocused(aura::Window* gained_focus,
                        aura::Window* lost_focus) override;
 
-  // aura::WindowObserver overrides:
-  void OnWindowBoundsChanged(aura::Window* root,
-                             const gfx::Rect& old_bounds,
-                             const gfx::Rect& new_bounds,
-                             ui::PropertyChangeReason reason) override;
-
   // ui::ImplicitAnimationObserver overrides:
   void OnImplicitAnimationsCompleted() override;
 
diff --git a/ui/app_list/presenter/app_list_presenter_impl_unittest.cc b/ui/app_list/presenter/app_list_presenter_impl_unittest.cc
index f6122bb..691c109 100644
--- a/ui/app_list/presenter/app_list_presenter_impl_unittest.cc
+++ b/ui/app_list/presenter/app_list_presenter_impl_unittest.cc
@@ -35,7 +35,6 @@
   bool init_called() const { return init_called_; }
   bool on_shown_called() const { return on_shown_called_; }
   bool on_dismissed_called() const { return on_dismissed_called_; }
-  bool update_bounds_called() const { return update_bounds_called_; }
 
  private:
   // AppListPresenterDelegate:
@@ -52,7 +51,6 @@
   }
   void OnShown(int64_t display_id) override { on_shown_called_ = true; }
   void OnDismissed() override { on_dismissed_called_ = true; }
-  void UpdateBounds() override { update_bounds_called_ = true; }
   gfx::Vector2d GetVisibilityAnimationOffset(aura::Window*) override {
     return gfx::Vector2d(0, 0);
   }
@@ -68,7 +66,6 @@
   bool init_called_ = false;
   bool on_shown_called_ = false;
   bool on_dismissed_called_ = false;
-  bool update_bounds_called_ = false;
   views::TestViewsDelegate views_delegate_;
 
   DISALLOW_COPY_AND_ASSIGN(AppListPresenterDelegateTest);
@@ -162,7 +159,6 @@
   EXPECT_TRUE(delegate()->init_called());
   EXPECT_TRUE(delegate()->on_shown_called());
   EXPECT_FALSE(delegate()->on_dismissed_called());
-  EXPECT_FALSE(delegate()->update_bounds_called());
   focus_client->FocusWindow(presenter()->GetWindow());
   EXPECT_TRUE(presenter()->GetTargetVisibility());
 
@@ -171,7 +167,6 @@
   focus_client->FocusWindow(window.get());
 
   EXPECT_TRUE(delegate()->on_dismissed_called());
-  EXPECT_FALSE(delegate()->update_bounds_called());
   EXPECT_FALSE(presenter()->GetTargetVisibility());
 }
 
@@ -192,7 +187,6 @@
   EXPECT_TRUE(delegate()->init_called());
   EXPECT_TRUE(delegate()->on_shown_called());
   EXPECT_FALSE(delegate()->on_dismissed_called());
-  EXPECT_FALSE(delegate()->update_bounds_called());
 
   // Create a sibling window.
   std::unique_ptr<aura::Window> window(
@@ -201,23 +195,6 @@
 
   EXPECT_TRUE(presenter()->GetTargetVisibility());
   EXPECT_FALSE(delegate()->on_dismissed_called());
-  EXPECT_FALSE(delegate()->update_bounds_called());
-}
-
-// Tests that UpdateBounds is called on the delegate when the root window
-// is resized.
-TEST_F(AppListPresenterImplTest, RootWindowResize) {
-  // TODO(newcomer): this test needs to be reevaluated for the fullscreen app
-  // list (http://crbug.com/759779).
-  if (features::IsFullscreenAppListEnabled())
-    return;
-
-  presenter()->Show(GetDisplayId());
-  EXPECT_FALSE(delegate()->update_bounds_called());
-  gfx::Rect bounds = root_window()->bounds();
-  bounds.Inset(-10, 0);
-  root_window()->SetBounds(bounds);
-  EXPECT_TRUE(delegate()->update_bounds_called());
 }
 
 // Tests that the app list is dismissed and the delegate is destroyed when the
diff --git a/ui/app_list/test/app_list_test_view_delegate.cc b/ui/app_list/test/app_list_test_view_delegate.cc
index 37c723f..2b9d50f 100644
--- a/ui/app_list/test/app_list_test_view_delegate.cc
+++ b/ui/app_list/test/app_list_test_view_delegate.cc
@@ -23,12 +23,6 @@
 
 AppListTestViewDelegate::~AppListTestViewDelegate() {}
 
-int AppListTestViewDelegate::GetStopSpeechRecognitionCountAndReset() {
-  int count = stop_speech_recognition_count_;
-  stop_speech_recognition_count_ = 0;
-  return count;
-}
-
 AppListModel* AppListTestViewDelegate::GetModel() {
   return model_.get();
 }
@@ -37,10 +31,6 @@
   return search_model_.get();
 }
 
-SpeechUIModel* AppListTestViewDelegate::GetSpeechUI() {
-  return &speech_ui_;
-}
-
 void AppListTestViewDelegate::OpenSearchResult(SearchResult* result,
                                                int event_flags) {
   const SearchModel::SearchResults* results = search_model_->results();
@@ -57,19 +47,11 @@
   ++dismiss_count_;
 }
 
-void AppListTestViewDelegate::StopSpeechRecognition() {
-  ++stop_speech_recognition_count_;
-}
-
 views::View* AppListTestViewDelegate::CreateStartPageWebView(
     const gfx::Size& size) {
   return NULL;
 }
 
-bool AppListTestViewDelegate::IsSpeechRecognitionEnabled() {
-  return false;
-}
-
 void AppListTestViewDelegate::ReplaceTestModel(int item_count) {
   model_ = std::make_unique<AppListTestModel>();
   model_->PopulateApps(item_count);
diff --git a/ui/app_list/test/app_list_test_view_delegate.h b/ui/app_list/test/app_list_test_view_delegate.h
index 89b47b65..d62a1cb9 100644
--- a/ui/app_list/test/app_list_test_view_delegate.h
+++ b/ui/app_list/test/app_list_test_view_delegate.h
@@ -13,7 +13,6 @@
 #include <vector>
 
 #include "ash/app_list/model/search/search_model.h"
-#include "ash/app_list/model/speech/speech_ui_model.h"
 #include "base/callback_forward.h"
 #include "base/compiler_specific.h"
 #include "base/macros.h"
@@ -41,17 +40,12 @@
   // SetProfileByPath() is called.
   void set_next_profile_app_count(int apps) { next_profile_app_count_ = apps; }
 
-  // Returns the value of |stop_speech_recognition_count_| and then resets this
-  // value to 0.
-  int GetStopSpeechRecognitionCountAndReset();
-
   // Sets whether the search engine is Google or not.
   void SetSearchEngineIsGoogle(bool is_google);
 
   // AppListViewDelegate overrides:
   AppListModel* GetModel() override;
   SearchModel* GetSearchModel() override;
-  SpeechUIModel* GetSpeechUI() override;
   void StartSearch(const base::string16& raw_query) override {}
   void OpenSearchResult(SearchResult* result,
                         int event_flags) override;
@@ -61,10 +55,7 @@
   void ViewInitialized() override {}
   void Dismiss() override;
   void ViewClosing() override {}
-  void StartSpeechRecognition() override {}
-  void StopSpeechRecognition() override;
   views::View* CreateStartPageWebView(const gfx::Size& size) override;
-  bool IsSpeechRecognitionEnabled() override;
   void GetWallpaperProminentColors(std::vector<SkColor>* colors) override {}
   void ActivateItem(const std::string& id, int event_flags) override;
   ui::MenuModel* GetContextMenuModel(const std::string& id) override;
@@ -80,13 +71,11 @@
 
  private:
   int dismiss_count_ = 0;
-  int stop_speech_recognition_count_ = 0;
   int open_search_result_count_ = 0;
   int next_profile_app_count_ = 0;
   std::map<size_t, int> open_search_result_counts_;
   std::unique_ptr<AppListTestModel> model_;
   std::unique_ptr<SearchModel> search_model_;
-  SpeechUIModel speech_ui_;
   std::vector<SkColor> wallpaper_prominent_colors_;
 
   DISALLOW_COPY_AND_ASSIGN(AppListTestViewDelegate);
diff --git a/ui/app_list/views/app_list_main_view.cc b/ui/app_list/views/app_list_main_view.cc
index 26a531b..73f1cef 100644
--- a/ui/app_list/views/app_list_main_view.cc
+++ b/ui/app_list/views/app_list_main_view.cc
@@ -146,9 +146,7 @@
   } else {
     base::RecordAction(base::UserMetricsAction("AppList_ClickOnApp"));
     delegate_->ActivateItem(item->id(), event_flags);
-    UMA_HISTOGRAM_BOOLEAN(features::IsFullscreenAppListEnabled()
-                              ? kAppListAppLaunchedFullscreen
-                              : kAppListAppLaunched,
+    UMA_HISTOGRAM_BOOLEAN(kAppListAppLaunchedFullscreen,
                           false /*not a suggested app*/);
   }
 }
diff --git a/ui/app_list/views/app_list_view.cc b/ui/app_list/views/app_list_view.cc
index 166f2ad1..2086744 100644
--- a/ui/app_list/views/app_list_view.cc
+++ b/ui/app_list/views/app_list_view.cc
@@ -8,7 +8,6 @@
 #include <vector>
 
 #include "ash/app_list/model/app_list_model.h"
-#include "ash/app_list/model/speech/speech_ui_model.h"
 #include "base/macros.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/metrics/user_metrics.h"
@@ -30,7 +29,6 @@
 #include "ui/app_list/views/apps_container_view.h"
 #include "ui/app_list/views/contents_view.h"
 #include "ui/app_list/views/search_box_view.h"
-#include "ui/app_list/views/speech_view.h"
 #include "ui/aura/window.h"
 #include "ui/aura/window_targeter.h"
 #include "ui/aura/window_tree_host.h"
@@ -50,12 +48,12 @@
 #include "ui/gfx/path.h"
 #include "ui/gfx/skia_util.h"
 #include "ui/strings/grit/ui_strings.h"
-#include "ui/views/bubble/bubble_frame_view.h"
 #include "ui/views/controls/image_view.h"
 #include "ui/views/controls/textfield/textfield.h"
 #include "ui/views/layout/fill_layout.h"
 #include "ui/views/views_delegate.h"
 #include "ui/views/widget/widget.h"
+#include "ui/views/widget/widget_observer.h"
 #include "ui/wm/core/coordinate_conversion.h"
 #include "ui/wm/core/shadow_types.h"
 
@@ -65,9 +63,6 @@
 
 namespace {
 
-// The margin from the edge to the speech UI.
-constexpr int kSpeechUIMargin = 12;
-
 // The height of the half app list from the bottom of the screen.
 constexpr int kHalfAppListHeight = 561;
 
@@ -93,9 +88,6 @@
 constexpr int kAppInfoDialogWidth = 512;
 constexpr int kAppInfoDialogHeight = 384;
 
-// The vertical position for the appearing animation of the speech UI.
-constexpr float kSpeechUIAppearingPosition = 12;
-
 // The animation duration for app list movement.
 constexpr float kAppListAnimationDurationTestMs = 0;
 constexpr float kAppListAnimationDurationMs = 200;
@@ -206,7 +198,7 @@
 // An animation observer to hide the view at the end of the animation.
 class HideViewAnimationObserver : public ui::ImplicitAnimationObserver {
  public:
-  HideViewAnimationObserver() : frame_(NULL), target_(NULL) {}
+  HideViewAnimationObserver() : target_(NULL) {}
 
   ~HideViewAnimationObserver() override {
     if (target_)
@@ -219,22 +211,15 @@
     target_ = target;
   }
 
-  void set_frame(views::BubbleFrameView* frame) { frame_ = frame; }
-
  private:
   // Overridden from ui::ImplicitAnimationObserver:
   void OnImplicitAnimationsCompleted() override {
     if (target_) {
       target_->SetVisible(false);
       target_ = NULL;
-
-      // Should update the background by invoking SchedulePaint().
-      if (frame_)
-        frame_->SchedulePaint();
     }
   }
 
-  views::BubbleFrameView* frame_;
   views::View* target_;
 
   DISALLOW_COPY_AND_ASSIGN(HideViewAnimationObserver);
@@ -248,7 +233,6 @@
       model_(delegate->GetModel()),
       search_model_(delegate->GetSearchModel()),
       short_animations_for_testing_(false),
-      is_fullscreen_app_list_enabled_(features::IsFullscreenAppListEnabled()),
       is_background_blur_enabled_(features::IsBackgroundBlurEnabled()),
       display_observer_(this),
       animation_observer_(new HideViewAnimationObserver()),
@@ -257,21 +241,16 @@
       state_animation_metrics_reporter_(
           std::make_unique<StateAnimationMetricsReporter>()) {
   CHECK(delegate);
-  delegate_->GetSpeechUI()->AddObserver(this);
 
-  if (is_fullscreen_app_list_enabled_) {
-    display_observer_.Add(display::Screen::GetScreen());
-    delegate_->AddObserver(this);
-  }
+  display_observer_.Add(display::Screen::GetScreen());
+  delegate_->AddObserver(this);
   // Enable arrow key in FocusManager. Arrow left/right and up/down triggers
   // the same focus movement as tab/shift+tab.
   views::FocusManager::set_arrow_key_traversal_enabled(true);
 }
 
 AppListView::~AppListView() {
-  delegate_->GetSpeechUI()->RemoveObserver(this);
-  if (is_fullscreen_app_list_enabled_)
-    delegate_->RemoveObserver(this);
+  delegate_->RemoveObserver(this);
 
   animation_observer_.reset();
   // Remove child views first to ensure no remaining dependencies on delegate_.
@@ -292,19 +271,14 @@
   is_side_shelf_ = params.is_side_shelf;
   InitContents(params.initial_apps_page);
   AddAccelerator(ui::Accelerator(ui::VKEY_ESCAPE, ui::EF_NONE));
-  set_color(kContentsBackgroundColor);
-  set_parent_window(params.parent);
+  parent_window_ = params.parent;
 
-  if (is_fullscreen_app_list_enabled_)
-    InitializeFullscreen(params.parent, params.parent_container_id);
-  else
-    InitializeBubble();
+  InitializeFullscreen(params.parent, params.parent_container_id);
 
   InitChildWidgets();
   AddChildView(overlay_view_);
 
-  if (is_fullscreen_app_list_enabled_)
-    SetState(app_list_state_);
+  SetState(app_list_state_);
 
   delegate_->ViewInitialized();
 
@@ -313,18 +287,6 @@
   RecordFolderMetrics();
 }
 
-void AppListView::SetBubbleArrow(views::BubbleBorder::Arrow arrow) {
-  GetBubbleFrameView()->bubble_border()->set_arrow(arrow);
-  SizeToContents();  // Recalcuates with new border.
-  GetBubbleFrameView()->SchedulePaint();
-}
-
-void AppListView::MaybeSetAnchorPoint(const gfx::Point& anchor_point) {
-  // if the AppListView is a bubble
-  if (!is_fullscreen_app_list_enabled_)
-    SetAnchorRect(gfx::Rect(anchor_point, gfx::Size()));
-}
-
 void AppListView::SetDragAndDropHostOfCurrentAppList(
     ApplicationDragAndDropHost* drag_and_drop_host) {
   app_list_main_view_->SetDragAndDropHostOfCurrentAppList(drag_and_drop_host);
@@ -341,12 +303,6 @@
   GetWidget()->Deactivate();
 }
 
-void AppListView::UpdateBounds() {
-  // if the AppListView is a bubble
-  if (!is_fullscreen_app_list_enabled_)
-    SizeToContents();
-}
-
 void AppListView::SetAppListOverlayVisible(bool visible) {
   DCHECK(overlay_view_);
 
@@ -361,7 +317,6 @@
   if (!visible) {
     // Since only one animation is visible at a time, it's safe to re-use
     // animation_observer_ here.
-    animation_observer_->set_frame(NULL);
     animation_observer_->SetTarget(overlay_view_);
     settings.AddObserver(animation_observer_.get());
   }
@@ -391,7 +346,7 @@
 }
 
 void AppListView::OnPaint(gfx::Canvas* canvas) {
-  views::BubbleDialogDelegateView::OnPaint(canvas);
+  views::WidgetDelegateView::OnPaint(canvas);
   if (!next_paint_callback_.is_null()) {
     next_paint_callback_.Run();
     next_paint_callback_.Reset();
@@ -429,21 +384,17 @@
 };
 
 void AppListView::InitContents(int initial_apps_page) {
-  if (is_fullscreen_app_list_enabled_) {
-    // The shield view that colors/blurs the background of the app list and
-    // makes it transparent.
-    app_list_background_shield_ = new views::View;
-    app_list_background_shield_->SetPaintToLayer(ui::LAYER_SOLID_COLOR);
-    app_list_background_shield_->layer()->SetOpacity(
-        is_background_blur_enabled_ ? kAppListOpacityWithBlur
-                                    : kAppListOpacity);
-    SetBackgroundShieldColor();
-    if (is_background_blur_enabled_) {
-      app_list_background_shield_->layer()->SetBackgroundBlur(
-          kAppListBlurRadius);
-    }
-    AddChildView(app_list_background_shield_);
+  // The shield view that colors/blurs the background of the app list and
+  // makes it transparent.
+  app_list_background_shield_ = new views::View;
+  app_list_background_shield_->SetPaintToLayer(ui::LAYER_SOLID_COLOR);
+  app_list_background_shield_->layer()->SetOpacity(
+      is_background_blur_enabled_ ? kAppListOpacityWithBlur : kAppListOpacity);
+  SetBackgroundShieldColor();
+  if (is_background_blur_enabled_) {
+    app_list_background_shield_->layer()->SetBackgroundBlur(kAppListBlurRadius);
   }
+  AddChildView(app_list_background_shield_);
   app_list_main_view_ = new AppListMainView(delegate_, this);
   AddChildView(app_list_main_view_);
   app_list_main_view_->SetPaintToLayer();
@@ -456,19 +407,7 @@
   search_box_view_->layer()->SetFillsBoundsOpaquely(false);
   search_box_view_->layer()->SetMasksToBounds(true);
 
-  app_list_main_view_->Init(
-      is_fullscreen_app_list_enabled_ ? 0 : initial_apps_page,
-      search_box_view_);
-
-  // Speech recognition is available only when the start page exists.
-  if (delegate_ && delegate_->IsSpeechRecognitionEnabled()) {
-    speech_view_ = new SpeechView(delegate_);
-    speech_view_->SetVisible(false);
-    speech_view_->SetPaintToLayer();
-    speech_view_->layer()->SetFillsBoundsOpaquely(false);
-    speech_view_->layer()->SetOpacity(0.0f);
-    AddChildView(speech_view_);
-  }
+  app_list_main_view_->Init(0, search_box_view_);
 }
 
 void AppListView::InitChildWidgets() {
@@ -569,28 +508,7 @@
       new FullscreenWidgetObserver(this));
 }
 
-void AppListView::InitializeBubble() {
-  set_margins(gfx::Insets());
-  set_close_on_deactivate(false);
-  set_shadow(views::BubbleBorder::NO_ASSETS);
-
-  // This creates the app list widget (Before this, child widgets cannot be
-  // created).
-  views::BubbleDialogDelegateView::CreateBubble(this);
-
-  SetBubbleArrow(views::BubbleBorder::FLOAT);
-  // We can now create the internal widgets.
-
-  const int kOverlayCornerRadius =
-      GetBubbleFrameView()->bubble_border()->GetBorderCornerRadius();
-  overlay_view_ = new AppListOverlayView(kOverlayCornerRadius);
-  overlay_view_->SetBoundsRect(GetContentsBounds());
-}
-
 void AppListView::HandleClickOrTap(ui::LocatedEvent* event) {
-  if (!is_fullscreen_app_list_enabled_)
-    return;
-
   // No-op if app list is on fullscreen all apps state and the event location is
   // within apps grid view's bounds.
   if (app_list_state_ == AppListViewState::FULLSCREEN_ALL_APPS &&
@@ -811,9 +729,6 @@
 }
 
 void AppListView::RecordStateTransitionForUma(AppListViewState new_state) {
-  if (!is_fullscreen_app_list_enabled_)
-    return;
-
   AppListStateTransitionSource transition =
       GetAppListStateTransitionSource(new_state);
   // kMaxAppListStateTransition denotes a transition we are not interested in
@@ -858,7 +773,7 @@
 }
 
 display::Display AppListView::GetDisplayNearestView() const {
-  return display::Screen::GetScreen()->GetDisplayNearestView(parent_window());
+  return display::Screen::GetScreen()->GetDisplayNearestView(parent_window_);
 }
 
 AppsGridView* AppListView::GetAppsGridView() const {
@@ -948,43 +863,11 @@
   }
 }
 
-void AppListView::OnBeforeBubbleWidgetInit(views::Widget::InitParams* params,
-                                           views::Widget* widget) const {
-  if (!params->native_widget) {
-    views::ViewsDelegate* views_delegate = views::ViewsDelegate::GetInstance();
-    if (views_delegate && !views_delegate->native_widget_factory().is_null()) {
-      params->native_widget =
-          views_delegate->native_widget_factory().Run(*params, widget);
-    }
-  }
-  // Apply a WM-provided shadow (see ui/wm/core/).
-  params->shadow_type = views::Widget::InitParams::SHADOW_TYPE_DROP;
-  params->shadow_elevation = wm::ShadowElevation::LARGE;
-}
-
-int AppListView::GetDialogButtons() const {
-  return ui::DIALOG_BUTTON_NONE;
-}
-
 views::View* AppListView::GetInitiallyFocusedView() {
   return app_list_main_view_->search_box_view()->search_box();
 }
 
-bool AppListView::WidgetHasHitTestMask() const {
-  return GetBubbleFrameView() != nullptr;
-}
-
-void AppListView::GetWidgetHitTestMask(gfx::Path* mask) const {
-  DCHECK(mask);
-  DCHECK(GetBubbleFrameView());
-
-  mask->addRect(gfx::RectToSkRect(GetBubbleFrameView()->GetContentsBounds()));
-}
-
 void AppListView::OnScrollEvent(ui::ScrollEvent* event) {
-  if (!is_fullscreen_app_list_enabled_)
-    return;
-
   if (!HandleScroll(event->y_offset(), event->type()))
     return;
 
@@ -993,9 +876,6 @@
 }
 
 void AppListView::OnMouseEvent(ui::MouseEvent* event) {
-  if (!is_fullscreen_app_list_enabled_)
-    return;
-
   switch (event->type()) {
     case ui::ET_MOUSE_PRESSED:
       event->SetHandled();
@@ -1012,9 +892,6 @@
 }
 
 void AppListView::OnGestureEvent(ui::GestureEvent* event) {
-  if (!is_fullscreen_app_list_enabled_)
-    return;
-
   switch (event->type()) {
     case ui::ET_GESTURE_TAP:
       SetIsInDrag(false);
@@ -1062,27 +939,6 @@
   }
 }
 
-void AppListView::OnWidgetDestroying(views::Widget* widget) {
-  DCHECK(!is_fullscreen_app_list_enabled_);
-
-  BubbleDialogDelegateView::OnWidgetDestroying(widget);
-  if (delegate_ && widget == GetWidget())
-    delegate_->ViewClosing();
-}
-
-void AppListView::OnWidgetVisibilityChanged(views::Widget* widget,
-                                            bool visible) {
-  DCHECK(!is_fullscreen_app_list_enabled_);
-
-  BubbleDialogDelegateView::OnWidgetVisibilityChanged(widget, visible);
-
-  if (widget != GetWidget())
-    return;
-
-  if (!visible)
-    app_list_main_view_->ResetForShow();
-}
-
 ui::AXRole AppListView::GetAccessibleWindowRole() const {
   // Default role of root view is AX_ROLE_WINDOW which traps ChromeVox focus
   // within the root view. Assign AX_ROLE_GROUP here to allow the focus to move
@@ -1106,40 +962,19 @@
 void AppListView::Layout() {
   const gfx::Rect contents_bounds = GetContentsBounds();
 
-  // Make sure to layout |app_list_main_view_| and |speech_view_| at the
-  // center of the widget.
+  // Make sure to layout |app_list_main_view_| at the center of the widget.
   gfx::Rect centered_bounds = contents_bounds;
   ContentsView* contents_view = app_list_main_view_->contents_view();
   centered_bounds.ClampToCenteredSize(
-      gfx::Size(is_fullscreen_app_list_enabled_
-                    ? contents_view->GetMaximumContentsSize().width()
-                    : contents_view->GetDefaultContentsBounds().width(),
+      gfx::Size(contents_view->GetMaximumContentsSize().width(),
                 contents_bounds.height()));
 
   app_list_main_view_->SetBoundsRect(centered_bounds);
 
-  if (speech_view_) {
-    gfx::Rect speech_bounds = centered_bounds;
-    int preferred_height = speech_view_->GetPreferredSize().height();
-    speech_bounds.Inset(kSpeechUIMargin, kSpeechUIMargin);
-    speech_bounds.set_height(
-        std::min(speech_bounds.height(), preferred_height));
-    speech_bounds.Inset(-speech_view_->GetInsets());
-    speech_view_->SetBoundsRect(speech_bounds);
-  }
-
-  if (!is_fullscreen_app_list_enabled_)
-    return;
   contents_view->Layout();
   app_list_background_shield_->SetBoundsRect(contents_bounds);
 }
 
-void AppListView::SchedulePaintInRect(const gfx::Rect& rect) {
-  BubbleDialogDelegateView::SchedulePaintInRect(rect);
-  if (GetBubbleFrameView())
-    GetBubbleFrameView()->SchedulePaint();
-}
-
 void AppListView::GetAccessibleNodeData(ui::AXNodeData* node_data) {
   node_data->SetName(state_announcement_);
   node_data->role = ui::AX_ROLE_DESKTOP;
@@ -1307,8 +1142,7 @@
 }
 
 void AppListView::StartCloseAnimation(base::TimeDelta animation_duration) {
-  DCHECK(is_fullscreen_app_list_enabled_);
-  if (is_side_shelf_ || !is_fullscreen_app_list_enabled_)
+  if (is_side_shelf_)
     return;
 
   if (app_list_state_ != AppListViewState::CLOSED)
@@ -1369,8 +1203,6 @@
 }
 
 gfx::Rect AppListView::GetAppInfoDialogBounds() const {
-  if (!is_fullscreen_app_list_enabled_)
-    return GetBoundsInScreen();
   gfx::Rect app_info_bounds(GetDisplayNearestView().bounds());
   app_info_bounds.ClampToCenteredSize(
       gfx::Size(kAppInfoDialogWidth, kAppInfoDialogHeight));
@@ -1449,80 +1281,8 @@
   }
 }
 
-void AppListView::OnSpeechRecognitionStateChanged(
-    SpeechRecognitionState new_state) {
-  if (!speech_view_)
-    return;
-
-  bool will_appear = (new_state == SPEECH_RECOGNITION_RECOGNIZING ||
-                      new_state == SPEECH_RECOGNITION_IN_SPEECH ||
-                      new_state == SPEECH_RECOGNITION_NETWORK_ERROR);
-  // No change for this class.
-  if (speech_view_->visible() == will_appear)
-    return;
-
-  if (will_appear)
-    speech_view_->Reset();
-
-  animation_observer_->set_frame(GetBubbleFrameView());
-  gfx::Transform speech_transform;
-  speech_transform.Translate(0, SkFloatToMScalar(kSpeechUIAppearingPosition));
-  if (will_appear)
-    speech_view_->layer()->SetTransform(speech_transform);
-
-  {
-    ui::ScopedLayerAnimationSettings main_settings(
-        app_list_main_view_->layer()->GetAnimator());
-    if (will_appear) {
-      animation_observer_->SetTarget(app_list_main_view_);
-      main_settings.AddObserver(animation_observer_.get());
-    }
-    app_list_main_view_->layer()->SetOpacity(will_appear ? 0.0f : 1.0f);
-  }
-
-  {
-    ui::ScopedLayerAnimationSettings search_box_settings(
-        search_box_widget_->GetLayer()->GetAnimator());
-    search_box_widget_->GetLayer()->SetOpacity(will_appear ? 0.0f : 1.0f);
-  }
-
-  {
-    ui::ScopedLayerAnimationSettings speech_settings(
-        speech_view_->layer()->GetAnimator());
-    if (!will_appear) {
-      animation_observer_->SetTarget(speech_view_);
-      speech_settings.AddObserver(animation_observer_.get());
-    }
-
-    speech_view_->layer()->SetOpacity(will_appear ? 1.0f : 0.0f);
-    if (will_appear)
-      speech_view_->layer()->SetTransform(gfx::Transform());
-    else
-      speech_view_->layer()->SetTransform(speech_transform);
-  }
-
-  // Prevent the search box from receiving events when hidden.
-  search_box_view_->SetEnabled(!will_appear);
-
-  if (will_appear) {
-    speech_view_->SetVisible(true);
-  } else {
-    app_list_main_view_->SetVisible(true);
-
-    // Refocus the search box. However, if the app list widget does not
-    // have focus, it means another window has already taken focus, and we
-    // *must not* focus the search box (or we would steal focus back into
-    // the app list).
-    if (GetWidget()->IsActive())
-      search_box_view_->search_box()->RequestFocus();
-  }
-}
-
 void AppListView::OnDisplayMetricsChanged(const display::Display& display,
                                           uint32_t changed_metrics) {
-  if (!is_fullscreen_app_list_enabled_)
-    return;
-
   // Set the |fullscreen_widget_| size to fit the new display metrics.
   gfx::Size size = GetDisplayNearestView().size();
   fullscreen_widget_->SetSize(size);
@@ -1557,7 +1317,7 @@
   // There is a chance when AppListView::OnWallpaperColorsChanged is called
   // from AppListViewDelegate, the |app_list_background_shield_| is not
   // initialized.
-  if (!is_fullscreen_app_list_enabled_ || !app_list_background_shield_)
+  if (!app_list_background_shield_)
     return;
 
   std::vector<SkColor> prominent_colors;
diff --git a/ui/app_list/views/app_list_view.h b/ui/app_list/views/app_list_view.h
index b6461d8..684e8a0 100644
--- a/ui/app_list/views/app_list_view.h
+++ b/ui/app_list/views/app_list_view.h
@@ -9,7 +9,6 @@
 #include <vector>
 
 #include "ash/app_list/model/app_list_view_state.h"
-#include "ash/app_list/model/speech/speech_ui_model_observer.h"
 #include "base/callback.h"
 #include "base/macros.h"
 #include "base/scoped_observer.h"
@@ -18,8 +17,8 @@
 #include "ui/app_list/app_list_export.h"
 #include "ui/app_list/app_list_view_delegate_observer.h"
 #include "ui/display/display_observer.h"
-#include "ui/views/bubble/bubble_dialog_delegate.h"
 #include "ui/views/widget/widget.h"
+#include "ui/views/widget/widget_delegate.h"
 
 namespace aura {
 class Window;
@@ -47,7 +46,6 @@
 class PaginationModel;
 class SearchBoxView;
 class SearchModel;
-class SpeechView;
 
 namespace test {
 class AppListViewTestApi;
@@ -55,8 +53,7 @@
 
 // AppListView is the top-level view and controller of app list UI. It creates
 // and hosts a AppsGridView and passes AppListModel to it for display.
-class APP_LIST_EXPORT AppListView : public views::BubbleDialogDelegateView,
-                                    public SpeechUIModelObserver,
+class APP_LIST_EXPORT AppListView : public views::WidgetDelegateView,
                                     public display::DisplayObserver,
                                     public AppListViewDelegateObserver {
  public:
@@ -107,10 +104,6 @@
   // fullscreen app list feature is set.
   void Initialize(const InitParams& params);
 
-  void SetBubbleArrow(views::BubbleBorder::Arrow arrow);
-
-  void MaybeSetAnchorPoint(const gfx::Point& anchor_point);
-
   // If |drag_and_drop_host| is not NULL it will be called upon drag and drop
   // operations outside the application list. This has to be called after
   // Initialize was called since the app list object needs to exist so that
@@ -125,8 +118,6 @@
   // Dismisses the UI, cleans up and sets the state to CLOSED.
   void Dismiss();
 
-  void UpdateBounds();
-
   // Enables/disables a semi-transparent overlay over the app list (good for
   // hiding the app list when a modal dialog is being shown).
   void SetAppListOverlayVisible(bool visible);
@@ -143,7 +134,6 @@
   // Overridden from views::View:
   bool AcceleratorPressed(const ui::Accelerator& accelerator) override;
   void Layout() override;
-  void SchedulePaintInRect(const gfx::Rect& rect) override;
   void GetAccessibleNodeData(ui::AXNodeData* node_data) override;
   void OnKeyEvent(ui::KeyEvent* event) override;
 
@@ -201,6 +191,8 @@
     return fullscreen_widget_;
   }
 
+  gfx::NativeView parent_window() const { return parent_window_; }
+
   AppListViewState app_list_state() const { return app_list_state_; }
 
   views::Widget* search_box_widget() const { return search_box_widget_; }
@@ -239,9 +231,6 @@
   // Initializes the widget for fullscreen mode.
   void InitializeFullscreen(gfx::NativeView parent, int parent_container_id);
 
-  // Initializes the widget as a bubble.
-  void InitializeBubble();
-
   // Closes the AppListView when a click or tap event propogates to the
   // AppListView.
   void HandleClickOrTap(ui::LocatedEvent* event);
@@ -292,23 +281,8 @@
   AppListStateTransitionSource GetAppListStateTransitionSource(
       AppListViewState target_state) const;
 
-  // Overridden from views::BubbleDialogDelegateView:
-  void OnBeforeBubbleWidgetInit(views::Widget::InitParams* params,
-                                views::Widget* widget) const override;
-  int GetDialogButtons() const override;
-
   // Overridden from views::WidgetDelegateView:
   views::View* GetInitiallyFocusedView() override;
-  bool WidgetHasHitTestMask() const override;
-  void GetWidgetHitTestMask(gfx::Path* mask) const override;
-
-  // Overridden from views::WidgetObserver:
-  void OnWidgetDestroying(views::Widget* widget) override;
-  void OnWidgetVisibilityChanged(views::Widget* widget, bool visible) override;
-
-  // Overridden from SpeechUIModelObserver:
-  void OnSpeechRecognitionStateChanged(
-      SpeechRecognitionState new_state) override;
 
   // Overridden from DisplayObserver:
   void OnDisplayMetricsChanged(const display::Display& display,
@@ -332,8 +306,8 @@
   SearchModel* const search_model_;  // Not Owned.
 
   AppListMainView* app_list_main_view_ = nullptr;
-  SpeechView* speech_view_ = nullptr;
   views::Widget* fullscreen_widget_ = nullptr;  // Owned by AppListView.
+  gfx::NativeView parent_window_ = nullptr;
 
   views::View* search_box_focus_host_ =
       nullptr;  // Owned by the views hierarchy.
@@ -369,8 +343,6 @@
 
   // The velocity of the gesture event.
   float last_fling_velocity_ = 0;
-  // Whether the fullscreen app list feature is enabled.
-  const bool is_fullscreen_app_list_enabled_;
   // Whether the background blur is enabled.
   const bool is_background_blur_enabled_;
   // The state of the app list, controlled via SetState().
diff --git a/ui/app_list/views/app_list_view_unittest.cc b/ui/app_list/views/app_list_view_unittest.cc
index 1cead10..c817c77 100644
--- a/ui/app_list/views/app_list_view_unittest.cc
+++ b/ui/app_list/views/app_list_view_unittest.cc
@@ -1327,8 +1327,6 @@
   params.parent = GetContext();
   params.initial_apps_page = 1;
   view_->Initialize(params);
-  const gfx::Size size = view_->bounds().size();
-  view_->MaybeSetAnchorPoint(gfx::Point(size.width() / 2, size.height() / 2));
   Show();
 
   ASSERT_EQ(0, view_->GetAppsPaginationModel()->selected_page());
@@ -1821,8 +1819,6 @@
   params.parent = GetContext();
   params.initial_apps_page = 1;
   view_->Initialize(params);
-  const gfx::Size size = view_->bounds().size();
-  view_->MaybeSetAnchorPoint(gfx::Point(size.width() / 2, size.height() / 2));
   Show();
 
   ASSERT_EQ(1, view_->GetAppsPaginationModel()->selected_page());
diff --git a/ui/app_list/views/apps_container_view.cc b/ui/app_list/views/apps_container_view.cc
index c5d25f3..5db8047 100644
--- a/ui/app_list/views/apps_container_view.cc
+++ b/ui/app_list/views/apps_container_view.cc
@@ -36,15 +36,10 @@
 constexpr int kSearchBoxMinimumTopPadding = 24;
 
 AppsContainerView::AppsContainerView(AppListMainView* app_list_main_view,
-                                     AppListModel* model)
-    : is_fullscreen_app_list_enabled_(features::IsFullscreenAppListEnabled()) {
+                                     AppListModel* model) {
   apps_grid_view_ =
       new AppsGridView(app_list_main_view->contents_view(), nullptr);
-  if (is_fullscreen_app_list_enabled_) {
-    apps_grid_view_->SetLayout(kPreferredCols, kPreferredRows);
-  } else {
-    apps_grid_view_->SetLayout(kPreferredCols, kPreferredRows);
-  }
+  apps_grid_view_->SetLayout(kPreferredCols, kPreferredRows);
   AddChildView(apps_grid_view_);
 
   folder_background_view_ = new FolderBackgroundView();
@@ -174,9 +169,6 @@
 
 gfx::Rect AppsContainerView::GetSearchBoxBoundsForState(
     AppListModel::State state) const {
-  if (!is_fullscreen_app_list_enabled_)
-    return AppListPage::GetSearchBoxBounds();
-
   gfx::Rect search_box_bounds(contents_view()->GetDefaultSearchBoxBounds());
   bool is_in_drag = false;
   if (contents_view()->app_list_view())
@@ -197,12 +189,6 @@
     AppListModel::State state) const {
   gfx::Rect onscreen_bounds = GetDefaultContentsBounds();
 
-  if (!is_fullscreen_app_list_enabled_) {
-    if (state == AppListModel::STATE_APPS)
-      return onscreen_bounds;
-    return GetBelowContentsOffscreenBounds(onscreen_bounds.size());
-  }
-
   // Both STATE_START and STATE_APPS are AppsContainerView page.
   if (state == AppListModel::STATE_APPS || state == AppListModel::STATE_START) {
     int y = GetSearchBoxBoundsForState(state).bottom();
diff --git a/ui/app_list/views/apps_container_view.h b/ui/app_list/views/apps_container_view.h
index bb27fc5..3a18695c 100644
--- a/ui/app_list/views/apps_container_view.h
+++ b/ui/app_list/views/apps_container_view.h
@@ -133,8 +133,6 @@
 
   size_t top_icon_animation_pending_count_ = 0u;
 
-  const bool is_fullscreen_app_list_enabled_;
-
   DISALLOW_COPY_AND_ASSIGN(AppsContainerView);
 };
 
diff --git a/ui/app_list/views/apps_grid_view.cc b/ui/app_list/views/apps_grid_view.cc
index 959d7cdd..6f8fcbf 100644
--- a/ui/app_list/views/apps_grid_view.cc
+++ b/ui/app_list/views/apps_grid_view.cc
@@ -31,7 +31,6 @@
 #include "ui/app_list/views/contents_view.h"
 #include "ui/app_list/views/expand_arrow_view.h"
 #include "ui/app_list/views/indicator_chip_view.h"
-#include "ui/app_list/views/page_switcher_horizontal.h"
 #include "ui/app_list/views/page_switcher_vertical.h"
 #include "ui/app_list/views/pulsing_block_view.h"
 #include "ui/app_list/views/search_box_view.h"
@@ -81,23 +80,13 @@
 // Padding space in pixels between pages.
 constexpr int kPagePadding = 40;
 
-// Preferred tile size when showing in fixed layout.
-constexpr int kPreferredTileWidth = 100;
-constexpr int kPreferredTileHeight = 100;
-
 // Padding on each side of a tile.
-constexpr int kTileLeftRightPadding = 10;
-constexpr int kTileBottomPadding = 6;
-constexpr int kTileTopPadding = 6;
 constexpr int kTileHorizontalPadding = 12;
 constexpr int kTileVerticalPadding = 6;
 
 // Width in pixels of the area on the sides that triggers a page flip.
 constexpr int kPageFlipZoneSize = 40;
 
-// Delay in milliseconds to do the page flip.
-constexpr int kPageFlipDelayInMs = 1000;
-
 // Delay in milliseconds to do the page flip in fullscreen app list.
 constexpr int kPageFlipDelayInMsFullscreen = 500;
 
@@ -158,9 +147,7 @@
 
 // Returns the size of a tile view excluding its padding.
 gfx::Size GetTileViewSize() {
-  if (features::IsFullscreenAppListEnabled())
-    return gfx::Size(kGridTileWidth, kGridTileHeight);
-  return gfx::Size(kPreferredTileWidth, kPreferredTileHeight);
+  return gfx::Size(kGridTileWidth, kGridTileHeight);
 }
 
 // RowMoveAnimationDelegate is used when moving an item into a different row.
@@ -354,10 +341,7 @@
     : folder_delegate_(folder_delegate),
       contents_view_(contents_view),
       bounds_animator_(this),
-      is_fullscreen_app_list_enabled_(features::IsFullscreenAppListEnabled()),
-      page_flip_delay_in_ms_(is_fullscreen_app_list_enabled_
-                                 ? kPageFlipDelayInMsFullscreen
-                                 : kPageFlipDelayInMs),
+      page_flip_delay_in_ms_(kPageFlipDelayInMsFullscreen),
       pagination_animation_metrics_reporter_(
           std::make_unique<PaginationAnimationMetricsReporter>()),
       pagination_animation_start_frame_number_(0) {
@@ -368,7 +352,7 @@
   layer()->SetMasksToBounds(true);
   layer()->SetFillsBoundsOpaquely(false);
 
-  if (is_fullscreen_app_list_enabled_ && !folder_delegate_) {
+  if (!folder_delegate_) {
     suggestions_container_ =
         new SuggestionsContainerView(contents_view_, &pagination_model_);
     AddChildView(suggestions_container_);
@@ -394,15 +378,9 @@
 
   pagination_model_.AddObserver(this);
 
-  if (is_fullscreen_app_list_enabled_) {
-    page_switcher_view_ = new PageSwitcherVertical(&pagination_model_);
-    pagination_controller_.reset(new PaginationController(
-        &pagination_model_, PaginationController::SCROLL_AXIS_VERTICAL));
-  } else {
-    page_switcher_view_ = new PageSwitcherHorizontal(&pagination_model_);
-    pagination_controller_.reset(new PaginationController(
-        &pagination_model_, PaginationController::SCROLL_AXIS_HORIZONTAL));
-  }
+  page_switcher_view_ = new PageSwitcherVertical(&pagination_model_);
+  pagination_controller_.reset(new PaginationController(
+      &pagination_model_, PaginationController::SCROLL_AXIS_VERTICAL));
   AddChildView(page_switcher_view_);
 }
 
@@ -429,11 +407,6 @@
 void AppsGridView::SetLayout(int cols, int rows_per_page) {
   cols_ = cols;
   rows_per_page_ = rows_per_page;
-
-  if (!is_fullscreen_app_list_enabled_) {
-    SetBorder(
-        views::CreateEmptyBorder(0, kAppsGridPadding, 0, kAppsGridPadding));
-  }
 }
 
 // static
@@ -452,26 +425,15 @@
 
 // static
 gfx::Insets AppsGridView::GetTilePadding() {
-  static gfx::Insets tile_padding;
   static gfx::Insets tile_padding_full_screen;
 
   // Full screen mode.
-  if (features::IsFullscreenAppListEnabled()) {
-    if (!tile_padding_full_screen.IsEmpty())
-      return tile_padding_full_screen;
-    tile_padding_full_screen =
-        gfx::Insets(-kTileVerticalPadding, -kTileHorizontalPadding,
-                    -kTileVerticalPadding, -kTileHorizontalPadding);
+  if (!tile_padding_full_screen.IsEmpty())
     return tile_padding_full_screen;
-  }
-
-  // Non full screen mode.
-  if (!tile_padding.IsEmpty()) {
-    return tile_padding;
-  }
-  tile_padding = gfx::Insets(-kTileTopPadding, -kTileLeftRightPadding,
-                             -kTileBottomPadding, -kTileLeftRightPadding);
-  return tile_padding;
+  tile_padding_full_screen =
+      gfx::Insets(-kTileVerticalPadding, -kTileHorizontalPadding,
+                  -kTileVerticalPadding, -kTileHorizontalPadding);
+  return tile_padding_full_screen;
 }
 
 void AppsGridView::ResetForShowApps() {
@@ -864,21 +826,10 @@
 }
 
 gfx::Size AppsGridView::CalculatePreferredSize() const {
-  if (is_fullscreen_app_list_enabled_) {
-    gfx::Size size =
-        gfx::Size(kAppsGridPreferredWidth, kAppsGridPreferredHeight);
-    // Add padding to both side of the apps grid to keep it horizontally
-    // centered since we place page switcher on the right side.
-    size.Enlarge(kAppsGridLeftRightPadding * 2, 0);
-    return size;
-  }
-
-  gfx::Size size = GetTileGridSize();
-  const gfx::Insets insets(GetInsets());
-  // If we are in a folder, ignore the page switcher for height calculations.
-  int page_switcher_height =
-      folder_delegate_ ? 0 : page_switcher_view_->GetPreferredSize().height();
-  size.Enlarge(insets.width(), insets.height() + page_switcher_height);
+  gfx::Size size = gfx::Size(kAppsGridPreferredWidth, kAppsGridPreferredHeight);
+  // Add padding to both side of the apps grid to keep it horizontally
+  // centered since we place page switcher on the right side.
+  size.Enlarge(kAppsGridLeftRightPadding * 2, 0);
   return size;
 }
 
@@ -910,11 +861,9 @@
   if (rect.IsEmpty())
     return;
 
-  if (is_fullscreen_app_list_enabled_) {
-    if (fadeout_layer_delegate_)
-      fadeout_layer_delegate_->layer()->SetBounds(layer()->bounds());
-    rect.Inset(0, kSearchBoxBottomPadding, 0, 0);
-  }
+  if (fadeout_layer_delegate_)
+    fadeout_layer_delegate_->layer()->SetBounds(layer()->bounds());
+  rect.Inset(0, kSearchBoxBottomPadding, 0, 0);
 
   gfx::Rect indicator_rect(rect);
   gfx::Rect arrow_rect(rect);
@@ -963,25 +912,15 @@
   }
   views::ViewModelUtils::SetViewBoundsToIdealBounds(pulsing_blocks_model_);
 
-  if (is_fullscreen_app_list_enabled_) {
-    const int page_switcher_width =
-        page_switcher_view_->GetPreferredSize().width();
-    rect.set_x(rect.right() - page_switcher_width);
-    rect.set_width(page_switcher_width);
-  } else {
-    const int page_switcher_height =
-        page_switcher_view_->GetPreferredSize().height();
-    rect.set_y(rect.bottom() - page_switcher_height);
-    rect.set_height(page_switcher_height);
-  }
+  const int page_switcher_width =
+      page_switcher_view_->GetPreferredSize().width();
+  rect.set_x(rect.right() - page_switcher_width);
+  rect.set_width(page_switcher_width);
   page_switcher_view_->SetBoundsRect(rect);
 }
 
 void AppsGridView::UpdateControlVisibility(AppListViewState app_list_state,
                                            bool is_in_drag) {
-  if (!is_fullscreen_app_list_enabled_)
-    return;
-
   const bool fullscreen_apps_in_drag =
       app_list_state == AppListViewState::FULLSCREEN_ALL_APPS || is_in_drag;
   if (all_apps_indicator_)
@@ -1077,7 +1016,7 @@
 }
 
 int AppsGridView::TilesPerPage(int page) const {
-  if (is_fullscreen_app_list_enabled_ && page == 0)
+  if (page == 0)
     return cols_ * (rows_per_page_ - 1);
   return cols_ * rows_per_page_;
 }
@@ -1246,78 +1185,58 @@
   const Index& selected = GetIndexOfView(selected_view_);
   int target_slot = selected.slot + slot_x_delta + slot_y_delta * cols_;
 
-  if (!is_fullscreen_app_list_enabled_) {
-    if (selected.slot % cols_ == 0 && slot_x_delta == -1) {
-      if (selected.page > 0) {
-        page_delta = -1;
-        target_slot = selected.slot + cols_ - 1;
-      } else {
-        target_slot = selected.slot;
-      }
-    }
-
-    if (selected.slot % cols_ == cols_ - 1 && slot_x_delta == 1) {
-      if (selected.page < pagination_model_.total_pages() - 1) {
-        page_delta = 1;
-        target_slot = selected.slot - cols_ + 1;
-      } else {
-        target_slot = selected.slot;
-      }
-    }
-  } else {
-    // Moving left from the first slot of all apps tiles should move focus to
-    // the last slot of previous page or last tile of suggested apps.
-    if (selected.slot == 0 && slot_x_delta == -1) {
-      if (selected.page == 0) {
-        ClearSelectedView(selected_view_);
-        if (!suggestions_container_)
-          return;
-        suggestions_container_->SetSelectedIndex(
-            suggestions_container_->num_results() - 1);
+  // Moving left from the first slot of all apps tiles should move focus to
+  // the last slot of previous page or last tile of suggested apps.
+  if (selected.slot == 0 && slot_x_delta == -1) {
+    if (selected.page == 0) {
+      ClearSelectedView(selected_view_);
+      if (!suggestions_container_)
         return;
-      } else {
-        page_delta = -1;
-        target_slot = LastIndexOfPage(selected.page + page_delta);
-      }
+      suggestions_container_->SetSelectedIndex(
+          suggestions_container_->num_results() - 1);
+      return;
+    } else {
+      page_delta = -1;
+      target_slot = LastIndexOfPage(selected.page + page_delta);
     }
+  }
 
-    // Moving right from last slot should flip to next page and focus on the
-    // first tile.
-    if (selected.slot == LastIndexOfPage(selected.page) && slot_x_delta == 1) {
+  // Moving right from last slot should flip to next page and focus on the
+  // first tile.
+  if (selected.slot == LastIndexOfPage(selected.page) && slot_x_delta == 1) {
+    page_delta = 1;
+    target_slot = 0;
+  }
+
+  // Moving up from the first row of all apps tiles should move focus to the
+  // last row of previous page or suggested apps.
+  if (selected.slot / cols_ == 0 && slot_y_delta == -1) {
+    if (selected.page == 0) {
+      ClearSelectedView(selected_view_);
+      if (!suggestions_container_)
+        return;
+      const int max_suggestion_index =
+          suggestions_container_->num_results() - 1;
+      int selected_index = std::min(max_suggestion_index, selected.slot);
+      suggestions_container_->SetSelectedIndex(selected_index);
+      return;
+    } else {
+      page_delta = -1;
+      target_slot = LastIndexOfPage(selected.page + page_delta) -
+                    (cols_ - 1 - selected.slot);
+    }
+  }
+
+  // Moving down from the last row of all apps tiles should move focus to the
+  // first row of next page if it exists.
+  if (LastIndexOfPage(selected.page) - selected.slot < cols_ &&
+      slot_y_delta == 1) {
+    if (selected.page < pagination_model_.total_pages() - 1) {
       page_delta = 1;
-      target_slot = 0;
-    }
-
-    // Moving up from the first row of all apps tiles should move focus to the
-    // last row of previous page or suggested apps.
-    if (selected.slot / cols_ == 0 && slot_y_delta == -1) {
-      if (selected.page == 0) {
-        ClearSelectedView(selected_view_);
-        if (!suggestions_container_)
-          return;
-        const int max_suggestion_index =
-            suggestions_container_->num_results() - 1;
-        int selected_index = std::min(max_suggestion_index, selected.slot);
-        suggestions_container_->SetSelectedIndex(selected_index);
-        return;
-      } else {
-        page_delta = -1;
-        target_slot = LastIndexOfPage(selected.page + page_delta) -
-                      (cols_ - 1 - selected.slot);
-      }
-    }
-
-    // Moving down from the last row of all apps tiles should move focus to the
-    // first row of next page if it exists.
-    if (LastIndexOfPage(selected.page) - selected.slot < cols_ &&
-        slot_y_delta == 1) {
-      if (selected.page < pagination_model_.total_pages() - 1) {
-        page_delta = 1;
-        target_slot =
-            (cols_ - 1) - (LastIndexOfPage(selected.page) - selected.slot);
-      } else {
-        target_slot = selected.slot;
-      }
+      target_slot =
+          (cols_ - 1) - (LastIndexOfPage(selected.page) - selected.slot);
+    } else {
+      target_slot = selected.slot;
     }
   }
 
@@ -2496,12 +2415,11 @@
   view_model_.Add(view, index);
   AddChildView(view);
 
-  if (is_fullscreen_app_list_enabled_) {
-    // Ensure that AppListItems that are added to the AppListItemList are not
-    // shown while in PEEKING. The visibility of the app icons will be updated
-    // on drag/animation from PEEKING.
-    view->SetVisible(model_->state_fullscreen() != AppListViewState::PEEKING);
-  }
+  // Ensure that AppListItems that are added to the AppListItemList are not
+  // shown while in PEEKING. The visibility of the app icons will be updated
+  // on drag/animation from PEEKING.
+  view->SetVisible(model_->state_fullscreen() != AppListViewState::PEEKING);
+
   UpdatePaging();
   UpdatePulsingBlockViews();
   Layout();
@@ -2615,25 +2533,18 @@
   int col = base::ClampToRange(
       (point.x() - bounds.x()) / total_tile_size.width(), 0, cols_ - 1);
   int row = rows_per_page_;
-  bool show_suggested_apps =
-      is_fullscreen_app_list_enabled_ && current_page == 0;
+  bool show_suggested_apps = current_page == 0;
   row = base::ClampToRange((point.y() - bounds.y()) / total_tile_size.height(),
                            0, rows_per_page_ - (show_suggested_apps ? 2 : 1));
   return Index(current_page, row * cols_ + col);
 }
 
 gfx::Size AppsGridView::GetTileGridSize() const {
-  if (is_fullscreen_app_list_enabled_)
-    return gfx::Size(kAppsGridPreferredWidth, kAppsGridPreferredHeight);
-
-  gfx::Rect bounds = GetExpectedTileBounds(Index(0, 0));
-  bounds.Union(GetExpectedTileBounds(Index(0, rows_per_page_ * cols_ - 1)));
-  bounds.Inset(GetTilePadding());
-  return bounds.size();
+  return gfx::Size(kAppsGridPreferredWidth, kAppsGridPreferredHeight);
 }
 
 int AppsGridView::GetHeightOnTopOfAllAppsTiles(int page) const {
-  if (!is_fullscreen_app_list_enabled_ || folder_delegate_)
+  if (folder_delegate_)
     return 0;
 
   if (page == 0) {
@@ -2649,9 +2560,7 @@
 
 gfx::Rect AppsGridView::GetExpectedTileBounds(const Index& index) const {
   gfx::Rect bounds(GetContentsBounds());
-  if (is_fullscreen_app_list_enabled_) {
-    bounds.Offset(kAppsGridLeftRightPadding - kTileHorizontalPadding, 0);
-  }
+  bounds.Offset(kAppsGridLeftRightPadding - kTileHorizontalPadding, 0);
   bounds.Inset(0, GetHeightOnTopOfAllAppsTiles(index.page), 0, 0);
   int row = index.slot / cols_;
   int col = index.slot % cols_;
diff --git a/ui/app_list/views/apps_grid_view.h b/ui/app_list/views/apps_grid_view.h
index 3fe3cb9..0cbee48 100644
--- a/ui/app_list/views/apps_grid_view.h
+++ b/ui/app_list/views/apps_grid_view.h
@@ -641,9 +641,6 @@
 
   std::unique_ptr<FadeoutLayerDelegate> fadeout_layer_delegate_;
 
-  // True if the fullscreen app list feature is enabled.
-  const bool is_fullscreen_app_list_enabled_;
-
   // Delay in milliseconds of when |page_flip_timer_| should fire after user
   // drags an item near the edges.
   int page_flip_delay_in_ms_;
diff --git a/ui/app_list/views/contents_view.cc b/ui/app_list/views/contents_view.cc
index 4b8a47c..627079e3 100644
--- a/ui/app_list/views/contents_view.cc
+++ b/ui/app_list/views/contents_view.cc
@@ -48,9 +48,7 @@
 
 ContentsView::ContentsView(AppListMainView* app_list_main_view,
                            AppListView* app_list_view)
-    : app_list_main_view_(app_list_main_view),
-      app_list_view_(app_list_view),
-      is_fullscreen_app_list_enabled_(features::IsFullscreenAppListEnabled()) {
+    : app_list_main_view_(app_list_main_view), app_list_view_(app_list_view) {
   pagination_model_.SetTransitionDurations(kPageTransitionDurationInMs,
                                            kOverscrollPageTransitionDurationMs);
   pagination_model_.AddObserver(this);
@@ -214,17 +212,6 @@
   app_list_pages_[GetActivePageIndex()]->OnWillBeShown();
 
   app_list_main_view_->model()->SetState(state);
-
-  // Set the visibility of the search box's back button.
-  const bool folder_active = state == AppListModel::STATE_APPS &&
-                             apps_container_view_->IsInFolderView();
-
-  if (!is_fullscreen_app_list_enabled_) {
-    app_list_main_view_->search_box_view()->back_button()->SetVisible(
-        state != AppListModel::STATE_START);
-    app_list_main_view_->search_box_view()->Layout();
-    app_list_main_view_->search_box_view()->SetBackButtonLabel(folder_active);
-  }
 }
 
 void ContentsView::ShowSearchResults(bool show) {
@@ -334,18 +321,10 @@
 
 gfx::Rect ContentsView::GetDefaultSearchBoxBounds() const {
   gfx::Rect search_box_bounds;
-  if (is_fullscreen_app_list_enabled_) {
-    search_box_bounds.set_size(GetSearchBoxView()->GetPreferredSize());
-    search_box_bounds.Offset((bounds().width() - search_box_bounds.width()) / 2,
-                             0);
-    search_box_bounds.set_y(kSearchBoxTopPadding);
-  } else {
-    search_box_bounds =
-        gfx::Rect(0, 0, GetDefaultContentsSize().width(),
-                  GetSearchBoxView()->GetPreferredSize().height());
-    search_box_bounds.set_y(kSearchBoxPadding);
-    search_box_bounds.Inset(kSearchBoxPadding, 0);
-  }
+  search_box_bounds.set_size(GetSearchBoxView()->GetPreferredSize());
+  search_box_bounds.Offset((bounds().width() - search_box_bounds.width()) / 2,
+                           0);
+  search_box_bounds.set_y(kSearchBoxTopPadding);
   return search_box_bounds;
 }
 
@@ -358,8 +337,7 @@
 gfx::Rect ContentsView::GetDefaultContentsBounds() const {
   const gfx::Size contents_size(GetDefaultContentsSize());
   gfx::Point origin(0, GetDefaultSearchBoxBounds().bottom());
-  if (is_fullscreen_app_list_enabled_)
-    origin.Offset((bounds().width() - contents_size.width()) / 2, 0);
+  origin.Offset((bounds().width() - contents_size.width()) / 2, 0);
   return gfx::Rect(origin, contents_size);
 }
 
@@ -384,9 +362,7 @@
       if (apps_container_view_->IsInFolderView()) {
         apps_container_view_->app_list_folder_view()->CloseFolderPage();
       } else {
-        is_fullscreen_app_list_enabled_
-            ? app_list_view_->Dismiss()
-            : SetActiveState(AppListModel::STATE_START);
+        app_list_view_->Dismiss();
       }
       break;
     case AppListModel::STATE_SEARCH_RESULTS:
@@ -413,9 +389,7 @@
       search_box_bounds.bottom_right().OffsetFromOrigin();
   bottom_right.SetToMax(
       default_contents_bounds.bottom_right().OffsetFromOrigin());
-  return gfx::Size(bottom_right.x(), is_fullscreen_app_list_enabled_
-                                         ? GetDisplayHeight()
-                                         : bottom_right.y());
+  return gfx::Size(bottom_right.x(), GetDisplayHeight());
 }
 
 void ContentsView::Layout() {
@@ -474,7 +448,6 @@
 }
 
 void ContentsView::FadeOutOnClose(base::TimeDelta animation_duration) {
-  DCHECK(is_fullscreen_app_list_enabled_);
   DoAnimation(animation_duration, layer(), 0.0f);
   DoAnimation(animation_duration, GetSearchBoxView()->layer(), 0.0f);
 }
diff --git a/ui/app_list/views/contents_view.h b/ui/app_list/views/contents_view.h
index e6850e7..4f3226b 100644
--- a/ui/app_list/views/contents_view.h
+++ b/ui/app_list/views/contents_view.h
@@ -230,8 +230,6 @@
   // Manages the pagination for the launcher pages.
   PaginationModel pagination_model_;
 
-  const bool is_fullscreen_app_list_enabled_;
-
   DISALLOW_COPY_AND_ASSIGN(ContentsView);
 };
 
diff --git a/ui/app_list/views/folder_background_view.cc b/ui/app_list/views/folder_background_view.cc
index ae33568..6fffa54d 100644
--- a/ui/app_list/views/folder_background_view.cc
+++ b/ui/app_list/views/folder_background_view.cc
@@ -24,9 +24,7 @@
 }  // namespace
 
 FolderBackgroundView::FolderBackgroundView()
-    : folder_view_(NULL),
-      show_state_(NO_BUBBLE),
-      is_fullscreen_app_list_enabled_(features::IsFullscreenAppListEnabled()) {
+    : folder_view_(NULL), show_state_(NO_BUBBLE) {
   SetPaintToLayer();
   layer()->SetFillsBoundsOpaquely(false);
 }
@@ -93,7 +91,7 @@
 }
 
 float FolderBackgroundView::GetBubbleOpacity() const {
-  return is_fullscreen_app_list_enabled_ ? kFolderBubbleOpacity : 1.0f;
+  return kFolderBubbleOpacity;
 }
 
 }  // namespace app_list
diff --git a/ui/app_list/views/folder_background_view.h b/ui/app_list/views/folder_background_view.h
index c1a3cae..cd5a0fa 100644
--- a/ui/app_list/views/folder_background_view.h
+++ b/ui/app_list/views/folder_background_view.h
@@ -45,7 +45,6 @@
 
   AppListFolderView* folder_view_;
   ShowState show_state_;
-  bool is_fullscreen_app_list_enabled_;
 
   DISALLOW_COPY_AND_ASSIGN(FolderBackgroundView);
 };
diff --git a/ui/app_list/views/folder_header_view.cc b/ui/app_list/views/folder_header_view.cc
index 43a4bd54..e71dd35 100644
--- a/ui/app_list/views/folder_header_view.cc
+++ b/ui/app_list/views/folder_header_view.cc
@@ -30,7 +30,6 @@
 constexpr int kPreferredWidth = 360;
 constexpr int kPreferredHeight = 48;
 constexpr int kBottomSeparatorHeight = 1;
-constexpr int kMaxFolderNameWidth = 300;
 constexpr int kMaxFolderNameWidthFullScreen = 236;
 
 }  // namespace
@@ -57,23 +56,18 @@
           ui::ResourceBundle::GetSharedInstance().GetLocalizedString(
               IDS_APP_LIST_FOLDER_NAME_PLACEHOLDER)),
       delegate_(delegate),
-      folder_name_visible_(true),
-      is_fullscreen_app_list_enabled_(features::IsFullscreenAppListEnabled()) {
+      folder_name_visible_(true) {
   ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
   gfx::FontList font_list = rb.GetFontList(ui::ResourceBundle::MediumFont);
   folder_name_view_->set_placeholder_text_color(kFolderTitleHintTextColor);
   folder_name_view_->set_placeholder_text(folder_name_placeholder_text_);
   folder_name_view_->SetBorder(views::NullBorder());
-  if (is_fullscreen_app_list_enabled_) {
-    // Make folder name font size 14px.
-    folder_name_view_->SetFontList(font_list.DeriveWithSizeDelta(-1));
-    folder_name_view_->SetBackgroundColor(SK_ColorTRANSPARENT);
-    folder_name_view_->SetTextColor(kGridTitleColor);
-  } else {
-    folder_name_view_->SetFontList(font_list);
-    folder_name_view_->SetBackgroundColor(kContentsBackgroundColor);
-    folder_name_view_->SetTextColor(kFolderTitleColor);
-  }
+
+  // Make folder name font size 14px.
+  folder_name_view_->SetFontList(font_list.DeriveWithSizeDelta(-1));
+  folder_name_view_->SetBackgroundColor(SK_ColorTRANSPARENT);
+  folder_name_view_->SetTextColor(kGridTitleColor);
+
   folder_name_view_->set_controller(this);
   AddChildView(folder_name_view_);
 }
@@ -155,11 +149,9 @@
 }
 
 gfx::Size FolderHeaderView::CalculatePreferredSize() const {
-  const int preferred_height = is_fullscreen_app_list_enabled_
-                                   ? kPreferredHeight +
-                                         kBottomSeparatorBottomPadding +
-                                         AppsGridView::GetTilePadding().top()
-                                   : kPreferredHeight;
+  const int preferred_height = kPreferredHeight +
+                               kBottomSeparatorBottomPadding +
+                               AppsGridView::GetTilePadding().top();
   return gfx::Size(kPreferredWidth, preferred_height);
 }
 
@@ -168,8 +160,7 @@
 }
 
 int FolderHeaderView::GetMaxFolderNameWidth() const {
-  return is_fullscreen_app_list_enabled_ ? kMaxFolderNameWidthFullScreen
-                                         : kMaxFolderNameWidth;
+  return kMaxFolderNameWidthFullScreen;
 }
 
 base::string16 FolderHeaderView::GetElidedFolderName(
@@ -222,20 +213,15 @@
     return;
 
   // Draw bottom separator line.
-  rect.Inset(is_fullscreen_app_list_enabled_
-                 ? kAppsGridLeftRightPadding +
-                       (-AppsGridView::GetTilePadding().left()) +
-                       kBottomSeparatorLeftRightPadding
-                 : kAppsGridPadding,
+  rect.Inset(kAppsGridLeftRightPadding +
+                 (-AppsGridView::GetTilePadding().left()) +
+                 kBottomSeparatorLeftRightPadding,
              0);
   int extra_bottom_padding =
-      is_fullscreen_app_list_enabled_
-          ? kBottomSeparatorBottomPadding + AppsGridView::GetTilePadding().top()
-          : 0;
+      kBottomSeparatorBottomPadding + AppsGridView::GetTilePadding().top();
   rect.set_y(rect.bottom() - kBottomSeparatorHeight - extra_bottom_padding);
   rect.set_height(kBottomSeparatorHeight);
-  SkColor color = is_fullscreen_app_list_enabled_ ? kBottomSeparatorColor
-                                                  : kBottomSeparatorColor;
+  SkColor color = kBottomSeparatorColor;
   canvas->FillRect(rect, color);
 }
 
diff --git a/ui/app_list/views/folder_header_view.h b/ui/app_list/views/folder_header_view.h
index 9e2813b..52a49a4 100644
--- a/ui/app_list/views/folder_header_view.h
+++ b/ui/app_list/views/folder_header_view.h
@@ -91,7 +91,6 @@
   FolderHeaderViewDelegate* delegate_;
 
   bool folder_name_visible_;
-  bool is_fullscreen_app_list_enabled_;
 
   DISALLOW_COPY_AND_ASSIGN(FolderHeaderView);
 };
diff --git a/ui/app_list/views/page_switcher_horizontal.cc b/ui/app_list/views/page_switcher_horizontal.cc
deleted file mode 100644
index fa115bf..0000000
--- a/ui/app_list/views/page_switcher_horizontal.cc
+++ /dev/null
@@ -1,286 +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 "ui/app_list/views/page_switcher_horizontal.h"
-
-#include <algorithm>
-
-#include "base/macros.h"
-#include "third_party/skia/include/core/SkPath.h"
-#include "ui/app_list/app_list_constants.h"
-#include "ui/app_list/pagination_model.h"
-#include "ui/gfx/animation/throb_animation.h"
-#include "ui/gfx/canvas.h"
-#include "ui/gfx/geometry/insets.h"
-#include "ui/gfx/skia_util.h"
-#include "ui/views/controls/button/button.h"
-#include "ui/views/layout/box_layout.h"
-
-namespace app_list {
-
-namespace {
-
-const int kPreferredHeight = 58;
-
-const int kMaxButtonSpacing = 18;
-const int kMinButtonSpacing = 4;
-const int kMaxButtonWidth = 68;
-const int kMinButtonWidth = 28;
-const int kButtonHeight = 6;
-const int kButtonCornerRadius = 2;
-const int kButtonStripPadding = 20;
-
-class PageSwitcherButton : public views::Button {
- public:
-  explicit PageSwitcherButton(views::ButtonListener* listener)
-      : views::Button(listener),
-        button_width_(kMaxButtonWidth),
-        selected_range_(0) {}
-  ~PageSwitcherButton() override {}
-
-  void SetSelectedRange(double selected_range) {
-    if (selected_range_ == selected_range)
-      return;
-
-    selected_range_ = selected_range;
-    SchedulePaint();
-  }
-
-  void set_button_width(int button_width) { button_width_ = button_width; }
-
-  // Overridden from views::View:
-  gfx::Size CalculatePreferredSize() const override {
-    return gfx::Size(button_width_, kButtonHeight);
-  }
-
-  void PaintButtonContents(gfx::Canvas* canvas) override {
-    if (state() == STATE_HOVERED)
-      PaintButton(canvas, kPagerHoverColor);
-    else
-      PaintButton(canvas, kPagerNormalColor);
-  }
-
-  void OnGestureEvent(ui::GestureEvent* event) override {
-    Button::OnGestureEvent(event);
-
-    if (event->type() == ui::ET_GESTURE_TAP_DOWN)
-      SetState(views::Button::STATE_HOVERED);
-    else if (event->type() == ui::ET_GESTURE_TAP_CANCEL ||
-             event->type() == ui::ET_GESTURE_TAP)
-      SetState(views::Button::STATE_NORMAL);
-    SchedulePaint();
-  }
-
- private:
-  // Paints a button that has two rounded corner at bottom.
-  void PaintButton(gfx::Canvas* canvas, SkColor base_color) {
-    gfx::Rect rect(GetContentsBounds());
-    rect.ClampToCenteredSize(gfx::Size(button_width_, kButtonHeight));
-
-    SkPath path;
-    path.addRoundRect(gfx::RectToSkRect(rect),
-                      SkIntToScalar(kButtonCornerRadius),
-                      SkIntToScalar(kButtonCornerRadius));
-
-    cc::PaintFlags flags;
-    flags.setAntiAlias(true);
-    flags.setStyle(cc::PaintFlags::kFill_Style);
-    flags.setColor(base_color);
-    canvas->DrawPath(path, flags);
-
-    int selected_start_x = 0;
-    int selected_width = 0;
-    if (selected_range_ > 0) {
-      selected_width = selected_range_ * rect.width();
-    } else if (selected_range_ < 0) {
-      selected_width = -selected_range_ * rect.width();
-      selected_start_x = rect.right() - selected_width;
-    }
-
-    if (selected_width) {
-      gfx::Rect selected_rect(rect);
-      selected_rect.set_x(selected_start_x);
-      selected_rect.set_width(selected_width);
-
-      SkPath selected_path;
-      selected_path.addRoundRect(gfx::RectToSkRect(selected_rect),
-                                 SkIntToScalar(kButtonCornerRadius),
-                                 SkIntToScalar(kButtonCornerRadius));
-      flags.setColor(kPagerSelectedColor);
-      canvas->DrawPath(selected_path, flags);
-    }
-  }
-
-  int button_width_;
-
-  // [-1, 1] range that represents the portion of the button that should be
-  // painted with kSelectedColor. Positive range starts from left side and
-  // negative range starts from the right side.
-  double selected_range_;
-
-  DISALLOW_COPY_AND_ASSIGN(PageSwitcherButton);
-};
-
-// Gets PageSwitcherButton at |index| in |buttons|.
-PageSwitcherButton* GetButtonByIndex(views::View* buttons, int index) {
-  return static_cast<PageSwitcherButton*>(buttons->child_at(index));
-}
-
-}  // namespace
-
-PageSwitcherHorizontal::PageSwitcherHorizontal(PaginationModel* model)
-    : model_(model), buttons_(new views::View) {
-  SetPaintToLayer();
-  layer()->SetFillsBoundsOpaquely(false);
-
-  AddChildView(buttons_);
-
-  TotalPagesChanged();
-  SelectedPageChanged(-1, model->selected_page());
-  model_->AddObserver(this);
-}
-
-PageSwitcherHorizontal::~PageSwitcherHorizontal() {
-  model_->RemoveObserver(this);
-}
-
-int PageSwitcherHorizontal::GetPageForPoint(const gfx::Point& point) const {
-  if (!buttons_->bounds().Contains(point))
-    return -1;
-
-  gfx::Point buttons_point(point);
-  views::View::ConvertPointToTarget(this, buttons_, &buttons_point);
-
-  for (int i = 0; i < buttons_->child_count(); ++i) {
-    const views::View* button = buttons_->child_at(i);
-    if (button->bounds().Contains(buttons_point))
-      return i;
-  }
-
-  return -1;
-}
-
-void PageSwitcherHorizontal::UpdateUIForDragPoint(const gfx::Point& point) {
-  int page = GetPageForPoint(point);
-
-  const int button_count = buttons_->child_count();
-  if (page >= 0 && page < button_count) {
-    PageSwitcherButton* button =
-        static_cast<PageSwitcherButton*>(buttons_->child_at(page));
-    button->SetState(views::Button::STATE_HOVERED);
-    return;
-  }
-
-  for (int i = 0; i < button_count; ++i) {
-    PageSwitcherButton* button =
-        static_cast<PageSwitcherButton*>(buttons_->child_at(i));
-    button->SetState(views::Button::STATE_NORMAL);
-  }
-}
-
-gfx::Rect PageSwitcherHorizontal::GetButtonsBoundsInScreen() {
-  return buttons_->GetBoundsInScreen();
-}
-
-gfx::Size PageSwitcherHorizontal::CalculatePreferredSize() const {
-  // Always return a size with correct height so that container resize is not
-  // needed when more pages are added.
-  return gfx::Size(buttons_->GetPreferredSize().width(), kPreferredHeight);
-}
-
-void PageSwitcherHorizontal::Layout() {
-  gfx::Rect rect(GetContentsBounds());
-
-  CalculateButtonWidthAndSpacing(rect.width());
-
-  // Makes |buttons_| horizontally center and vertically fill.
-  gfx::Size buttons_size(buttons_->GetPreferredSize());
-  gfx::Rect buttons_bounds(rect.CenterPoint().x() - buttons_size.width() / 2,
-                           rect.y(), buttons_size.width(), rect.height());
-  buttons_->SetBoundsRect(gfx::IntersectRects(rect, buttons_bounds));
-}
-
-void PageSwitcherHorizontal::CalculateButtonWidthAndSpacing(
-    int contents_width) {
-  const int button_count = buttons_->child_count();
-  if (!button_count)
-    return;
-
-  contents_width -= 2 * kButtonStripPadding;
-
-  int button_width = kMinButtonWidth;
-  int button_spacing = kMinButtonSpacing;
-  if (button_count > 1) {
-    button_spacing =
-        (contents_width - button_width * button_count) / (button_count - 1);
-    button_spacing = std::min(kMaxButtonSpacing,
-                              std::max(kMinButtonSpacing, button_spacing));
-  }
-
-  button_width =
-      (contents_width - (button_count - 1) * button_spacing) / button_count;
-  button_width =
-      std::min(kMaxButtonWidth, std::max(kMinButtonWidth, button_width));
-
-  buttons_->SetLayoutManager(std::make_unique<views::BoxLayout>(
-      views::BoxLayout::kHorizontal, gfx::Insets(0, kButtonStripPadding),
-      button_spacing));
-  for (int i = 0; i < button_count; ++i) {
-    PageSwitcherButton* button =
-        static_cast<PageSwitcherButton*>(buttons_->child_at(i));
-    button->set_button_width(button_width);
-  }
-}
-
-void PageSwitcherHorizontal::ButtonPressed(views::Button* sender,
-                                           const ui::Event& event) {
-  for (int i = 0; i < buttons_->child_count(); ++i) {
-    if (sender == static_cast<views::Button*>(buttons_->child_at(i))) {
-      model_->SelectPage(i, true /* animate */);
-      break;
-    }
-  }
-}
-
-void PageSwitcherHorizontal::TotalPagesChanged() {
-  buttons_->RemoveAllChildViews(true);
-  for (int i = 0; i < model_->total_pages(); ++i) {
-    PageSwitcherButton* button = new PageSwitcherButton(this);
-    button->SetSelectedRange(i == model_->selected_page() ? 1 : 0);
-    buttons_->AddChildView(button);
-  }
-  buttons_->SetVisible(model_->total_pages() > 1);
-  Layout();
-}
-
-void PageSwitcherHorizontal::SelectedPageChanged(int old_selected,
-                                                 int new_selected) {
-  if (old_selected >= 0 && old_selected < buttons_->child_count())
-    GetButtonByIndex(buttons_, old_selected)->SetSelectedRange(0);
-  if (new_selected >= 0 && new_selected < buttons_->child_count())
-    GetButtonByIndex(buttons_, new_selected)->SetSelectedRange(1);
-}
-
-void PageSwitcherHorizontal::TransitionStarted() {}
-
-void PageSwitcherHorizontal::TransitionChanged() {
-  const int current_page = model_->selected_page();
-  const int target_page = model_->transition().target_page;
-
-  double progress = model_->transition().progress;
-  double remaining = progress - 1;
-
-  if (current_page > target_page) {
-    remaining = -remaining;
-    progress = -progress;
-  }
-
-  GetButtonByIndex(buttons_, current_page)->SetSelectedRange(remaining);
-  if (model_->is_valid_page(target_page))
-    GetButtonByIndex(buttons_, target_page)->SetSelectedRange(progress);
-}
-
-void PageSwitcherHorizontal::TransitionEnded() {}
-
-}  // namespace app_list
diff --git a/ui/app_list/views/page_switcher_horizontal.h b/ui/app_list/views/page_switcher_horizontal.h
deleted file mode 100644
index 43facf7..0000000
--- a/ui/app_list/views/page_switcher_horizontal.h
+++ /dev/null
@@ -1,57 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_APP_LIST_VIEWS_PAGE_SWITCHER_HORIZONTAL_H_
-#define UI_APP_LIST_VIEWS_PAGE_SWITCHER_HORIZONTAL_H_
-
-#include "base/macros.h"
-#include "ui/app_list/pagination_model_observer.h"
-#include "ui/app_list/views/page_switcher.h"
-#include "ui/views/controls/button/button.h"
-
-namespace app_list {
-
-class PaginationModel;
-
-// PageSwitcher represents its underlying PaginationModel with a button strip.
-// Each page in the PageinationModel has a button in the strip and when the
-// button is clicked, the corresponding page becomes selected.
-class PageSwitcherHorizontal : public PageSwitcher,
-                               public views::ButtonListener,
-                               public PaginationModelObserver {
- public:
-  explicit PageSwitcherHorizontal(PaginationModel* model);
-  ~PageSwitcherHorizontal() override;
-
-  // Overridden from PageSwitcher:
-  int GetPageForPoint(const gfx::Point& point) const override;
-  void UpdateUIForDragPoint(const gfx::Point& point) override;
-  gfx::Rect GetButtonsBoundsInScreen() override;
-
-  // Overridden from views::View:
-  gfx::Size CalculatePreferredSize() const override;
-  void Layout() override;
-
- private:
-  void CalculateButtonWidthAndSpacing(int contents_width);
-
-  // Overridden from views::ButtonListener:
-  void ButtonPressed(views::Button* sender, const ui::Event& event) override;
-
-  // Overridden from PaginationModelObserver:
-  void TotalPagesChanged() override;
-  void SelectedPageChanged(int old_selected, int new_selected) override;
-  void TransitionStarted() override;
-  void TransitionChanged() override;
-  void TransitionEnded() override;
-
-  PaginationModel* model_;  // Owned by AppsGridView.
-  views::View* buttons_;    // Owned by views hierarchy.
-
-  DISALLOW_COPY_AND_ASSIGN(PageSwitcherHorizontal);
-};
-
-}  // namespace app_list
-
-#endif  // UI_APP_LIST_VIEWS_PAGE_SWITCHER_HORIZONTAL_H_
diff --git a/ui/app_list/views/search_box_view.cc b/ui/app_list/views/search_box_view.cc
index 39b5fcf3..6149dd05 100644
--- a/ui/app_list/views/search_box_view.cc
+++ b/ui/app_list/views/search_box_view.cc
@@ -9,7 +9,6 @@
 #include <vector>
 
 #include "ash/app_list/model/search/search_box_model.h"
-#include "ash/app_list/model/speech/speech_ui_model.h"
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
 #include "build/build_config.h"
@@ -65,7 +64,6 @@
     SkColorSetARGBMacro(0x3D, 0xFF, 0xFF, 0xFF);
 
 constexpr int kSearchBoxBorderCornerRadiusSearchResult = 4;
-constexpr int kMicIconSize = 24;
 constexpr int kCloseIconSize = 24;
 constexpr int kSearchBoxFocusBorderCornerRadius = 28;
 
@@ -261,13 +259,11 @@
       l10n_util::GetStringUTF16(IDS_APP_LIST_CLEAR_SEARCHBOX));
   content_container_->AddChildView(close_button_);
 
-  view_delegate_->GetSpeechUI()->AddObserver(this);
   view_delegate_->AddObserver(this);
   ModelChanged();
 }
 
 SearchBoxView::~SearchBoxView() {
-  view_delegate_->GetSpeechUI()->RemoveObserver(this);
   search_model_->search_box()->RemoveObserver(this);
   view_delegate_->RemoveObserver(this);
 }
@@ -281,7 +277,6 @@
   UpdateSearchIcon();
   search_model_->search_box()->AddObserver(this);
 
-  SpeechRecognitionButtonPropChanged();
   HintTextChanged();
   OnWallpaperColorsChanged();
 }
@@ -418,8 +413,6 @@
 
 void SearchBoxView::OnEnabledChanged() {
   search_box_->SetEnabled(enabled());
-  if (speech_button_)
-    speech_button_->SetEnabled(enabled());
   if (close_button_)
     close_button_->SetEnabled(enabled());
 }
@@ -468,8 +461,6 @@
                                   const ui::Event& event) {
   if (back_button_ && sender == back_button_) {
     delegate_->BackButtonPressed();
-  } else if (speech_button_ && sender == speech_button_) {
-    view_delegate_->StartSpeechRecognition();
   } else if (close_button_ && sender == close_button_) {
     ClearSearch();
     app_list_view_->SetStateFromSearchBoxView(true);
@@ -639,33 +630,6 @@
   return OnTextfieldEvent();
 }
 
-void SearchBoxView::SpeechRecognitionButtonPropChanged() {
-  const SearchBoxModel::SpeechButtonProperty* speech_button_prop =
-      search_model_->search_box()->speech_button();
-  if (speech_button_prop) {
-    if (!speech_button_) {
-      speech_button_ = new SearchBoxImageButton(this);
-      content_container_->AddChildView(speech_button_);
-    }
-
-    speech_button_->SetAccessibleName(speech_button_prop->accessible_name);
-
-    speech_button_->SetImage(
-        views::Button::STATE_NORMAL,
-        gfx::CreateVectorIcon(kIcMicBlackIcon, kMicIconSize,
-                              kDefaultSearchboxColor));
-
-    speech_button_->SetTooltipText(speech_button_prop->tooltip);
-  } else {
-    if (speech_button_) {
-      // Deleting a view will detach it from its parent.
-      delete speech_button_;
-      speech_button_ = nullptr;
-    }
-  }
-  Layout();
-}
-
 void SearchBoxView::HintTextChanged() {
   const app_list::SearchBoxModel* search_box = search_model_->search_box();
   search_box_->set_placeholder_text(search_box->hint_text());
@@ -696,12 +660,6 @@
   SetBackgroundColor(
       prominent_colors[static_cast<int>(ColorProfileType::LIGHT_VIBRANT)]);
   UpdateSearchIcon();
-  if (speech_button_) {
-    speech_button_->SetImage(
-        views::Button::STATE_NORMAL,
-        gfx::CreateVectorIcon(kIcMicBlackIcon, kMicIconSize,
-                              search_box_color_));
-  }
   close_button_->SetImage(
       views::Button::STATE_NORMAL,
       gfx::CreateVectorIcon(kIcCloseIcon, kCloseIconSize, search_box_color_));
@@ -710,12 +668,6 @@
   SchedulePaint();
 }
 
-void SearchBoxView::OnSpeechRecognitionStateChanged(
-    SpeechRecognitionState new_state) {
-  SpeechRecognitionButtonPropChanged();
-  SchedulePaint();
-}
-
 void SearchBoxView::UpdateSearchIcon() {
   const gfx::VectorIcon& google_icon =
       is_search_box_active() ? kIcGoogleColorIcon : kIcGoogleBlackIcon;
diff --git a/ui/app_list/views/search_box_view.h b/ui/app_list/views/search_box_view.h
index 7b22cb2..33b7aa7 100644
--- a/ui/app_list/views/search_box_view.h
+++ b/ui/app_list/views/search_box_view.h
@@ -11,7 +11,6 @@
 #include "ash/app_list/model/app_list_model.h"
 #include "ash/app_list/model/search/search_box_model_observer.h"
 #include "ash/app_list/model/search/search_model.h"
-#include "ash/app_list/model/speech/speech_ui_model_observer.h"
 #include "base/macros.h"
 #include "ui/app_list/app_list_constants.h"
 #include "ui/app_list/app_list_view_delegate_observer.h"
@@ -44,7 +43,6 @@
                                       public views::TextfieldController,
                                       public views::ButtonListener,
                                       public SearchBoxModelObserver,
-                                      public SpeechUIModelObserver,
                                       public AppListViewDelegateObserver {
  public:
   SearchBoxView(SearchBoxViewDelegate* delegate,
@@ -184,15 +182,10 @@
                           const ui::GestureEvent& gesture_event) override;
 
   // Overridden from SearchBoxModelObserver:
-  void SpeechRecognitionButtonPropChanged() override;
   void HintTextChanged() override;
   void SelectionModelChanged() override;
   void Update() override;
 
-  // Overridden from SpeechUIModelObserver:
-  void OnSpeechRecognitionStateChanged(
-      SpeechRecognitionState new_state) override;
-
   // Overridden from AppListViewDelegateObserver:
   void OnWallpaperColorsChanged() override;
 
@@ -207,7 +200,6 @@
   views::View* content_container_;
   views::ImageView* search_icon_ = nullptr;
   SearchBoxImageButton* back_button_ = nullptr;
-  SearchBoxImageButton* speech_button_ = nullptr;
   SearchBoxImageButton* close_button_ = nullptr;
   views::Textfield* search_box_;
   views::View* search_box_right_space_ = nullptr;
diff --git a/ui/app_list/views/speech_view.cc b/ui/app_list/views/speech_view.cc
deleted file mode 100644
index 0edd2efb..0000000
--- a/ui/app_list/views/speech_view.cc
+++ /dev/null
@@ -1,254 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/app_list/views/speech_view.h"
-
-#include <stdint.h>
-
-#include <limits>
-
-#include "ash/app_list/model/app_list_model.h"
-#include "ash/app_list/model/speech/speech_ui_model.h"
-#include "base/macros.h"
-#include "base/strings/utf_string_conversions.h"
-#include "third_party/skia/include/core/SkPath.h"
-#include "ui/app_list/app_list_constants.h"
-#include "ui/app_list/app_list_view_delegate.h"
-#include "ui/app_list/resources/grit/app_list_resources.h"
-#include "ui/base/l10n/l10n_util.h"
-#include "ui/base/resource/resource_bundle.h"
-#include "ui/gfx/canvas.h"
-#include "ui/gfx/path.h"
-#include "ui/gfx/shadow_value.h"
-#include "ui/strings/grit/ui_strings.h"
-#include "ui/views/animation/bounds_animator.h"
-#include "ui/views/background.h"
-#include "ui/views/controls/button/image_button.h"
-#include "ui/views/controls/image_view.h"
-#include "ui/views/controls/label.h"
-#include "ui/views/layout/fill_layout.h"
-#include "ui/views/masked_targeter_delegate.h"
-#include "ui/views/shadow_border.h"
-
-namespace app_list {
-
-namespace {
-
-const int kSpeechViewMaxHeight = 300;
-const int kMicButtonMargin = 12;
-const int kTextMargin = 32;
-const int kLogoMarginLeft = 30;
-const int kLogoMarginTop = 28;
-const int kLogoWidth = 104;
-const int kLogoHeight = 36;
-const int kIndicatorCenterOffsetY = -1;
-const int kIndicatorRadiusMinOffset = -3;
-const int kIndicatorRadiusMax = 100;
-const int kIndicatorAnimationDuration = 100;
-const SkColor kHintTextColor = SkColorSetRGB(119, 119, 119);
-const SkColor kResultTextColor = SkColorSetRGB(178, 178, 178);
-const SkColor kSoundLevelIndicatorColor = SkColorSetRGB(219, 219, 219);
-
-class SoundLevelIndicator : public views::View {
- public:
-  SoundLevelIndicator();
-  ~SoundLevelIndicator() override;
-
- private:
-  // Overridden from views::View:
-  void OnPaint(gfx::Canvas* canvas) override;
-
-  DISALLOW_COPY_AND_ASSIGN(SoundLevelIndicator);
-};
-
-SoundLevelIndicator::SoundLevelIndicator() {}
-
-SoundLevelIndicator::~SoundLevelIndicator() {}
-
-void SoundLevelIndicator::OnPaint(gfx::Canvas* canvas) {
-  cc::PaintFlags flags;
-  flags.setStyle(cc::PaintFlags::kFill_Style);
-  flags.setColor(kSoundLevelIndicatorColor);
-  flags.setAntiAlias(true);
-  canvas->DrawCircle(bounds().CenterPoint(), width() / 2, flags);
-}
-
-// MicButton is an image button with a circular hit test mask.
-class MicButton : public views::ImageButton,
-                  public views::MaskedTargeterDelegate {
- public:
-  explicit MicButton(views::ButtonListener* listener);
-  ~MicButton() override;
-
- private:
-  // views::MaskedTargeterDelegate:
-  bool GetHitTestMask(gfx::Path* mask) const override;
-
-  DISALLOW_COPY_AND_ASSIGN(MicButton);
-};
-
-MicButton::MicButton(views::ButtonListener* listener)
-    : views::ImageButton(listener) {}
-
-MicButton::~MicButton() {}
-
-bool MicButton::GetHitTestMask(gfx::Path* mask) const {
-  DCHECK(mask);
-
-  // The mic button icon is a circle.
-  gfx::Rect local_bounds = GetLocalBounds();
-  int radius = local_bounds.width() / 2 + kIndicatorRadiusMinOffset;
-  gfx::Point center = local_bounds.CenterPoint();
-  center.set_y(center.y() + kIndicatorCenterOffsetY);
-  mask->addCircle(SkIntToScalar(center.x()),
-                  SkIntToScalar(center.y()),
-                  SkIntToScalar(radius));
-  return true;
-}
-
-}  // namespace
-
-// static
-
-SpeechView::SpeechView(AppListViewDelegate* delegate)
-    : delegate_(delegate),
-      logo_(NULL) {
-  SetBorder(std::unique_ptr<views::Border>(
-      new views::ShadowBorder(GetShadowForZHeight(1))));
-
-  // To keep the painting order of the border and the background, this class
-  // actually has a single child of 'container' which has white background and
-  // contains all components.
-  views::View* container = new views::View();
-  container->SetBackground(views::CreateSolidBackground(SK_ColorWHITE));
-
-  const gfx::ImageSkia& logo_image = delegate_->GetSpeechUI()->logo();
-  if (!logo_image.isNull()) {
-    logo_ = new views::ImageView();
-    logo_->SetImage(&logo_image);
-    container->AddChildView(logo_);
-  }
-
-  indicator_ = new SoundLevelIndicator();
-  indicator_->SetVisible(false);
-  container->AddChildView(indicator_);
-
-  MicButton* mic_button = new MicButton(this);
-  mic_button_ = mic_button;
-  container->AddChildView(mic_button_);
-  mic_button_->SetEventTargeter(std::unique_ptr<views::ViewTargeter>(
-      new views::ViewTargeter(mic_button)));
-
-  // TODO(mukai): use BoundedLabel to cap 2 lines.
-  ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
-  speech_result_ = new views::Label(
-      base::string16(), {bundle.GetFontList(ui::ResourceBundle::LargeFont)});
-  speech_result_->SetMultiLine(true);
-  speech_result_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
-
-  container->AddChildView(speech_result_);
-
-  AddChildView(container);
-
-  delegate_->GetSpeechUI()->AddObserver(this);
-  indicator_animator_.reset(new views::BoundsAnimator(container));
-  indicator_animator_->SetAnimationDuration(kIndicatorAnimationDuration);
-  indicator_animator_->set_tween_type(gfx::Tween::LINEAR);
-
-  Reset();
-}
-
-SpeechView::~SpeechView() {
-  delegate_->GetSpeechUI()->RemoveObserver(this);
-}
-
-void SpeechView::Reset() {
-  OnSpeechRecognitionStateChanged(delegate_->GetSpeechUI()->state());
-}
-
-int SpeechView::GetIndicatorRadius(uint8_t level) {
-  int radius_min = mic_button_->width() / 2 + kIndicatorRadiusMinOffset;
-  int range = kIndicatorRadiusMax - radius_min;
-  return level * range / std::numeric_limits<uint8_t>::max() + radius_min;
-}
-
-void SpeechView::Layout() {
-  views::View* container = child_at(0);
-  container->SetBoundsRect(GetContentsBounds());
-
-  // Because container is a pure View, this class should layout its children.
-  const gfx::Rect contents_bounds = container->GetContentsBounds();
-  if (logo_)
-    logo_->SetBounds(kLogoMarginLeft, kLogoMarginTop, kLogoWidth, kLogoHeight);
-  gfx::Size mic_size = mic_button_->GetPreferredSize();
-  gfx::Point mic_origin(
-      contents_bounds.right() - kMicButtonMargin - mic_size.width(),
-      contents_bounds.y() + kMicButtonMargin);
-  mic_button_->SetBoundsRect(gfx::Rect(mic_origin, mic_size));
-
-  int speech_width = contents_bounds.width() - kTextMargin * 2;
-  int speech_height = speech_result_->GetHeightForWidth(speech_width);
-  speech_result_->SetBounds(
-      contents_bounds.x() + kTextMargin,
-      contents_bounds.bottom() - kTextMargin - speech_height,
-      speech_width,
-      speech_height);
-}
-
-gfx::Size SpeechView::CalculatePreferredSize() const {
-  return gfx::Size(0, kSpeechViewMaxHeight);
-}
-
-void SpeechView::ButtonPressed(views::Button* sender, const ui::Event& event) {
-  delegate_->StopSpeechRecognition();
-}
-
-void SpeechView::OnSpeechSoundLevelChanged(uint8_t level) {
-  if (!visible() ||
-      delegate_->GetSpeechUI()->state() == SPEECH_RECOGNITION_NETWORK_ERROR)
-    return;
-
-  gfx::Point origin = mic_button_->bounds().CenterPoint();
-  int radius = GetIndicatorRadius(level);
-  origin.Offset(-radius, -radius + kIndicatorCenterOffsetY);
-  gfx::Rect indicator_bounds =
-      gfx::Rect(origin, gfx::Size(radius * 2, radius * 2));
-  if (indicator_->visible()) {
-    indicator_animator_->AnimateViewTo(indicator_, indicator_bounds);
-  } else {
-    indicator_->SetVisible(true);
-    indicator_->SetBoundsRect(indicator_bounds);
-  }
-}
-
-void SpeechView::OnSpeechResult(const base::string16& result,
-                                bool is_final) {
-  speech_result_->SetText(result);
-  speech_result_->SetEnabledColor(kResultTextColor);
-  Layout();
-}
-
-void SpeechView::OnSpeechRecognitionStateChanged(
-    SpeechRecognitionState new_state) {
-  int resource_id = IDR_APP_LIST_SPEECH_MIC_OFF;
-  if (new_state == SPEECH_RECOGNITION_RECOGNIZING)
-    resource_id = IDR_APP_LIST_SPEECH_MIC_ON;
-  else if (new_state == SPEECH_RECOGNITION_IN_SPEECH)
-    resource_id = IDR_APP_LIST_SPEECH_MIC_RECORDING;
-
-  int text_resource_id = IDS_APP_LIST_SPEECH_HINT_TEXT;
-
-  if (new_state == SPEECH_RECOGNITION_NETWORK_ERROR) {
-    text_resource_id = IDS_APP_LIST_SPEECH_NETWORK_ERROR_HINT_TEXT;
-    indicator_->SetVisible(false);
-  }
-  speech_result_->SetText(l10n_util::GetStringUTF16(text_resource_id));
-  speech_result_->SetEnabledColor(kHintTextColor);
-
-  ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
-  mic_button_->SetImage(views::Button::STATE_NORMAL,
-                        bundle.GetImageSkiaNamed(resource_id));
-}
-
-}  // namespace app_list
diff --git a/ui/app_list/views/speech_view.h b/ui/app_list/views/speech_view.h
deleted file mode 100644
index 3f706d48..0000000
--- a/ui/app_list/views/speech_view.h
+++ /dev/null
@@ -1,69 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_APP_LIST_VIEWS_SPEECH_VIEW_H_
-#define UI_APP_LIST_VIEWS_SPEECH_VIEW_H_
-
-#include <stdint.h>
-
-#include "ash/app_list/model/speech/speech_ui_model_observer.h"
-#include "base/macros.h"
-#include "ui/app_list/app_list_export.h"
-#include "ui/views/controls/button/button.h"
-#include "ui/views/view.h"
-
-namespace views {
-class BoundsAnimator;
-class ImageButton;
-class ImageView;
-class Label;
-}
-
-namespace app_list {
-
-class AppListViewDelegate;
-
-// SpeechView provides the card-like UI for the search-by-speech.
-class APP_LIST_EXPORT SpeechView : public views::View,
-                                   public views::ButtonListener,
-                                   public SpeechUIModelObserver {
- public:
-  explicit SpeechView(AppListViewDelegate* delegate);
-  ~SpeechView() override;
-
-  // Reset to the original state.
-  void Reset();
-
-  // Overridden from views::View:
-  void Layout() override;
-  gfx::Size CalculatePreferredSize() const override;
-
-  views::ImageButton* mic_button() { return mic_button_; }
-
- private:
-  int GetIndicatorRadius(uint8_t level);
-
-  // Overridden from views::ButtonListener:
-  void ButtonPressed(views::Button* sender, const ui::Event& event) override;
-
-  // Overridden from SpeechUIModelObserver:
-  void OnSpeechSoundLevelChanged(uint8_t level) override;
-  void OnSpeechResult(const base::string16& result, bool is_final) override;
-  void OnSpeechRecognitionStateChanged(
-      SpeechRecognitionState new_state) override;
-
-  AppListViewDelegate* delegate_;
-
-  views::ImageView* logo_;
-  views::View* indicator_;
-  views::ImageButton* mic_button_;
-  views::Label* speech_result_;
-  std::unique_ptr<views::BoundsAnimator> indicator_animator_;
-
-  DISALLOW_COPY_AND_ASSIGN(SpeechView);
-};
-
-}  // namespace app_list
-
-#endif  // UI_APP_LIST_VIEWS_SPEECH_VIEW_H_
diff --git a/ui/app_list/views/speech_view_unittest.cc b/ui/app_list/views/speech_view_unittest.cc
deleted file mode 100644
index 122e934c..0000000
--- a/ui/app_list/views/speech_view_unittest.cc
+++ /dev/null
@@ -1,86 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/app_list/views/speech_view.h"
-
-#include "base/macros.h"
-#include "ui/app_list/test/app_list_test_view_delegate.h"
-#include "ui/events/event_utils.h"
-#include "ui/views/controls/button/image_button.h"
-#include "ui/views/test/widget_test.h"
-
-namespace app_list {
-namespace test {
-
-class SpeechViewTest : public views::test::WidgetTest,
-                       public AppListTestViewDelegate {
- public:
-  SpeechViewTest() {}
-  ~SpeechViewTest() override {}
-
-  // Overridden from testing::Test:
-  void SetUp() override {
-    views::test::WidgetTest::SetUp();
-    widget_ = CreateTopLevelPlatformWidget();
-    widget_->SetBounds(gfx::Rect(0, 0, 300, 200));
-    view_ = new SpeechView(&view_delegate_);
-    widget_->GetContentsView()->AddChildView(view_);
-    view_->SetBoundsRect(widget_->GetContentsView()->GetLocalBounds());
-  }
-
-  void TearDown() override {
-    widget_->CloseNow();
-    views::test::WidgetTest::TearDown();
-  }
-
- protected:
-  SpeechView* view() { return view_; }
-  views::Widget* widget() { return widget_; }
-
-  int GetStopSpeechRecognitionCountAndReset() {
-    return view_delegate_.GetStopSpeechRecognitionCountAndReset();
-  }
-
- private:
-  AppListTestViewDelegate view_delegate_;
-  views::Widget* widget_;
-  SpeechView* view_;
-
-  DISALLOW_COPY_AND_ASSIGN(SpeechViewTest);
-};
-
-// Tests that clicking within the circular hit-test mask of MicButton invokes
-// SpeechView::StopSpeechRecognition() and clicking outside of the
-// hit-test mask does not.
-TEST_F(SpeechViewTest, ClickMicButton) {
-  EXPECT_EQ(0, GetStopSpeechRecognitionCountAndReset());
-  gfx::Rect screen_bounds(view()->mic_button()->GetBoundsInScreen());
-
-  // Simulate a mouse click in the center of the MicButton.
-  ui::MouseEvent press(ui::ET_MOUSE_PRESSED, screen_bounds.CenterPoint(),
-                       screen_bounds.CenterPoint(), ui::EventTimeForNow(),
-                       ui::EF_LEFT_MOUSE_BUTTON, 0);
-  ui::MouseEvent release(ui::ET_MOUSE_RELEASED, screen_bounds.CenterPoint(),
-                         screen_bounds.CenterPoint(), ui::EventTimeForNow(),
-                         ui::EF_LEFT_MOUSE_BUTTON, 0);
-  widget()->OnMouseEvent(&press);
-  widget()->OnMouseEvent(&release);
-  EXPECT_EQ(1, GetStopSpeechRecognitionCountAndReset());
-
-  // Simulate a mouse click in the bottom right-hand corner of the
-  // MicButton's view bounds (which would fall outside of its
-  // circular hit-test mask).
-  gfx::Point bottom_right(screen_bounds.right() - 1,
-                          screen_bounds.bottom() - 2);
-  press = ui::MouseEvent(ui::ET_MOUSE_PRESSED, bottom_right, bottom_right,
-                         ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON, 0);
-  release = ui::MouseEvent(ui::ET_MOUSE_RELEASED, bottom_right, bottom_right,
-                           ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON, 0);
-  widget()->OnMouseEvent(&press);
-  widget()->OnMouseEvent(&release);
-  EXPECT_EQ(0, GetStopSpeechRecognitionCountAndReset());
-}
-
-}  // namespace test
-}  // namespace app_list
diff --git a/ui/base/test/cocoa_helper.h b/ui/base/test/cocoa_helper.h
index ebea0fb2..11de905 100644
--- a/ui/base/test/cocoa_helper.h
+++ b/ui/base/test/cocoa_helper.h
@@ -32,6 +32,10 @@
 // NSWindowDidChangeOcclusionStateNotification.
 @property(nonatomic) BOOL pretendIsOccluded;
 
+// Value to return for -isOnActiveSpace. Posts
+// NSWorkspaceActiveSpaceDidChangeNotification when set.
+@property(nonatomic) BOOL pretendIsOnActiveSpace;
+
 // Whether to handle the key view loop as if full keyboard access is enabled.
 @property(nonatomic) BOOL pretendFullKeyboardAccessIsEnabled;
 
diff --git a/ui/base/test/cocoa_helper.mm b/ui/base/test/cocoa_helper.mm
index 2ff39bd..0b48d89 100644
--- a/ui/base/test/cocoa_helper.mm
+++ b/ui/base/test/cocoa_helper.mm
@@ -33,6 +33,7 @@
 
 @synthesize pretendIsKeyWindow = pretendIsKeyWindow_;
 @synthesize pretendIsOccluded = pretendIsOccluded_;
+@synthesize pretendIsOnActiveSpace = pretendIsOnActiveSpace_;
 @synthesize pretendFullKeyboardAccessIsEnabled =
     pretendFullKeyboardAccessIsEnabled_;
 @synthesize useDefaultConstraints = useDefaultConstraints_;
@@ -44,6 +45,7 @@
                               defer:NO];
   if (self) {
     useDefaultConstraints_ = YES;
+    pretendIsOnActiveSpace_ = YES;
   }
   return self;
 }
@@ -58,6 +60,14 @@
   [super dealloc];
 }
 
+- (BOOL)isKeyWindow {
+  return pretendIsKeyWindow_;
+}
+
+- (BOOL)isOnActiveSpace {
+  return pretendIsOnActiveSpace_;
+}
+
 - (void)makePretendKeyWindowAndSetFirstResponder:(NSResponder*)responder {
   EXPECT_TRUE([self makeFirstResponder:responder]);
   self.pretendIsKeyWindow = YES;
@@ -75,6 +85,13 @@
                     object:self];
 }
 
+- (void)setPretendIsOnActiveSpace:(BOOL)pretendIsOnActiveSpace {
+  pretendIsOnActiveSpace_ = pretendIsOnActiveSpace;
+  [[NSWorkspace sharedWorkspace].notificationCenter
+      postNotificationName:NSWorkspaceActiveSpaceDidChangeNotification
+                    object:[NSWorkspace sharedWorkspace]];
+}
+
 - (void)setPretendFullKeyboardAccessIsEnabled:(BOOL)enabled {
   EXPECT_TRUE([NSWindow
       instancesRespondToSelector:@selector(_allowsAnyValidResponder)]);
@@ -82,10 +99,6 @@
   [self recalculateKeyViewLoop];
 }
 
-- (BOOL)isKeyWindow {
-  return pretendIsKeyWindow_;
-}
-
 // Override of an undocumented AppKit method which controls call to check if
 // full keyboard access is enabled. Its presence is verified in
 // -setPretendFullKeyboardAccessIsEnabled:.
diff --git a/ui/file_manager/file_manager/foreground/js/file_manager_commands.js b/ui/file_manager/file_manager/foreground/js/file_manager_commands.js
index d43a0c0e..ef792f2b 100644
--- a/ui/file_manager/file_manager/foreground/js/file_manager_commands.js
+++ b/ui/file_manager/file_manager/foreground/js/file_manager_commands.js
@@ -348,8 +348,8 @@
       this.updateAvailability.bind(this));
 
   chrome.commandLinePrivate.hasSwitch(
-      'disable-zip-archiver-packer', function(disabled) {
-        CommandHandler.IS_ZIP_ARCHIVER_PACKER_ENABLED_ = !disabled;
+      'enable-zip-archiver-packer', function(enabled) {
+        CommandHandler.IS_ZIP_ARCHIVER_PACKER_ENABLED_ = enabled;
       }.bind(this));
 };
 
diff --git a/ui/gfx/x/x11_types.cc b/ui/gfx/x/x11_types.cc
index 7540f8a..502589f 100644
--- a/ui/gfx/x/x11_types.cc
+++ b/ui/gfx/x/x11_types.cc
@@ -149,17 +149,17 @@
     for (int y = 0; y < data_height; ++y) {
       for (int x = 0; x < data_width; ++x) {
         const uint32_t pixel = *(bitmap_in++);
-        uint16_t out_pixel = ((pixel >> 8) & 0xf800) |
-                             ((pixel >> 5) & 0x07e0) |
-                             ((pixel >> 3) & 0x001f);
+        uint16_t out_pixel = ((pixel >> 8) & 0b1111100000000000) |
+                             ((pixel >> 5) & 0b0000011111100000) |
+                             ((pixel >> 3) & 0b0000000000011111);
         *(bitmap16++) = out_pixel;
       }
     }
 
     image.data = reinterpret_cast<char*>(orig_bitmap16);
-    image.red_mask = 0xf800;
-    image.green_mask = 0x07e0;
-    image.blue_mask = 0x001f;
+    image.red_mask = 0b1111100000000000;
+    image.green_mask = 0b0000011111100000;
+    image.blue_mask = 0b0000000000011111;
 
     XPutImage(display, pixmap, static_cast<GC>(pixmap_gc), &image,
               src_x, src_y, dst_x, dst_y,
diff --git a/ui/gl/gl_bindings.h b/ui/gl/gl_bindings.h
index 2fc96618..4e7c09b 100644
--- a/ui/gl/gl_bindings.h
+++ b/ui/gl/gl_bindings.h
@@ -99,6 +99,7 @@
 #define GL_ALPHA8_EXT                                    0x803C
 #define GL_LUMINANCE8_EXT                                0x8040
 #define GL_LUMINANCE8_ALPHA8_EXT                         0x8045
+#define GL_RGB10_A2_EXT                                  0x8059
 #define GL_RGBA32F_EXT                                   0x8814
 #define GL_RGB32F_EXT                                    0x8815
 #define GL_ALPHA32F_EXT                                  0x8816
@@ -106,13 +107,13 @@
 #define GL_LUMINANCE_ALPHA32F_EXT                        0x8819
 #define GL_RGBA16F_EXT                                   0x881A
 #define GL_RGB16F_EXT                                    0x881B
-#define GL_RG16F_EXT 0x822F
-#define GL_R16F_EXT 0x822D
+#define GL_RG16F_EXT                                     0x822F
+#define GL_R16F_EXT                                      0x822D
 #define GL_ALPHA16F_EXT                                  0x881C
 #define GL_LUMINANCE16F_EXT                              0x881E
 #define GL_LUMINANCE_ALPHA16F_EXT                        0x881F
-#define GL_R32F_EXT 0x822E
-#define GL_RG32F_EXT 0x8230
+#define GL_R32F_EXT                                      0x822E
+#define GL_RG32F_EXT                                     0x8230
 #define GL_BGRA8_EXT                                     0x93A1
 
 // GL_ANGLE_instanced_arrays
diff --git a/ui/gl/gl_image_io_surface.mm b/ui/gl/gl_image_io_surface.mm
index da406da..d2af129 100644
--- a/ui/gl/gl_image_io_surface.mm
+++ b/ui/gl/gl_image_io_surface.mm
@@ -18,6 +18,7 @@
 #include "ui/gfx/mac/io_surface.h"
 #include "ui/gl/gl_bindings.h"
 #include "ui/gl/gl_context.h"
+#include "ui/gl/gl_enums.h"
 #include "ui/gl/scoped_binders.h"
 #include "ui/gl/yuv_to_rgb_converter.h"
 
@@ -85,7 +86,7 @@
     case gfx::BufferFormat::RG_88:
       return GL_RG;
     case gfx::BufferFormat::BGRA_8888:
-    case gfx::BufferFormat::BGRX_8888:
+    case gfx::BufferFormat::BGRX_8888:  // See https://crbug.com/595948.
     case gfx::BufferFormat::RGBA_8888:
     case gfx::BufferFormat::RGBA_F16:
       return GL_RGBA;
@@ -93,8 +94,9 @@
     case gfx::BufferFormat::YUV_420_BIPLANAR:
       return GL_RGB_YCBCR_420V_CHROMIUM;
     case gfx::BufferFormat::BGRX_1010102:
-      // CGLTexImageIOSurface2D() (and OpenGL ES 3.0, for the case) support only
-      // GL_RGBA despite the hardware ignoring it.
+      // Technically we should use GL_RGB but CGLTexImageIOSurface2D() (and
+      // OpenGL ES 3.0, for the case) support only GL_RGBA (the hardware ignores
+      // the alpha channel anyway), see https://crbug.com/797347.
       return GL_RGBA;
     case gfx::BufferFormat::ATC:
     case gfx::BufferFormat::ATCIA:
@@ -123,7 +125,7 @@
       return GL_RG;
     case gfx::BufferFormat::BGRA_8888:
     case gfx::BufferFormat::BGRX_8888:
-    case gfx::BufferFormat::RGBA_8888:
+    case gfx::BufferFormat::RGBA_8888:  // See https://crbug.com/533677#c6.
     case gfx::BufferFormat::BGRX_1010102:
       return GL_BGRA;
     case gfx::BufferFormat::RGBA_F16:
@@ -140,7 +142,7 @@
     case gfx::BufferFormat::RGBX_8888:
     case gfx::BufferFormat::YVU_420:
     case gfx::BufferFormat::YUV_420_BIPLANAR:
-      NOTREACHED();
+      NOTREACHED() << gfx::BufferFormatToString(format);
       return 0;
   }
 
@@ -175,7 +177,7 @@
     case gfx::BufferFormat::RGBX_8888:
     case gfx::BufferFormat::YVU_420:
     case gfx::BufferFormat::YUV_420_BIPLANAR:
-      NOTREACHED();
+      NOTREACHED() << gfx::BufferFormatToString(format);
       return 0;
   }
 
@@ -219,7 +221,8 @@
   DCHECK(!io_surface_);
 
   if (!ValidInternalFormat(internalformat_)) {
-    LOG(ERROR) << "Invalid internalformat: " << internalformat_;
+    LOG(ERROR) << "Invalid internalformat: "
+               << GLEnums::GetStringEnum(internalformat_);
     return false;
   }
 
diff --git a/ui/gl/gl_image_io_surface_unittest.cc b/ui/gl/gl_image_io_surface_unittest.cc
index 1b7c837..6884e4d09 100644
--- a/ui/gl/gl_image_io_surface_unittest.cc
+++ b/ui/gl/gl_image_io_surface_unittest.cc
@@ -36,13 +36,27 @@
     IOSurfaceRef surface_ref = gfx::CreateIOSurface(size, format);
     IOReturn status = IOSurfaceLock(surface_ref, 0, nullptr);
     EXPECT_NE(status, kIOReturnCannotLock);
+
+    uint8_t corrected_color[4];
+    if (format == gfx::BufferFormat::RGBA_8888) {
+      // GL_RGBA is not supported by CGLTexImageIOSurface2D(), so we pretend it
+      // is GL_BGRA, (see https://crbug.com/533677) swizzle the channels for the
+      // purpose of this test.
+      corrected_color[0] = color[2];
+      corrected_color[1] = color[1];
+      corrected_color[2] = color[0];
+      corrected_color[3] = color[3];
+    } else {
+      memcpy(corrected_color, color, arraysize(corrected_color));
+    }
+
     for (size_t plane = 0; plane < NumberOfPlanesForBufferFormat(format);
          ++plane) {
       void* data = IOSurfaceGetBaseAddressOfPlane(surface_ref, plane);
       GLImageTestSupport::SetBufferDataToColor(
           size.width(), size.height(),
           IOSurfaceGetBytesPerRowOfPlane(surface_ref, plane), plane, format,
-          color, static_cast<uint8_t*>(data));
+          corrected_color, static_cast<uint8_t*>(data));
     }
     IOSurfaceUnlock(surface_ref, 0, nullptr);
 
@@ -65,6 +79,7 @@
 using GLImageTestTypes = testing::Types<
     GLImageIOSurfaceTestDelegate<gfx::BufferFormat::RGBA_8888>,
     GLImageIOSurfaceTestDelegate<gfx::BufferFormat::BGRA_8888>,
+    GLImageIOSurfaceTestDelegate<gfx::BufferFormat::BGRX_8888>,
     GLImageIOSurfaceTestDelegate<gfx::BufferFormat::RGBA_F16>,
     GLImageIOSurfaceTestDelegate<gfx::BufferFormat::YUV_420_BIPLANAR>,
     GLImageIOSurfaceTestDelegate<gfx::BufferFormat::BGRX_1010102>>;
@@ -74,6 +89,7 @@
 using GLImageRGBTestTypes = testing::Types<
     GLImageIOSurfaceTestDelegate<gfx::BufferFormat::RGBA_8888>,
     GLImageIOSurfaceTestDelegate<gfx::BufferFormat::BGRA_8888>,
+    GLImageIOSurfaceTestDelegate<gfx::BufferFormat::BGRX_8888>,
     GLImageIOSurfaceTestDelegate<gfx::BufferFormat::RGBA_F16>,
     GLImageIOSurfaceTestDelegate<gfx::BufferFormat::BGRX_1010102>>;
 
@@ -82,8 +98,10 @@
                               GLImageRGBTestTypes);
 
 using GLImageBindTestTypes = testing::Types<
-    // TODO(mcasas): enable BGRX_1010102 entry, https://crbug.com/803473.
-    GLImageIOSurfaceTestDelegate<gfx::BufferFormat::BGRA_8888>>;
+    // TODO(mcasas): enable BGRX_1010102, BGRX_8888, https://crbug.com/803473.
+    GLImageIOSurfaceTestDelegate<gfx::BufferFormat::BGRA_8888>,
+    GLImageIOSurfaceTestDelegate<gfx::BufferFormat::RGBA_8888>,
+    GLImageIOSurfaceTestDelegate<gfx::BufferFormat::RGBA_F16>>;
 
 INSTANTIATE_TYPED_TEST_CASE_P(GLImageIOSurface,
                               GLImageBindTest,
diff --git a/ui/gl/test/gl_image_test_support.cc b/ui/gl/test/gl_image_test_support.cc
index a1e1fca..675d383 100644
--- a/ui/gl/test/gl_image_test_support.cc
+++ b/ui/gl/test/gl_image_test_support.cc
@@ -6,6 +6,7 @@
 
 #include <vector>
 
+#include "ui/gfx/buffer_format_util.h"
 #include "ui/gfx/half_float.h"
 #include "ui/gl/init/gl_factory.h"
 #include "ui/gl/test/gl_surface_test_support.h"
@@ -218,7 +219,7 @@
     case gfx::BufferFormat::ETC1:
     case gfx::BufferFormat::RGBA_4444:
     case gfx::BufferFormat::UYVY_422:
-      NOTREACHED();
+      NOTREACHED() << gfx::BufferFormatToString(format);
       return;
   }
   NOTREACHED();
diff --git a/ui/keyboard/container_behavior.h b/ui/keyboard/container_behavior.h
index e6224c3..d641d88 100644
--- a/ui/keyboard/container_behavior.h
+++ b/ui/keyboard/container_behavior.h
@@ -60,9 +60,11 @@
   virtual bool IsDragHandle(const gfx::Vector2d& offset,
                             const gfx::Size& keyboard_size) const = 0;
 
-  virtual void SavePosition(const gfx::Point& position) = 0;
+  virtual void SavePosition(const gfx::Rect& keyboard_bounds,
+                            const gfx::Size& screen_size) = 0;
 
-  virtual void HandlePointerEvent(const ui::LocatedEvent& event) = 0;
+  virtual void HandlePointerEvent(const ui::LocatedEvent& event,
+                                  const gfx::Rect& display_bounds) = 0;
 
   virtual ContainerType GetType() const = 0;
 
diff --git a/ui/keyboard/container_floating_behavior.cc b/ui/keyboard/container_floating_behavior.cc
index 9d93d393..7939ecf 100644
--- a/ui/keyboard/container_floating_behavior.cc
+++ b/ui/keyboard/container_floating_behavior.cc
@@ -69,7 +69,7 @@
     const gfx::Rect& requested_bounds) {
   gfx::Rect keyboard_bounds = requested_bounds;
 
-  if (UseDefaultPosition()) {
+  if (!default_position_) {
     // If the keyboard hasn't been shown yet, ignore the request and use
     // default.
     gfx::Point default_location =
@@ -80,18 +80,49 @@
     // the screen.
     keyboard_bounds =
         ContainKeyboardToScreenBounds(keyboard_bounds, display_bounds);
+    SavePosition(keyboard_bounds, display_bounds.size());
   }
 
   return keyboard_bounds;
 }
 
+void ContainerFloatingBehavior::SavePosition(const gfx::Rect& keyboard_bounds,
+                                             const gfx::Size& screen_size) {
+  int left_distance = keyboard_bounds.x();
+  int right_distance = screen_size.width() - (keyboard_bounds.right());
+  int top_distance = keyboard_bounds.y();
+  int bottom_distance = screen_size.height() - (keyboard_bounds.bottom());
+
+  if (!default_position_) {
+    default_position_ = std::make_unique<KeyboardPosition>();
+  }
+
+  if (left_distance < right_distance) {
+    default_position_->horizontal_anchor_direction =
+        HorizontalAnchorDirection::LEFT;
+    default_position_->offset.set_x(left_distance);
+  } else {
+    default_position_->horizontal_anchor_direction =
+        HorizontalAnchorDirection::RIGHT;
+    default_position_->offset.set_x(right_distance);
+  }
+  if (top_distance < bottom_distance) {
+    default_position_->vertical_anchor_direction = VerticalAnchorDirection::TOP;
+    default_position_->offset.set_y(top_distance);
+  } else {
+    default_position_->vertical_anchor_direction =
+        VerticalAnchorDirection::BOTTOM;
+    default_position_->offset.set_y(bottom_distance);
+  }
+}
+
 gfx::Rect ContainerFloatingBehavior::ContainKeyboardToScreenBounds(
     const gfx::Rect& keyboard_bounds,
     const gfx::Rect& display_bounds) const {
   int left = keyboard_bounds.x();
   int top = keyboard_bounds.y();
-  int right = left + keyboard_bounds.width();
-  int bottom = top + keyboard_bounds.height();
+  int right = keyboard_bounds.right();
+  int bottom = keyboard_bounds.bottom();
 
   // Prevent keyboard from appearing off screen or overlapping with the edge.
   if (left < 0) {
@@ -118,37 +149,43 @@
   return false;
 }
 
-bool ContainerFloatingBehavior::UseDefaultPosition() const {
-  // (-1, -1) is used as a sentinel unset value.
-  return default_position_.x() == -1;
-}
-
 gfx::Point ContainerFloatingBehavior::GetPositionForShowingKeyboard(
     const gfx::Size& keyboard_size,
     const gfx::Rect& display_bounds) const {
   // Start with the last saved position
-  gfx::Point position = default_position_;
-  if (UseDefaultPosition()) {
+  gfx::Point top_left_offset;
+  KeyboardPosition* position = default_position_.get();
+  if (position == nullptr) {
     // If there is none, center the keyboard along the bottom of the screen.
-    position.set_x(display_bounds.width() - keyboard_size.width() -
-                   kDefaultDistanceFromScreenRight);
-    position.set_y(display_bounds.height() - keyboard_size.height() -
-                   kDefaultDistanceFromScreenBottom);
+    top_left_offset.set_x(display_bounds.width() - keyboard_size.width() -
+                          kDefaultDistanceFromScreenRight);
+    top_left_offset.set_y(display_bounds.height() - keyboard_size.height() -
+                          kDefaultDistanceFromScreenBottom);
+  } else {
+    if (position->horizontal_anchor_direction ==
+        HorizontalAnchorDirection::LEFT) {
+      top_left_offset.set_x(position->offset.x());
+    } else {
+      top_left_offset.set_x(display_bounds.width() - position->offset.x() -
+                            keyboard_size.width());
+    }
+    if (position->vertical_anchor_direction == VerticalAnchorDirection::TOP) {
+      top_left_offset.set_y(position->offset.y());
+    } else {
+      top_left_offset.set_y(display_bounds.height() - position->offset.y() -
+                            keyboard_size.height());
+    }
   }
 
   // Make sure that this location is valid according to the current size of the
   // screen.
-  gfx::Rect keyboard_bounds = gfx::Rect(position, keyboard_size);
+  gfx::Rect keyboard_bounds = gfx::Rect(top_left_offset, keyboard_size);
   gfx::Rect valid_keyboard_bounds =
       ContainKeyboardToScreenBounds(keyboard_bounds, display_bounds);
 
   return valid_keyboard_bounds.origin();
 }
 
-void ContainerFloatingBehavior::SavePosition(const gfx::Point& position) {
-  default_position_ = position;
-}
-
 bool ContainerFloatingBehavior::IsDragHandle(
     const gfx::Vector2d& offset,
     const gfx::Size& keyboard_size) const {
@@ -156,7 +193,8 @@
 }
 
 void ContainerFloatingBehavior::HandlePointerEvent(
-    const ui::LocatedEvent& event) {
+    const ui::LocatedEvent& event,
+    const gfx::Rect& display_bounds) {
   // Cannot call UI-backed operations without a KeyboardController
   DCHECK(controller_);
   auto kb_offset = gfx::Vector2d(event.x(), event.y());
@@ -205,7 +243,7 @@
     const gfx::Rect new_bounds =
         gfx::Rect(new_keyboard_location, keyboard_bounds.size());
     controller_->MoveKeyboard(new_bounds);
-    SavePosition(container->bounds().origin());
+    SavePosition(container->bounds(), display_bounds.size());
     handle_drag = true;
   }
   if (!handle_drag && drag_descriptor_) {
@@ -219,9 +257,10 @@
     const gfx::Rect& display_bounds) {
   gfx::Point keyboard_location =
       GetPositionForShowingKeyboard(container->bounds().size(), display_bounds);
-  SavePosition(keyboard_location);
-  container->SetBounds(
-      gfx::Rect(keyboard_location, container->bounds().size()));
+  gfx::Rect keyboard_bounds =
+      gfx::Rect(keyboard_location, container->bounds().size());
+  SavePosition(keyboard_bounds, display_bounds.size());
+  container->SetBounds(keyboard_bounds);
 }
 
 bool ContainerFloatingBehavior::TextBlurHidesKeyboard() const {
diff --git a/ui/keyboard/container_floating_behavior.h b/ui/keyboard/container_floating_behavior.h
index 89124dfa..6247b7d8 100644
--- a/ui/keyboard/container_floating_behavior.h
+++ b/ui/keyboard/container_floating_behavior.h
@@ -23,6 +23,25 @@
 constexpr int kDefaultDistanceFromScreenBottom = 20;
 constexpr int kDefaultDistanceFromScreenRight = 20;
 
+enum class HorizontalAnchorDirection {
+  LEFT,
+  RIGHT,
+};
+
+enum class VerticalAnchorDirection {
+  TOP,
+  BOTTOM,
+};
+
+struct KeyboardPosition {
+  // Whether the keyboard is anchored to the left or right side of the screen.
+  HorizontalAnchorDirection horizontal_anchor_direction;
+  // Whether the keyboard is anchored to the top or bottom side of the screen.
+  VerticalAnchorDirection vertical_anchor_direction;
+  // Distance from the sides of the screen that the keyboard is anchored to.
+  gfx::Point offset;
+};
+
 class KEYBOARD_EXPORT ContainerFloatingBehavior : public ContainerBehavior {
  public:
   ContainerFloatingBehavior(KeyboardController* controller);
@@ -42,8 +61,10 @@
   bool IsOverscrollAllowed() const override;
   bool IsDragHandle(const gfx::Vector2d& offset,
                     const gfx::Size& keyboard_size) const override;
-  void SavePosition(const gfx::Point& position) override;
-  void HandlePointerEvent(const ui::LocatedEvent& event) override;
+  void SavePosition(const gfx::Rect& keyboard_bounds,
+                    const gfx::Size& screen_size) override;
+  void HandlePointerEvent(const ui::LocatedEvent& event,
+                          const gfx::Rect& display_bounds) override;
   void SetCanonicalBounds(aura::Window* container,
                           const gfx::Rect& display_bounds) override;
   ContainerType GetType() const override;
@@ -52,6 +73,11 @@
   bool BoundsAffectWorkspaceLayout() const override;
   bool SetDraggableArea(const gfx::Rect& rect) override;
 
+  // Calculate the position of the keyboard for when it is being shown.
+  gfx::Point GetPositionForShowingKeyboard(
+      const gfx::Size& keyboard_size,
+      const gfx::Rect& display_bounds) const;
+
  private:
   // Ensures that the keyboard is neither off the screen nor overlapping an
   // edge.
@@ -62,19 +88,11 @@
   // Saves the current keyboard location for use the next time it is displayed.
   void UpdateLastPoint(const gfx::Point& position);
 
-  // Returns true if the keyboard has not been display/moved yet and the default
-  // position should be used.
-  bool UseDefaultPosition() const;
-
-  // Calculate the position of the keyboard for when it is being shown.
-  gfx::Point GetPositionForShowingKeyboard(
-      const gfx::Size& keyboard_size,
-      const gfx::Rect& display_bounds) const;
-
   KeyboardController* controller_;
 
   // TODO(blakeo): cache the default_position_ on a per-display basis.
-  gfx::Point default_position_ = gfx::Point(-1, -1);
+  std::unique_ptr<struct keyboard::KeyboardPosition> default_position_ =
+      nullptr;
 
   // Current state of a cursor drag to move the keyboard, if one exists.
   // Otherwise nullptr.
diff --git a/ui/keyboard/container_floating_behavior_unittest.cc b/ui/keyboard/container_floating_behavior_unittest.cc
index c3e81c7..b8421fa 100644
--- a/ui/keyboard/container_floating_behavior_unittest.cc
+++ b/ui/keyboard/container_floating_behavior_unittest.cc
@@ -32,7 +32,8 @@
                                  keyboard_height);
 
   // Save an arbitrary position so that default location will not be used.
-  floating_behavior.SavePosition(gfx::Point(0, 0));
+  floating_behavior.SavePosition(
+      gfx::Rect(0, 0, keyboard_width, keyboard_height), workspace.size());
 
   gfx::Rect result =
       floating_behavior.AdjustSetBoundsRequest(workspace, center);
@@ -49,6 +50,56 @@
             result);
 }
 
+TEST(ContainerFloatingBehaviorTest, AdjustSetBoundsRequestVariousSides) {
+  ContainerFloatingBehavior floating_behavior(nullptr);
+
+  const int keyboard_width = 100;
+  const int keyboard_height = 100;
+  gfx::Size keyboard_size = gfx::Size(keyboard_width, keyboard_height);
+  gfx::Rect workspace_wide(0, 0, 1000, 500);
+  gfx::Rect workspace_tall(0, 0, 500, 1000);
+  gfx::Rect top_left(0, 0, keyboard_width, keyboard_height);
+  gfx::Rect top_right(900, 0, keyboard_width, keyboard_height);
+  gfx::Rect bottom_left(0, 400, keyboard_width, keyboard_height);
+  gfx::Rect bottom_right(900, 400, keyboard_width, keyboard_height);
+
+  // Save an arbitrary position so that default location will not be used.
+  floating_behavior.SavePosition(
+      gfx::Rect(0, 0, keyboard_width, keyboard_height), workspace_wide.size());
+
+  floating_behavior.AdjustSetBoundsRequest(workspace_wide, top_left);
+  gfx::Point result = floating_behavior.GetPositionForShowingKeyboard(
+      keyboard_size, workspace_wide);
+  ASSERT_EQ(gfx::Point(0, 0), result);
+  result = floating_behavior.GetPositionForShowingKeyboard(keyboard_size,
+                                                           workspace_tall);
+  ASSERT_EQ(gfx::Point(0, 0), result);
+
+  floating_behavior.AdjustSetBoundsRequest(workspace_wide, top_right);
+  result = floating_behavior.GetPositionForShowingKeyboard(keyboard_size,
+                                                           workspace_wide);
+  ASSERT_EQ(gfx::Point(900, 0), result);
+  result = floating_behavior.GetPositionForShowingKeyboard(keyboard_size,
+                                                           workspace_tall);
+  ASSERT_EQ(gfx::Point(400, 0), result);
+
+  floating_behavior.AdjustSetBoundsRequest(workspace_wide, bottom_left);
+  result = floating_behavior.GetPositionForShowingKeyboard(keyboard_size,
+                                                           workspace_wide);
+  ASSERT_EQ(gfx::Point(0, 400), result);
+  result = floating_behavior.GetPositionForShowingKeyboard(keyboard_size,
+                                                           workspace_tall);
+  ASSERT_EQ(gfx::Point(0, 900), result);
+
+  floating_behavior.AdjustSetBoundsRequest(workspace_wide, bottom_right);
+  result = floating_behavior.GetPositionForShowingKeyboard(keyboard_size,
+                                                           workspace_wide);
+  ASSERT_EQ(gfx::Point(900, 400), result);
+  result = floating_behavior.GetPositionForShowingKeyboard(keyboard_size,
+                                                           workspace_tall);
+  ASSERT_EQ(gfx::Point(400, 900), result);
+}
+
 TEST(ContainerFloatingBehaviorTest, DontSaveCoordinatesUntilKeyboardMoved) {
   ContainerFloatingBehavior floating_behavior(nullptr);
 
@@ -77,7 +128,8 @@
   // Simulate the user clicking and moving the keyboard to some arbitrary
   // location (it doesn't matter where). Now that the coordinate is known to be
   // user-determined.
-  floating_behavior.SavePosition(gfx::Point(10, 10));
+  floating_behavior.SavePosition(
+      gfx::Rect(10, 10, keyboard_width, keyboard_height), workspace.size());
 
   // Move the keyboard somewhere else. The coordinates should be taken as-is
   // without being adjusted.
diff --git a/ui/keyboard/container_full_width_behavior.cc b/ui/keyboard/container_full_width_behavior.cc
index 15cbf04..2dca9c0 100644
--- a/ui/keyboard/container_full_width_behavior.cc
+++ b/ui/keyboard/container_full_width_behavior.cc
@@ -82,7 +82,8 @@
   return controller_ && !controller_->keyboard_locked();
 }
 
-void ContainerFullWidthBehavior::SavePosition(const gfx::Point& position) {
+void ContainerFullWidthBehavior::SavePosition(const gfx::Rect& keyboard_bounds,
+                                              const gfx::Size& screen_size) {
   // No-op. Nothing to save.
 }
 
@@ -93,7 +94,8 @@
 }
 
 void ContainerFullWidthBehavior::HandlePointerEvent(
-    const ui::LocatedEvent& event) {
+    const ui::LocatedEvent& event,
+    const gfx::Rect& display_bounds) {
   // No-op. Nothing special to do for pointer events.
 }
 
diff --git a/ui/keyboard/container_full_width_behavior.h b/ui/keyboard/container_full_width_behavior.h
index 5a5d1a4..077d3b9 100644
--- a/ui/keyboard/container_full_width_behavior.h
+++ b/ui/keyboard/container_full_width_behavior.h
@@ -39,8 +39,10 @@
   bool IsOverscrollAllowed() const override;
   bool IsDragHandle(const gfx::Vector2d& offset,
                     const gfx::Size& keyboard_size) const override;
-  void SavePosition(const gfx::Point& position) override;
-  void HandlePointerEvent(const ui::LocatedEvent& event) override;
+  void SavePosition(const gfx::Rect& keyboard_bounds,
+                    const gfx::Size& screen_size) override;
+  void HandlePointerEvent(const ui::LocatedEvent& event,
+                          const gfx::Rect& display_bounds) override;
   void SetCanonicalBounds(aura::Window* container,
                           const gfx::Rect& display_bounds) override;
   ContainerType GetType() const override;
diff --git a/ui/keyboard/keyboard_controller.cc b/ui/keyboard/keyboard_controller.cc
index 76a576b..67263cbc 100644
--- a/ui/keyboard/keyboard_controller.cc
+++ b/ui/keyboard/keyboard_controller.cc
@@ -737,7 +737,8 @@
 }
 
 void KeyboardController::HandlePointerEvent(const ui::LocatedEvent& event) {
-  container_behavior_->HandlePointerEvent(event);
+  container_behavior_->HandlePointerEvent(
+      event, container_->GetRootWindow()->bounds());
 }
 
 void KeyboardController::SetContainerType(const ContainerType type) {
diff --git a/ui/strings/ui_strings.grd b/ui/strings/ui_strings.grd
index a58dd60..15a885d3 100644
--- a/ui/strings/ui_strings.grd
+++ b/ui/strings/ui_strings.grd
@@ -719,12 +719,6 @@
       <message name="IDS_APP_LIST_FOLDER_CLOSE_FOLDER_ACCESSIBILE_NAME" desc="The spoken feedback text for closing an app launcher folder">
         Close folder
       </message>
-      <message name="IDS_APP_LIST_SPEECH_HINT_TEXT" desc="The text label in the speech recognition UI to ask the user to speak the search query">
-        Speak now
-      </message>
-      <message name="IDS_APP_LIST_SPEECH_NETWORK_ERROR_HINT_TEXT" desc="The text label in the speech recognition UI to show the speech recognition can't start because of network error.">
-        No internet connection
-      </message>
       <message name="IDS_APP_LIST_EXPAND_BUTTON" desc="Tooltip for the button that expands the app list from suggested apps to a fullscreen view which shows all apps.">
         Expand to all apps
       </message>
diff --git a/ui/views/controls/textfield/textfield.cc b/ui/views/controls/textfield/textfield.cc
index 7be7cbfa..67055d09 100644
--- a/ui/views/controls/textfield/textfield.cc
+++ b/ui/views/controls/textfield/textfield.cc
@@ -268,7 +268,6 @@
       background_color_(SK_ColorWHITE),
       selection_text_color_(SK_ColorWHITE),
       selection_background_color_(SK_ColorBLUE),
-      placeholder_text_color_(kDefaultPlaceholderTextColor),
       placeholder_text_draw_flags_(gfx::Canvas::DefaultCanvasTextAlignment()),
       invalid_(false),
       text_input_type_(ui::TEXT_INPUT_TYPE_TEXT),
@@ -2036,9 +2035,10 @@
         GetPlaceholderText(),
         placeholder_font_list_.has_value() ? placeholder_font_list_.value()
                                            : GetFontList(),
-        ui::MaterialDesignController::IsSecondaryUiMaterial()
-            ? SkColorSetA(GetTextColor(), 0x83)
-            : placeholder_text_color_,
+        placeholder_text_color_.value_or(
+            ui::MaterialDesignController::IsSecondaryUiMaterial()
+                ? SkColorSetA(GetTextColor(), 0x83)
+                : kDefaultPlaceholderTextColor),
         render_text->display_rect(), placeholder_text_draw_flags);
   }
 
diff --git a/ui/views/controls/textfield/textfield.h b/ui/views/controls/textfield/textfield.h
index 1c36080f..dc58e1f 100644
--- a/ui/views/controls/textfield/textfield.h
+++ b/ui/views/controls/textfield/textfield.h
@@ -488,8 +488,10 @@
   base::string16 placeholder_text_;
 
   // Placeholder text color.
-  // TODO(estade): remove this when Harmony/MD is default.
-  SkColor placeholder_text_color_;
+  // TODO(newcomer): Use NativeTheme to define different default placeholder
+  // text colors for chrome/CrOS when harmony is enabled by default
+  // (https://crbug.com/803279).
+  base::Optional<SkColor> placeholder_text_color_;
 
   // The draw flags specified for |placeholder_text_|.
   int placeholder_text_draw_flags_;