diff --git a/DEPS b/DEPS
index bdeef9c..32f03b7 100644
--- a/DEPS
+++ b/DEPS
@@ -91,7 +91,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ANGLE
   # and whatever else without interference from each other.
-  'angle_revision': '0b0dcbc1cffaa47fd225a9276c5cd4e48c2ca891',
+  'angle_revision': '41918387cc52553defbfc10ed30b504e628b6fe4',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling build tools
   # and whatever else without interference from each other.
@@ -103,7 +103,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
-  'pdfium_revision': '40c223e4ed41e991f81281ca08b3085e218c52dc',
+  'pdfium_revision': 'd1ffda2acaee90a7b8a6dd36e0605dce826058e9',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling openmax_dl
   # and whatever else without interference from each other.
@@ -135,7 +135,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling catapult
   # and whatever else without interference from each other.
-  'catapult_revision': '6c4a8ca2e9bc7d1d8fc526efe3c2e8ce087b730c',
+  'catapult_revision': '1446cf3fe8a3b827432365c3fdaf902d6bd033a7',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -206,7 +206,7 @@
   },
 
   'src/ios/third_party/material_components_ios/src': {
-      'url': Var('chromium_git') + '/external/github.com/material-components/material-components-ios.git' + '@' + '7d2e0214553aba8b5bb09fbe023df0f0dc48005a',
+      'url': Var('chromium_git') + '/external/github.com/material-components/material-components-ios.git' + '@' + 'dd21af4fef24ddb42d39e9610b84109273c50899',
       'condition': 'checkout_ios',
   },
 
@@ -397,7 +397,7 @@
   },
 
   'src/third_party/googletest/src':
-    Var('chromium_git') + '/external/github.com/google/googletest.git' + '@' + '703b4a85a21e394252560a89cc856b384b48c286',
+    Var('chromium_git') + '/external/github.com/google/googletest.git' + '@' + 'a325ad2db5deb623eab740527e559b81c0f39d65',
 
   # GNU binutils assembler for x86-32.
   'src/third_party/gnu_binutils': {
@@ -657,7 +657,7 @@
     Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + '3c1cb0203b6cfc10389e85a350b2ea6ca29d01ce',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + 'a12b1d625cc992de704b9947c4d11957ebfbc0f8', # commit position 21742
+    Var('webrtc_git') + '/src.git' + '@' + '853715c9a90611486aa191219a103a4acd7a664f', # commit position 21742
 
   'src/third_party/xdg-utils': {
       'url': Var('chromium_git') + '/chromium/deps/xdg-utils.git' + '@' + 'd80274d5869b17b8c9067a1022e4416ee7ed5e0d',
@@ -1004,7 +1004,7 @@
     ]
   },
  {
-    'name': 'content_shell_fonts',
+    'name': 'test_fonts',
     'pattern': '.',
     'condition': 'checkout_linux or (checkout_android or checkout_fuchsia)',
     'action': [ 'download_from_google_storage',
@@ -1012,7 +1012,7 @@
                 '--extract',
                 '--no_auth',
                 '--bucket', 'chromium-fonts',
-                '-s', 'src/third_party/content_shell_fonts/content_shell_test_fonts.tar.gz.sha1',
+                '-s', 'src/third_party/test_fonts/test_fonts.tar.gz.sha1',
     ],
   },
   # Pull order files for the win/clang build.
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsClientShouldInterceptRequestTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsClientShouldInterceptRequestTest.java
index c52deb4..17259197 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsClientShouldInterceptRequestTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsClientShouldInterceptRequestTest.java
@@ -21,7 +21,6 @@
 import org.chromium.android_webview.test.util.CommonResources;
 import org.chromium.android_webview.test.util.JSUtils;
 import org.chromium.base.test.util.CallbackHelper;
-import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.Feature;
 import org.chromium.base.test.util.TestFileUtil;
 import org.chromium.content.browser.test.util.TestCallbackHelperContainer.OnReceivedErrorHelper;
@@ -971,7 +970,6 @@
     @Test
     @SmallTest
     @Feature({"AndroidWebView"})
-    @DisabledTest // Enable when renderer-side navigation is removed. crbug.com/769126
     public void testLoadDataWithBaseUrlTriggersShouldInterceptRequest() throws Throwable {
         String data = "foo";
         String mimeType = "text/plain";
@@ -984,7 +982,7 @@
                 mContentsClient.getOnPageFinishedHelper(), data, mimeType, isBase64Encoded, baseUrl,
                 historyUrl);
         Assert.assertEquals(callCount + 1, mShouldInterceptRequestHelper.getCallCount());
-        // Not checking the URL yet. It's the empty data URL which should be fixed in
+        // TODO(boliu): Not checking the URL yet. It's the empty data URL which should be fixed in
         // crbug.com/669885.
     }
 
diff --git a/ash/accelerators/accelerator_controller.cc b/ash/accelerators/accelerator_controller.cc
index 7c898725..5d46ea4 100644
--- a/ash/accelerators/accelerator_controller.cc
+++ b/ash/accelerators/accelerator_controller.cc
@@ -508,7 +508,7 @@
       display::Screen::GetScreen()
           ->GetDisplayNearestWindow(Shell::GetRootWindowForNewWindows())
           .id(),
-      app_list::kSearchKey);
+      app_list::kSearchKey, accelerator.time_stamp());
 }
 
 void HandleToggleFullscreen(const ui::Accelerator& accelerator) {
diff --git a/ash/app_list/app_list_controller_impl.cc b/ash/app_list/app_list_controller_impl.cc
index 2422a61e..46059a28 100644
--- a/ash/app_list/app_list_controller_impl.cc
+++ b/ash/app_list/app_list_controller_impl.cc
@@ -250,7 +250,7 @@
 }
 
 void AppListControllerImpl::DismissAppList() {
-  presenter_.Dismiss();
+  presenter_.Dismiss(base::TimeTicks());
 }
 
 void AppListControllerImpl::GetAppInfoDialogBounds(
@@ -270,7 +270,7 @@
     // TODO(calamity): This may cause the app list to show briefly before the
     // state change. If this becomes an issue, add the ability to ash::Shell to
     // load the app list without showing it.
-    presenter_.Show(GetDisplayIdToShowAppListOn());
+    presenter_.Show(GetDisplayIdToShowAppListOn(), base::TimeTicks());
     app_list_was_open = false;
     app_list_view = presenter_.GetView();
     DCHECK(app_list_view);
@@ -285,7 +285,7 @@
 }
 
 void AppListControllerImpl::ShowAppList() {
-  presenter_.Show(GetDisplayIdToShowAppListOn());
+  presenter_.Show(GetDisplayIdToShowAppListOn(), base::TimeTicks());
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -318,10 +318,11 @@
 }
 
 void AppListControllerImpl::Show(int64_t display_id,
-                                 app_list::AppListShowSource show_source) {
+                                 app_list::AppListShowSource show_source,
+                                 base::TimeTicks event_time_stamp) {
   UMA_HISTOGRAM_ENUMERATION(app_list::kAppListToggleMethodHistogram,
                             show_source, app_list::kMaxAppListToggleMethod);
-  presenter_.Show(display_id);
+  presenter_.Show(display_id, event_time_stamp);
 }
 
 void AppListControllerImpl::UpdateYPositionAndOpacity(
@@ -343,12 +344,13 @@
 
 void AppListControllerImpl::ToggleAppList(
     int64_t display_id,
-    app_list::AppListShowSource show_source) {
+    app_list::AppListShowSource show_source,
+    base::TimeTicks event_time_stamp) {
   if (!IsVisible()) {
     UMA_HISTOGRAM_ENUMERATION(app_list::kAppListToggleMethodHistogram,
                               show_source, app_list::kMaxAppListToggleMethod);
   }
-  presenter_.ToggleAppList(display_id);
+  presenter_.ToggleAppList(display_id, event_time_stamp);
 }
 
 app_list::AppListViewState AppListControllerImpl::GetAppListViewState() {
diff --git a/ash/app_list/app_list_controller_impl.h b/ash/app_list/app_list_controller_impl.h
index efe3fc49..3f47f4a 100644
--- a/ash/app_list/app_list_controller_impl.h
+++ b/ash/app_list/app_list_controller_impl.h
@@ -101,13 +101,16 @@
   // Methods used in ash:
   bool GetTargetVisibility() const;
   bool IsVisible() const;
-  void Show(int64_t display_id, app_list::AppListShowSource show_source);
+  void Show(int64_t display_id,
+            app_list::AppListShowSource show_source,
+            base::TimeTicks event_time_stamp);
   void UpdateYPositionAndOpacity(int y_position_in_screen,
                                  float background_opacity);
   void EndDragFromShelf(app_list::AppListViewState app_list_state);
   void ProcessMouseWheelEvent(const ui::MouseWheelEvent& event);
   void ToggleAppList(int64_t display_id,
-                     app_list::AppListShowSource show_source);
+                     app_list::AppListShowSource show_source,
+                     base::TimeTicks event_time_stamp);
   app_list::AppListViewState GetAppListViewState();
 
   // Methods of |client_|:
diff --git a/ash/app_list/app_list_presenter_delegate.cc b/ash/app_list/app_list_presenter_delegate.cc
index f10d1b5..e167c53 100644
--- a/ash/app_list/app_list_presenter_delegate.cc
+++ b/ash/app_list/app_list_presenter_delegate.cc
@@ -198,7 +198,7 @@
   aura::Window* window = view_->GetWidget()->GetNativeView()->parent();
   if (!window->Contains(target) && !presenter_->Back() &&
       !app_list::switches::ShouldNotDismissOnBlur()) {
-    presenter_->Dismiss();
+    presenter_->Dismiss(event->time_stamp());
   }
 }
 
@@ -222,7 +222,7 @@
 // AppListPresenterDelegate, ShellObserver implementation:
 void AppListPresenterDelegate::OnOverviewModeStarting() {
   if (is_visible_)
-    presenter_->Dismiss();
+    presenter_->Dismiss(base::TimeTicks());
 }
 
 void AppListPresenterDelegate::OnTabletModeStarted() {
diff --git a/ash/app_list/app_list_presenter_impl.cc b/ash/app_list/app_list_presenter_impl.cc
index 587d601..6fb0716 100644
--- a/ash/app_list/app_list_presenter_impl.cc
+++ b/ash/app_list/app_list_presenter_impl.cc
@@ -13,6 +13,7 @@
 #include "base/metrics/user_metrics.h"
 #include "ui/app_list/app_list_constants.h"
 #include "ui/app_list/app_list_features.h"
+#include "ui/app_list/app_list_metrics.h"
 #include "ui/app_list/app_list_switches.h"
 #include "ui/app_list/app_list_view_delegate.h"
 #include "ui/app_list/pagination_model.h"
@@ -48,6 +49,25 @@
   DISALLOW_COPY_AND_ASSIGN(StateAnimationMetricsReporter);
 };
 
+// Callback from the compositor when it presented a valid frame. Used to
+// record UMA of input latency.
+void DidPresentCompositorFrame(base::TimeTicks event_time_stamp,
+                               bool is_showing,
+                               base::TimeTicks present_time,
+                               base::TimeDelta refresh,
+                               uint32_t flags) {
+  if (present_time.is_null() || event_time_stamp.is_null() ||
+      present_time < event_time_stamp) {
+    return;
+  }
+  const base::TimeDelta input_latency = present_time - event_time_stamp;
+  if (is_showing) {
+    UMA_HISTOGRAM_TIMES(kAppListShowInputLatencyHistogram, input_latency);
+  } else {
+    UMA_HISTOGRAM_TIMES(kAppListHideInputLatencyHistogram, input_latency);
+  }
+}
+
 }  // namespace
 
 AppListPresenterImpl::AppListPresenterImpl(
@@ -61,7 +81,7 @@
 }
 
 AppListPresenterImpl::~AppListPresenterImpl() {
-  Dismiss();
+  Dismiss(base::TimeTicks());
   presenter_delegate_.reset();
   // Ensures app list view goes before the controller since pagination model
   // lives in the controller and app list view would access it on destruction.
@@ -76,14 +96,16 @@
   return is_visible_ && view_ ? view_->GetWidget()->GetNativeWindow() : nullptr;
 }
 
-void AppListPresenterImpl::Show(int64_t display_id) {
+void AppListPresenterImpl::Show(int64_t display_id,
+                                base::TimeTicks event_time_stamp) {
   if (is_visible_) {
     if (display_id != GetDisplayId())
-      Dismiss();
+      Dismiss(event_time_stamp);
     return;
   }
 
   is_visible_ = true;
+  RequestPresentationTime(display_id, event_time_stamp);
   NotifyTargetVisibilityChanged(GetTargetVisibility());
   NotifyVisibilityChanged(GetTargetVisibility(), display_id);
 
@@ -103,7 +125,7 @@
   view_delegate_->ViewShown(display_id);
 }
 
-void AppListPresenterImpl::Dismiss() {
+void AppListPresenterImpl::Dismiss(base::TimeTicks event_time_stamp) {
   if (!is_visible_)
     return;
 
@@ -111,8 +133,10 @@
   DCHECK(view_);
 
   is_visible_ = false;
+  const int64_t display_id = GetDisplayId();
+  RequestPresentationTime(display_id, event_time_stamp);
   NotifyTargetVisibilityChanged(GetTargetVisibility());
-  NotifyVisibilityChanged(GetTargetVisibility(), GetDisplayId());
+  NotifyVisibilityChanged(GetTargetVisibility(), display_id);
   // The dismissal may have occurred in response to the app list losing
   // activation. Otherwise, our widget is currently active. When the animation
   // completes we'll hide the widget, changing activation. If a menu is shown
@@ -138,12 +162,13 @@
   return view_->app_list_main_view()->contents_view()->Back();
 }
 
-void AppListPresenterImpl::ToggleAppList(int64_t display_id) {
+void AppListPresenterImpl::ToggleAppList(int64_t display_id,
+                                         base::TimeTicks event_time_stamp) {
   if (IsVisible()) {
-    Dismiss();
+    Dismiss(event_time_stamp);
     return;
   }
-  Show(display_id);
+  Show(display_id, event_time_stamp);
 }
 
 bool AppListPresenterImpl::IsVisible() const {
@@ -290,7 +315,7 @@
     if (applist_container->Contains(lost_focus) &&
         (!gained_focus || !applist_container->Contains(gained_focus)) &&
         !switches::ShouldNotDismissOnBlur()) {
-      Dismiss();
+      Dismiss(base::TimeTicks());
     }
   }
 }
@@ -311,7 +336,7 @@
 void AppListPresenterImpl::OnWidgetDestroying(views::Widget* widget) {
   DCHECK_EQ(view_->GetWidget(), widget);
   if (is_visible_)
-    Dismiss();
+    Dismiss(base::TimeTicks());
   ResetView();
 }
 
@@ -337,4 +362,20 @@
 
 void AppListPresenterImpl::TransitionEnded() {}
 
+void AppListPresenterImpl::RequestPresentationTime(
+    int64_t display_id,
+    base::TimeTicks event_time_stamp) {
+  if (event_time_stamp.is_null())
+    return;
+  aura::Window* root_window =
+      ash::Shell::Get()->GetRootWindowForDisplayId(display_id);
+  if (!root_window)
+    return;
+  ui::Compositor* compositor = root_window->layer()->GetCompositor();
+  if (!compositor)
+    return;
+  compositor->RequestPresentationTimeForNextFrame(base::BindOnce(
+      &DidPresentCompositorFrame, event_time_stamp, is_visible_));
+}
+
 }  // namespace app_list
diff --git a/ash/app_list/app_list_presenter_impl.h b/ash/app_list/app_list_presenter_impl.h
index 78bfcc2..2c48395 100644
--- a/ash/app_list/app_list_presenter_impl.h
+++ b/ash/app_list/app_list_presenter_impl.h
@@ -62,18 +62,24 @@
   // Returns app list view if one exists, or NULL otherwise.
   AppListView* GetView() { return view_; }
 
-  // Show the app list window on the display with the given id.
-  void Show(int64_t display_id);
+  // Show the app list window on the display with the given id. If
+  // |event_time_stamp| is not 0, it means |Show()| was triggered by one of the
+  // AppListShowSources: kSearchKey, kShelfButton, or kSwipeFromShelf.
+  void Show(int64_t display_id, base::TimeTicks event_time_stamp);
 
   // Hide the open app list window. This may leave the view open but hidden.
-  void Dismiss();
+  // If |event_time_stamp| is not 0, it means |Dismiss()| was triggered by
+  // one AppListShowSource or focusing out side of the launcher.
+  void Dismiss(base::TimeTicks event_time_stamp);
 
   // Performs the 'back' action for the active page. Returns whether the action
   // was handled.
   bool Back();
 
-  // Show the app list if it is visible, hide it if it is hidden.
-  void ToggleAppList(int64_t display_id);
+  // Show the app list if it is visible, hide it if it is hidden. If
+  // |event_time_stamp| is not 0, it means |ToggleAppList()| was triggered by
+  // one of the AppListShowSources: kSearchKey or kShelfButton.
+  void ToggleAppList(int64_t display_id, base::TimeTicks event_time_stamp);
 
   // Returns current visibility of the app list.
   bool IsVisible() const;
@@ -129,6 +135,11 @@
   void TransitionChanged() override;
   void TransitionEnded() override;
 
+  // Registers a callback that is run when the next frame successfully makes it
+  // to the screen.
+  void RequestPresentationTime(int64_t display_id,
+                               base::TimeTicks event_time_stamp);
+
   // The factory for the presenter's delegate.
   std::unique_ptr<AppListPresenterDelegateFactory> factory_;
 
diff --git a/ash/app_list/app_list_view_delegate_mash.cc b/ash/app_list/app_list_view_delegate_mash.cc
index 3988748..34e3aa79 100644
--- a/ash/app_list/app_list_view_delegate_mash.cc
+++ b/ash/app_list/app_list_view_delegate_mash.cc
@@ -49,7 +49,7 @@
 }
 
 void AppListViewDelegateMash::Dismiss() {
-  owner_->presenter()->Dismiss();
+  owner_->presenter()->Dismiss(base::TimeTicks());
 }
 
 void AppListViewDelegateMash::ViewClosing() {
diff --git a/ash/app_list/presenter/app_list_presenter_impl_unittest.cc b/ash/app_list/presenter/app_list_presenter_impl_unittest.cc
index ae22192..0f3b397 100644
--- a/ash/app_list/presenter/app_list_presenter_impl_unittest.cc
+++ b/ash/app_list/presenter/app_list_presenter_impl_unittest.cc
@@ -156,7 +156,7 @@
 
   aura::client::FocusClient* focus_client =
       aura::client::GetFocusClient(root_window());
-  presenter()->Show(GetDisplayId());
+  presenter()->Show(GetDisplayId(), base::TimeTicks());
   EXPECT_TRUE(delegate()->init_called());
   EXPECT_TRUE(delegate()->on_shown_called());
   EXPECT_FALSE(delegate()->on_dismissed_called());
@@ -182,7 +182,7 @@
 
   aura::client::FocusClient* focus_client =
       aura::client::GetFocusClient(root_window());
-  presenter()->Show(GetDisplayId());
+  presenter()->Show(GetDisplayId(), base::TimeTicks());
   focus_client->FocusWindow(presenter()->GetWindow());
   EXPECT_TRUE(presenter()->GetTargetVisibility());
   EXPECT_TRUE(delegate()->init_called());
@@ -206,7 +206,7 @@
   if (features::IsFullscreenAppListEnabled())
     return;
 
-  presenter()->Show(GetDisplayId());
+  presenter()->Show(GetDisplayId(), base::TimeTicks());
   EXPECT_TRUE(presenter()->GetTargetVisibility());
   presenter()->GetView()->GetWidget()->CloseNow();
   EXPECT_FALSE(presenter()->GetTargetVisibility());
diff --git a/ash/app_list/test/app_list_test_helper.cc b/ash/app_list/test/app_list_test_helper.cc
index 13e723b..c78f109b5 100644
--- a/ash/app_list/test/app_list_test_helper.cc
+++ b/ash/app_list/test/app_list_test_helper.cc
@@ -40,7 +40,7 @@
 void AppListTestHelper::ShowAndRunLoop(
     uint64_t display_id,
     app_list::AppListShowSource show_source) {
-  app_list_controller_->Show(display_id, show_source);
+  app_list_controller_->Show(display_id, show_source, base::TimeTicks());
   WaitUntilIdle();
 }
 
@@ -56,7 +56,8 @@
 void AppListTestHelper::ToggleAndRunLoop(
     uint64_t display_id,
     app_list::AppListShowSource show_source) {
-  app_list_controller_->ToggleAppList(display_id, show_source);
+  app_list_controller_->ToggleAppList(display_id, show_source,
+                                      base::TimeTicks());
   WaitUntilIdle();
 }
 
diff --git a/ash/components/shortcut_viewer/vector_icons/ksv_arrow_down.1x.icon b/ash/components/shortcut_viewer/vector_icons/ksv_arrow_down.1x.icon
index ed82bb8..968f1d2 100644
--- a/ash/components/shortcut_viewer/vector_icons/ksv_arrow_down.1x.icon
+++ b/ash/components/shortcut_viewer/vector_icons/ksv_arrow_down.1x.icon
@@ -9,5 +9,4 @@
 R_LINE_TO, 4.45f, 4.41f,
 LINE_TO, 12.45f, 5,
 LINE_TO, 13.5f, 6.04f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/components/shortcut_viewer/vector_icons/ksv_arrow_down.icon b/ash/components/shortcut_viewer/vector_icons/ksv_arrow_down.icon
index 673d57c..1fddea3 100644
--- a/ash/components/shortcut_viewer/vector_icons/ksv_arrow_down.icon
+++ b/ash/components/shortcut_viewer/vector_icons/ksv_arrow_down.icon
@@ -9,5 +9,4 @@
 R_LINE_TO, 8.9f, 8.82f,
 LINE_TO, 24.9f, 10,
 LINE_TO, 27, 12.09f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/components/shortcut_viewer/vector_icons/ksv_arrow_left.1x.icon b/ash/components/shortcut_viewer/vector_icons/ksv_arrow_left.1x.icon
index 5271a7f..d2cadf7b 100644
--- a/ash/components/shortcut_viewer/vector_icons/ksv_arrow_left.1x.icon
+++ b/ash/components/shortcut_viewer/vector_icons/ksv_arrow_left.1x.icon
@@ -9,5 +9,4 @@
 R_LINE_TO, -4.41f, -4.45f,
 R_LINE_TO, 4.41f, -4.45f,
 R_LINE_TO, -1.04f, -1.05f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/components/shortcut_viewer/vector_icons/ksv_arrow_left.icon b/ash/components/shortcut_viewer/vector_icons/ksv_arrow_left.icon
index a5c0ad1..1f88f2f 100644
--- a/ash/components/shortcut_viewer/vector_icons/ksv_arrow_left.icon
+++ b/ash/components/shortcut_viewer/vector_icons/ksv_arrow_left.icon
@@ -9,5 +9,4 @@
 R_LINE_TO, -8.82f, -8.9f,
 LINE_TO, 22.5f, 7.6f,
 LINE_TO, 20.41f, 5.5f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/components/shortcut_viewer/vector_icons/ksv_arrow_right.1x.icon b/ash/components/shortcut_viewer/vector_icons/ksv_arrow_right.1x.icon
index 69819d7..ca0cacf 100644
--- a/ash/components/shortcut_viewer/vector_icons/ksv_arrow_right.1x.icon
+++ b/ash/components/shortcut_viewer/vector_icons/ksv_arrow_right.1x.icon
@@ -9,5 +9,4 @@
 R_LINE_TO, 4.41f, -4.45f,
 LINE_TO, 4.75f, 3.8f,
 LINE_TO, 5.79f, 2.75f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/components/shortcut_viewer/vector_icons/ksv_arrow_right.icon b/ash/components/shortcut_viewer/vector_icons/ksv_arrow_right.icon
index dd17694..e86867b 100644
--- a/ash/components/shortcut_viewer/vector_icons/ksv_arrow_right.icon
+++ b/ash/components/shortcut_viewer/vector_icons/ksv_arrow_right.icon
@@ -9,5 +9,4 @@
 R_LINE_TO, 8.82f, -8.9f,
 LINE_TO, 9.5f, 7.6f,
 LINE_TO, 11.59f, 5.5f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/components/shortcut_viewer/vector_icons/ksv_arrow_up.1x.icon b/ash/components/shortcut_viewer/vector_icons/ksv_arrow_up.1x.icon
index d4b3fb4..0016c7f 100644
--- a/ash/components/shortcut_viewer/vector_icons/ksv_arrow_up.1x.icon
+++ b/ash/components/shortcut_viewer/vector_icons/ksv_arrow_up.1x.icon
@@ -9,5 +9,4 @@
 R_LINE_TO, 4.45f, -4.41f,
 R_LINE_TO, 4.45f, 4.41f,
 R_LINE_TO, 1.05f, -1.04f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/components/shortcut_viewer/vector_icons/ksv_arrow_up.icon b/ash/components/shortcut_viewer/vector_icons/ksv_arrow_up.icon
index f8c9a72..1d6cffc 100644
--- a/ash/components/shortcut_viewer/vector_icons/ksv_arrow_up.icon
+++ b/ash/components/shortcut_viewer/vector_icons/ksv_arrow_up.icon
@@ -9,5 +9,4 @@
 R_LINE_TO, 8.9f, -8.82f,
 LINE_TO, 24.9f, 23,
 LINE_TO, 27, 20.91f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/components/shortcut_viewer/vector_icons/ksv_brightness_down.1x.icon b/ash/components/shortcut_viewer/vector_icons/ksv_brightness_down.1x.icon
index 0a52101..fb9ebec 100644
--- a/ash/components/shortcut_viewer/vector_icons/ksv_brightness_down.1x.icon
+++ b/ash/components/shortcut_viewer/vector_icons/ksv_brightness_down.1x.icon
@@ -26,5 +26,4 @@
 LINE_TO, 10.68f, 9.06f,
 LINE_TO, 11.82f, 7.91f,
 LINE_TO, 10.68f, 6.76f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/components/shortcut_viewer/vector_icons/ksv_brightness_down.icon b/ash/components/shortcut_viewer/vector_icons/ksv_brightness_down.icon
index 788987e67..8d42331 100644
--- a/ash/components/shortcut_viewer/vector_icons/ksv_brightness_down.icon
+++ b/ash/components/shortcut_viewer/vector_icons/ksv_brightness_down.icon
@@ -26,5 +26,4 @@
 LINE_TO, 21.35f, 18.11f,
 LINE_TO, 23.64f, 15.82f,
 LINE_TO, 21.35f, 13.53f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/components/shortcut_viewer/vector_icons/ksv_brightness_up.1x.icon b/ash/components/shortcut_viewer/vector_icons/ksv_brightness_up.1x.icon
index 0a06d200..6e4c72e 100644
--- a/ash/components/shortcut_viewer/vector_icons/ksv_brightness_up.1x.icon
+++ b/ash/components/shortcut_viewer/vector_icons/ksv_brightness_up.1x.icon
@@ -26,5 +26,4 @@
 R_V_LINE_TO, -2.22f,
 R_LINE_TO, 1.57f, -1.57f,
 R_LINE_TO, -1.57f, -1.57f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/components/shortcut_viewer/vector_icons/ksv_brightness_up.icon b/ash/components/shortcut_viewer/vector_icons/ksv_brightness_up.icon
index 87fbd256..6e3dcf7f 100644
--- a/ash/components/shortcut_viewer/vector_icons/ksv_brightness_up.icon
+++ b/ash/components/shortcut_viewer/vector_icons/ksv_brightness_up.icon
@@ -26,5 +26,4 @@
 R_V_LINE_TO, -4.44f,
 R_LINE_TO, 3.14f, -3.14f,
 R_LINE_TO, -3.14f, -3.14f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/components/shortcut_viewer/vector_icons/ksv_browser_back.1x.icon b/ash/components/shortcut_viewer/vector_icons/ksv_browser_back.1x.icon
index 86935b03f..b902618 100644
--- a/ash/components/shortcut_viewer/vector_icons/ksv_browser_back.1x.icon
+++ b/ash/components/shortcut_viewer/vector_icons/ksv_browser_back.1x.icon
@@ -12,5 +12,4 @@
 V_LINE_TO, 7.45f,
 H_LINE_TO, 6.07f,
 R_LINE_TO, 2.84f, -2.81f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/components/shortcut_viewer/vector_icons/ksv_browser_back.icon b/ash/components/shortcut_viewer/vector_icons/ksv_browser_back.icon
index ce6926a..7d3990b 100644
--- a/ash/components/shortcut_viewer/vector_icons/ksv_browser_back.icon
+++ b/ash/components/shortcut_viewer/vector_icons/ksv_browser_back.icon
@@ -12,5 +12,4 @@
 R_V_LINE_TO, -3.21f,
 H_LINE_TO, 12.13f,
 R_LINE_TO, 5.67f, -5.62f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/components/shortcut_viewer/vector_icons/ksv_browser_forward.1x.icon b/ash/components/shortcut_viewer/vector_icons/ksv_browser_forward.1x.icon
index 4e5bded..d2ea6609 100644
--- a/ash/components/shortcut_viewer/vector_icons/ksv_browser_forward.1x.icon
+++ b/ash/components/shortcut_viewer/vector_icons/ksv_browser_forward.1x.icon
@@ -12,5 +12,4 @@
 V_LINE_TO, 7.45f,
 R_H_LINE_TO, 6.93f,
 LINE_TO, 7.1f, 4.64f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/components/shortcut_viewer/vector_icons/ksv_browser_forward.icon b/ash/components/shortcut_viewer/vector_icons/ksv_browser_forward.icon
index a893357..92e1c712 100644
--- a/ash/components/shortcut_viewer/vector_icons/ksv_browser_forward.icon
+++ b/ash/components/shortcut_viewer/vector_icons/ksv_browser_forward.icon
@@ -12,5 +12,4 @@
 R_V_LINE_TO, -3.21f,
 R_H_LINE_TO, 13.87f,
 LINE_TO, 14.2f, 9.27f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/components/shortcut_viewer/vector_icons/ksv_fullscreen.1x.icon b/ash/components/shortcut_viewer/vector_icons/ksv_fullscreen.1x.icon
index 5d536489..5e2ac30 100644
--- a/ash/components/shortcut_viewer/vector_icons/ksv_fullscreen.1x.icon
+++ b/ash/components/shortcut_viewer/vector_icons/ksv_fullscreen.1x.icon
@@ -34,5 +34,4 @@
 H_LINE_TO, 13,
 V_LINE_TO, 9.35f,
 R_H_LINE_TO, -1.32f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/components/shortcut_viewer/vector_icons/ksv_fullscreen.icon b/ash/components/shortcut_viewer/vector_icons/ksv_fullscreen.icon
index 0555eb276..f2c9b0db 100644
--- a/ash/components/shortcut_viewer/vector_icons/ksv_fullscreen.icon
+++ b/ash/components/shortcut_viewer/vector_icons/ksv_fullscreen.icon
@@ -34,5 +34,4 @@
 R_H_LINE_TO, 8.23f,
 R_V_LINE_TO, -6.3f,
 R_H_LINE_TO, -2.64f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/components/shortcut_viewer/vector_icons/ksv_mute.1x.icon b/ash/components/shortcut_viewer/vector_icons/ksv_mute.1x.icon
index 59033b2..0305760 100644
--- a/ash/components/shortcut_viewer/vector_icons/ksv_mute.1x.icon
+++ b/ash/components/shortcut_viewer/vector_icons/ksv_mute.1x.icon
@@ -38,5 +38,4 @@
 LINE_TO, 9.11f, 6.99f,
 LINE_TO, 10.47f, 8.35f,
 CUBIC_TO, 10.49f, 8.24f, 10.5f, 8.12f, 10.5f, 8,
-CLOSE,
-END
+CLOSE
diff --git a/ash/components/shortcut_viewer/vector_icons/ksv_mute.icon b/ash/components/shortcut_viewer/vector_icons/ksv_mute.icon
index f57a16c..2d4d688 100644
--- a/ash/components/shortcut_viewer/vector_icons/ksv_mute.icon
+++ b/ash/components/shortcut_viewer/vector_icons/ksv_mute.icon
@@ -38,5 +38,4 @@
 LINE_TO, 18.22f, 13.98f,
 LINE_TO, 20.94f, 16.7f,
 CUBIC_TO, 20.98f, 16.48f, 21, 16.25f, 21, 16,
-CLOSE,
-END
+CLOSE
diff --git a/ash/components/shortcut_viewer/vector_icons/ksv_overview.1x.icon b/ash/components/shortcut_viewer/vector_icons/ksv_overview.1x.icon
index b0254a4..c2f4f72 100644
--- a/ash/components/shortcut_viewer/vector_icons/ksv_overview.1x.icon
+++ b/ash/components/shortcut_viewer/vector_icons/ksv_overview.1x.icon
@@ -24,5 +24,4 @@
 R_H_LINE_TO, 1,
 R_V_LINE_TO, -7,
 R_H_LINE_TO, -1,
-CLOSE,
-END
+CLOSE
diff --git a/ash/components/shortcut_viewer/vector_icons/ksv_overview.icon b/ash/components/shortcut_viewer/vector_icons/ksv_overview.icon
index d5b942a..a810a00 100644
--- a/ash/components/shortcut_viewer/vector_icons/ksv_overview.icon
+++ b/ash/components/shortcut_viewer/vector_icons/ksv_overview.icon
@@ -24,5 +24,4 @@
 R_H_LINE_TO, 2,
 V_LINE_TO, 9,
 R_H_LINE_TO, -2,
-CLOSE,
-END
+CLOSE
diff --git a/ash/components/shortcut_viewer/vector_icons/ksv_reload.1x.icon b/ash/components/shortcut_viewer/vector_icons/ksv_reload.1x.icon
index 97f9d9f..392be2a8 100644
--- a/ash/components/shortcut_viewer/vector_icons/ksv_reload.1x.icon
+++ b/ash/components/shortcut_viewer/vector_icons/ksv_reload.1x.icon
@@ -20,6 +20,5 @@
 CUBIC_TO, 8.96f, 4.42f, 9.9f, 4.89f, 10.54f, 5.65f,
 LINE_TO, 8.92f, 7.27f,
 LINE_TO, 13.19f, 7.27f,
-CLOSE,
-END
+CLOSE
 
diff --git a/ash/components/shortcut_viewer/vector_icons/ksv_reload.icon b/ash/components/shortcut_viewer/vector_icons/ksv_reload.icon
index ce946af..1d62433a 100644
--- a/ash/components/shortcut_viewer/vector_icons/ksv_reload.icon
+++ b/ash/components/shortcut_viewer/vector_icons/ksv_reload.icon
@@ -20,5 +20,4 @@
 CUBIC_TO, 17.91f, 8.84f, 19.79f, 9.78f, 21.07f, 11.3f,
 LINE_TO, 17.84f, 14.53f,
 LINE_TO, 26.37f, 14.53f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/components/shortcut_viewer/vector_icons/ksv_search_back.1x.icon b/ash/components/shortcut_viewer/vector_icons/ksv_search_back.1x.icon
index 2ebd257..b2c2931a 100644
--- a/ash/components/shortcut_viewer/vector_icons/ksv_search_back.1x.icon
+++ b/ash/components/shortcut_viewer/vector_icons/ksv_search_back.1x.icon
@@ -12,5 +12,4 @@
 R_LINE_TO, 1.15f, -1.15f,
 LINE_TO, 6.45f, 10.5f,
 H_LINE_TO, 16,
-CLOSE,
-END
+CLOSE
diff --git a/ash/components/shortcut_viewer/vector_icons/ksv_search_back.icon b/ash/components/shortcut_viewer/vector_icons/ksv_search_back.icon
index b501e4a..33f08fa5 100644
--- a/ash/components/shortcut_viewer/vector_icons/ksv_search_back.icon
+++ b/ash/components/shortcut_viewer/vector_icons/ksv_search_back.icon
@@ -12,5 +12,4 @@
 R_LINE_TO, 2.3f, -2.3f,
 LINE_TO, 12.89f, 21,
 H_LINE_TO, 33,
-CLOSE,
-END
+CLOSE
diff --git a/ash/components/shortcut_viewer/vector_icons/ksv_search_bar.1x.icon b/ash/components/shortcut_viewer/vector_icons/ksv_search_bar.1x.icon
index eef7777..3b4cd225 100644
--- a/ash/components/shortcut_viewer/vector_icons/ksv_search_bar.1x.icon
+++ b/ash/components/shortcut_viewer/vector_icons/ksv_search_bar.1x.icon
@@ -20,5 +20,4 @@
 R_ARC_TO, 3.75f, 3.75f, 0, 0, 1, 3.75f, -3.75f,
 R_ARC_TO, 3.75f, 3.75f, 0, 0, 1, 3.75f, 3.75f,
 R_ARC_TO, 3.75f, 3.75f, 0, 0, 1, -3.75f, 3.75f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/components/shortcut_viewer/vector_icons/ksv_search_bar.icon b/ash/components/shortcut_viewer/vector_icons/ksv_search_bar.icon
index 62361a2..5988315 100644
--- a/ash/components/shortcut_viewer/vector_icons/ksv_search_bar.icon
+++ b/ash/components/shortcut_viewer/vector_icons/ksv_search_bar.icon
@@ -22,5 +22,4 @@
 R_CUBIC_TO, 0, -4.15f, 3.35f, -7.5f, 7.5f, -7.5f,
 R_CUBIC_TO, 4.15f, 0, 7.5f, 3.35f, 7.5f, 7.5f,
 R_CUBIC_TO, 0, 4.15f, -3.35f, 7.5f, -7.5f, 7.5f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/components/shortcut_viewer/vector_icons/ksv_search_close.1x.icon b/ash/components/shortcut_viewer/vector_icons/ksv_search_close.1x.icon
index e7f3f225..db1d582 100644
--- a/ash/components/shortcut_viewer/vector_icons/ksv_search_close.1x.icon
+++ b/ash/components/shortcut_viewer/vector_icons/ksv_search_close.1x.icon
@@ -22,5 +22,4 @@
 R_LINE_TO, 0.79f, -0.79f,
 R_LINE_TO, -3.1f, -3.1f,
 R_LINE_TO, 3.1f, -3.1f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/components/shortcut_viewer/vector_icons/ksv_search_close.icon b/ash/components/shortcut_viewer/vector_icons/ksv_search_close.icon
index 411555e4..340b406 100644
--- a/ash/components/shortcut_viewer/vector_icons/ksv_search_close.icon
+++ b/ash/components/shortcut_viewer/vector_icons/ksv_search_close.icon
@@ -22,5 +22,4 @@
 R_LINE_TO, 1.57f, -1.57f,
 R_LINE_TO, -6.21f, -6.2f,
 R_LINE_TO, 6.21f, -6.21f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/components/shortcut_viewer/vector_icons/ksv_search_no_result.1x.icon b/ash/components/shortcut_viewer/vector_icons/ksv_search_no_result.1x.icon
index 5a587c3..2d5b56b6 100644
--- a/ash/components/shortcut_viewer/vector_icons/ksv_search_no_result.1x.icon
+++ b/ash/components/shortcut_viewer/vector_icons/ksv_search_no_result.1x.icon
@@ -57,5 +57,4 @@
 R_CUBIC_TO, 0, -5.59f, 4.54f, -10.12f, 10.14f, -10.12f,
 R_CUBIC_TO, 5.6f, 0, 10.14f, 4.53f, 10.14f, 10.13f,
 R_CUBIC_TO, 0, 5.6f, -4.54f, 10.13f, -10.14f, 10.13f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/components/shortcut_viewer/vector_icons/ksv_search_no_result.icon b/ash/components/shortcut_viewer/vector_icons/ksv_search_no_result.icon
index 7cb0b2f..d0578a3 100644
--- a/ash/components/shortcut_viewer/vector_icons/ksv_search_no_result.icon
+++ b/ash/components/shortcut_viewer/vector_icons/ksv_search_no_result.icon
@@ -58,5 +58,4 @@
 R_CUBIC_TO, 0, -11.18f, 9.08f, -20.25f, 20.28f, -20.25f,
 R_CUBIC_TO, 11.2f, 0, 20.28f, 9.07f, 20.28f, 20.25f,
 R_CUBIC_TO, 0, 11.18f, -9.08f, 20.25f, -20.28f, 20.25f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/components/shortcut_viewer/vector_icons/ksv_separator_plus.1x.icon b/ash/components/shortcut_viewer/vector_icons/ksv_separator_plus.1x.icon
index 1cb0f87..1882cfb 100644
--- a/ash/components/shortcut_viewer/vector_icons/ksv_separator_plus.1x.icon
+++ b/ash/components/shortcut_viewer/vector_icons/ksv_separator_plus.1x.icon
@@ -15,5 +15,4 @@
 R_H_LINE_TO, 2,
 R_V_LINE_TO, 3,
 R_H_LINE_TO, 3,
-CLOSE,
-END
+CLOSE
diff --git a/ash/components/shortcut_viewer/vector_icons/ksv_separator_plus.icon b/ash/components/shortcut_viewer/vector_icons/ksv_separator_plus.icon
index 65b0911..f71544c 100644
--- a/ash/components/shortcut_viewer/vector_icons/ksv_separator_plus.icon
+++ b/ash/components/shortcut_viewer/vector_icons/ksv_separator_plus.icon
@@ -15,5 +15,4 @@
 R_H_LINE_TO, 4,
 R_V_LINE_TO, 6,
 R_H_LINE_TO, 6,
-CLOSE,
-END
+CLOSE
diff --git a/ash/components/shortcut_viewer/vector_icons/ksv_volume_down.1x.icon b/ash/components/shortcut_viewer/vector_icons/ksv_volume_down.1x.icon
index cf5063d..1e55f0ce 100644
--- a/ash/components/shortcut_viewer/vector_icons/ksv_volume_down.1x.icon
+++ b/ash/components/shortcut_viewer/vector_icons/ksv_volume_down.1x.icon
@@ -15,5 +15,4 @@
 CUBIC_TO, 11.59f, 7, 11.02f, 6.15f, 10.19f, 5.73f,
 LINE_TO, 10.19f, 10.26f,
 CUBIC_TO, 11.02f, 9.85f, 11.59f, 9, 11.59f, 8,
-CLOSE,
-END
+CLOSE
diff --git a/ash/components/shortcut_viewer/vector_icons/ksv_volume_down.icon b/ash/components/shortcut_viewer/vector_icons/ksv_volume_down.icon
index 8427713..d24273cb 100644
--- a/ash/components/shortcut_viewer/vector_icons/ksv_volume_down.icon
+++ b/ash/components/shortcut_viewer/vector_icons/ksv_volume_down.icon
@@ -15,5 +15,4 @@
 CUBIC_TO, 23.19f, 14.01f, 22.04f, 12.3f, 20.37f, 11.47f,
 LINE_TO, 20.37f, 20.52f,
 CUBIC_TO, 22.04f, 19.7f, 23.19f, 17.99f, 23.19f, 16,
-CLOSE,
-END
+CLOSE
diff --git a/ash/components/shortcut_viewer/vector_icons/ksv_volume_up.1x.icon b/ash/components/shortcut_viewer/vector_icons/ksv_volume_up.1x.icon
index b0a1da0..f59c157 100644
--- a/ash/components/shortcut_viewer/vector_icons/ksv_volume_up.1x.icon
+++ b/ash/components/shortcut_viewer/vector_icons/ksv_volume_up.1x.icon
@@ -23,5 +23,4 @@
 LINE_TO, 8.06f, 3.43f,
 LINE_TO, 5.25f, 6.24f,
 LINE_TO, 3, 6.24f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/components/shortcut_viewer/vector_icons/ksv_volume_up.icon b/ash/components/shortcut_viewer/vector_icons/ksv_volume_up.icon
index 55dfe52..4a77d47 100644
--- a/ash/components/shortcut_viewer/vector_icons/ksv_volume_up.icon
+++ b/ash/components/shortcut_viewer/vector_icons/ksv_volume_up.icon
@@ -23,5 +23,4 @@
 LINE_TO, 16.11f, 6.87f,
 LINE_TO, 10.49f, 12.48f,
 LINE_TO, 6, 12.48f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/components/shortcut_viewer_strings.grdp b/ash/components/shortcut_viewer_strings.grdp
index 4a8b59f6..50d3c5ee 100644
--- a/ash/components/shortcut_viewer_strings.grdp
+++ b/ash/components/shortcut_viewer_strings.grdp
@@ -112,7 +112,7 @@
     Press and hold <ph name="alt">$1<ex>Alt</ex></ph>, tap <ph name="tab">$2<ex>v</ex></ph> until you get to the window you want to open, then release.
   </message>
   <message name="IDS_KSV_DESCRIPTION_CYCLE_BACKWARD_MRU" desc="Description of the command in keyboard shortcut viewer.">
-    Open the window you used least recently
+    Open the window that has been unused for the longest time
   </message>
   <message name="IDS_KSV_SHORTCUT_CYCLE_BACKWARD_MRU" desc="Human readable version of the keyboard shortcut.">
     Press and hold <ph name="alt">$1<ex>Alt</ex></ph><ph name="separator">$2<ex>+</ex></ph><ph name="shift">$3<ex>Shift</ex></ph>, tap <ph name="tab">$4<ex>v</ex></ph> until you get to the window you want to open, then release.
diff --git a/ash/public/cpp/vector_icons/notification_captive_portal.icon b/ash/public/cpp/vector_icons/notification_captive_portal.icon
index 74a3f8ae..aa44f60 100644
--- a/ash/public/cpp/vector_icons/notification_captive_portal.icon
+++ b/ash/public/cpp/vector_icons/notification_captive_portal.icon
@@ -59,5 +59,4 @@
 R_LINE_TO, -8.24f, 8.85f,
 LINE_TO, 86.67f, 75.76f,
 LINE_TO, 75.76f, 86.67f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/public/cpp/vector_icons/notification_cellular_alert.1x.icon b/ash/public/cpp/vector_icons/notification_cellular_alert.1x.icon
index bd7c4e5..b1c722fb 100644
--- a/ash/public/cpp/vector_icons/notification_cellular_alert.1x.icon
+++ b/ash/public/cpp/vector_icons/notification_cellular_alert.1x.icon
@@ -32,5 +32,4 @@
 H_LINE_TO, 16,
 V_LINE_TO, 8,
 H_LINE_TO, 14,
-CLOSE,
-END
+CLOSE
diff --git a/ash/public/cpp/vector_icons/notification_cellular_alert.icon b/ash/public/cpp/vector_icons/notification_cellular_alert.icon
index def7350..92ed360 100644
--- a/ash/public/cpp/vector_icons/notification_cellular_alert.icon
+++ b/ash/public/cpp/vector_icons/notification_cellular_alert.icon
@@ -32,5 +32,4 @@
 H_LINE_TO, 32,
 V_LINE_TO, 16,
 H_LINE_TO, 28,
-CLOSE,
-END
+CLOSE
diff --git a/ash/public/cpp/vector_icons/notification_download.icon b/ash/public/cpp/vector_icons/notification_download.icon
index 6112097..cb54cfb 100644
--- a/ash/public/cpp/vector_icons/notification_download.icon
+++ b/ash/public/cpp/vector_icons/notification_download.icon
@@ -17,5 +17,4 @@
 R_H_LINE_TO, 56,
 R_V_LINE_TO, -8,
 H_LINE_TO, 20,
-CLOSE,
-END
+CLOSE
diff --git a/ash/public/cpp/vector_icons/notification_end_of_support.icon b/ash/public/cpp/vector_icons/notification_end_of_support.icon
index 78502ea..475ccda 100644
--- a/ash/public/cpp/vector_icons/notification_end_of_support.icon
+++ b/ash/public/cpp/vector_icons/notification_end_of_support.icon
@@ -40,5 +40,4 @@
 R_H_LINE_TO, 9,
 R_V_LINE_TO, 15,
 R_H_LINE_TO, 20,
-CLOSE,
-END
+CLOSE
diff --git a/ash/public/cpp/vector_icons/notification_google.icon b/ash/public/cpp/vector_icons/notification_google.icon
index 42135ac..45d9211 100644
--- a/ash/public/cpp/vector_icons/notification_google.icon
+++ b/ash/public/cpp/vector_icons/notification_google.icon
@@ -23,5 +23,4 @@
 R_LINE_TO, 8.19f, -8.03f,
 CUBIC_TO, 62.74f, 22.78f, 56.28f, 20, 48.57f, 20,
 CUBIC_TO, 32.79f, 20, 20, 32.54f, 20, 48,
-CLOSE,
-END
+CLOSE
diff --git a/ash/public/cpp/vector_icons/notification_image.icon b/ash/public/cpp/vector_icons/notification_image.icon
index b698f4c..ad5746c 100644
--- a/ash/public/cpp/vector_icons/notification_image.icon
+++ b/ash/public/cpp/vector_icons/notification_image.icon
@@ -19,5 +19,4 @@
 R_LINE_TO, 18, 24,
 H_LINE_TO, 20,
 R_LINE_TO, 14, -18,
-CLOSE,
-END
+CLOSE
diff --git a/ash/public/cpp/vector_icons/notification_installed.icon b/ash/public/cpp/vector_icons/notification_installed.icon
index 348d1db..1089044 100644
--- a/ash/public/cpp/vector_icons/notification_installed.icon
+++ b/ash/public/cpp/vector_icons/notification_installed.icon
@@ -16,5 +16,4 @@
 R_LINE_TO, 30.36f, -30.36f,
 LINE_TO, 76, 32,
 LINE_TO, 40, 68,
-CLOSE,
-END
+CLOSE
diff --git a/ash/public/cpp/vector_icons/notification_mobile_data.icon b/ash/public/cpp/vector_icons/notification_mobile_data.icon
index 7ab9e42..d78be61 100644
--- a/ash/public/cpp/vector_icons/notification_mobile_data.icon
+++ b/ash/public/cpp/vector_icons/notification_mobile_data.icon
@@ -6,5 +6,4 @@
 MOVE_TO, 12, 84,
 R_H_LINE_TO, 72,
 V_LINE_TO, 12,
-CLOSE,
-END
+CLOSE
diff --git a/ash/public/cpp/vector_icons/notification_mobile_data_off.icon b/ash/public/cpp/vector_icons/notification_mobile_data_off.icon
index 70494c3..b4531401 100644
--- a/ash/public/cpp/vector_icons/notification_mobile_data_off.icon
+++ b/ash/public/cpp/vector_icons/notification_mobile_data_off.icon
@@ -16,5 +16,4 @@
 LINE_TO, 84, 8,
 R_V_LINE_TO, 60.36f,
 LINE_TO, 53.82f, 38.18f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/public/cpp/vector_icons/notification_play_prism.icon b/ash/public/cpp/vector_icons/notification_play_prism.icon
index f7293f99..3f3f637 100644
--- a/ash/public/cpp/vector_icons/notification_play_prism.icon
+++ b/ash/public/cpp/vector_icons/notification_play_prism.icon
@@ -33,5 +33,4 @@
 V_LINE_TO, 79.78f,
 R_CUBIC_TO, 0, 0.95f, 0.68f, 1.39f, 1.35f, 0.7f,
 LINE_TO, 48, 49,
-CLOSE,
-END
+CLOSE
diff --git a/ash/public/cpp/vector_icons/notification_printing.icon b/ash/public/cpp/vector_icons/notification_printing.icon
index ff9384a..2c93ce9 100644
--- a/ash/public/cpp/vector_icons/notification_printing.icon
+++ b/ash/public/cpp/vector_icons/notification_printing.icon
@@ -32,5 +32,4 @@
 R_V_LINE_TO, 16,
 R_H_LINE_TO, 48,
 V_LINE_TO, 12,
-CLOSE,
-END
+CLOSE
diff --git a/ash/public/cpp/vector_icons/notification_printing_done.icon b/ash/public/cpp/vector_icons/notification_printing_done.icon
index 626b6df..c60eda4d 100644
--- a/ash/public/cpp/vector_icons/notification_printing_done.icon
+++ b/ash/public/cpp/vector_icons/notification_printing_done.icon
@@ -45,5 +45,4 @@
 R_LINE_TO, -5.13f, -5.5f,
 LINE_TO, 62, 72.32f,
 LINE_TO, 69.14f, 80,
-CLOSE,
-END
+CLOSE
diff --git a/ash/public/cpp/vector_icons/notification_printing_warning.icon b/ash/public/cpp/vector_icons/notification_printing_warning.icon
index 984fc20..9d54e1a 100644
--- a/ash/public/cpp/vector_icons/notification_printing_warning.icon
+++ b/ash/public/cpp/vector_icons/notification_printing_warning.icon
@@ -49,5 +49,4 @@
 R_H_LINE_TO, 4,
 R_V_LINE_TO, -4,
 R_H_LINE_TO, -4,
-CLOSE,
-END
+CLOSE
diff --git a/ash/public/cpp/vector_icons/notification_storage_full.icon b/ash/public/cpp/vector_icons/notification_storage_full.icon
index c344066..ac9835d 100644
--- a/ash/public/cpp/vector_icons/notification_storage_full.icon
+++ b/ash/public/cpp/vector_icons/notification_storage_full.icon
@@ -42,5 +42,4 @@
 R_H_LINE_TO, 4,
 R_V_LINE_TO, -4,
 R_H_LINE_TO, -4,
-CLOSE,
-END
+CLOSE
diff --git a/ash/public/cpp/vector_icons/notification_vpn.icon b/ash/public/cpp/vector_icons/notification_vpn.icon
index 9a54dda..8aa5fb5a 100644
--- a/ash/public/cpp/vector_icons/notification_vpn.icon
+++ b/ash/public/cpp/vector_icons/notification_vpn.icon
@@ -21,5 +21,4 @@
 R_CUBIC_TO, 0, -4.4f, 3.6f, -8, 8, -8,
 R_CUBIC_TO, 4.4f, 0, 8, 3.6f, 8, 8,
 R_CUBIC_TO, 0, 4.4f, -3.6f, 8, -8, 8,
-CLOSE,
-END
+CLOSE
diff --git a/ash/public/cpp/vector_icons/notification_warning.icon b/ash/public/cpp/vector_icons/notification_warning.icon
index b90da17..146fa3c 100644
--- a/ash/public/cpp/vector_icons/notification_warning.icon
+++ b/ash/public/cpp/vector_icons/notification_warning.icon
@@ -20,5 +20,4 @@
 R_H_LINE_TO, 8,
 R_V_LINE_TO, -8,
 R_H_LINE_TO, -8,
-CLOSE,
-END
+CLOSE
diff --git a/ash/public/cpp/vector_icons/notification_wifi_off.icon b/ash/public/cpp/vector_icons/notification_wifi_off.icon
index 63e879a..b868c416 100644
--- a/ash/public/cpp/vector_icons/notification_wifi_off.icon
+++ b/ash/public/cpp/vector_icons/notification_wifi_off.icon
@@ -21,5 +21,4 @@
 R_LINE_TO, 5.18f, -5.15f,
 LINE_TO, 12.31f, 8,
 R_LINE_TO, -5.18f, 5.15f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/public/cpp/vector_icons/window_control_close.1x.icon b/ash/public/cpp/vector_icons/window_control_close.1x.icon
index 94d36a0f..813445e 100644
--- a/ash/public/cpp/vector_icons/window_control_close.1x.icon
+++ b/ash/public/cpp/vector_icons/window_control_close.1x.icon
@@ -16,5 +16,4 @@
 R_LINE_TO, 3.54f, -3.54f,
 LINE_TO, 9.54f, 1.05f,
 LINE_TO, 6, 4.59f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/public/cpp/vector_icons/window_control_close.icon b/ash/public/cpp/vector_icons/window_control_close.icon
index 1e6fb80..d9d780e 100644
--- a/ash/public/cpp/vector_icons/window_control_close.icon
+++ b/ash/public/cpp/vector_icons/window_control_close.icon
@@ -16,5 +16,4 @@
 LINE_TO, 23, 20.78f,
 LINE_TO, 14.22f, 12,
 LINE_TO, 23, 3.22f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/public/cpp/vector_icons/window_control_left_snapped.1x.icon b/ash/public/cpp/vector_icons/window_control_left_snapped.1x.icon
index 0899d308..b5bfa0e 100644
--- a/ash/public/cpp/vector_icons/window_control_left_snapped.1x.icon
+++ b/ash/public/cpp/vector_icons/window_control_left_snapped.1x.icon
@@ -11,5 +11,4 @@
 LINE_TO, 6.6f, 1,
 LINE_TO, 1.7f, 5.38f,
 LINE_TO, 1, 6,
-CLOSE,
-END
+CLOSE
diff --git a/ash/public/cpp/vector_icons/window_control_left_snapped.icon b/ash/public/cpp/vector_icons/window_control_left_snapped.icon
index f764dc7..694f178e1 100644
--- a/ash/public/cpp/vector_icons/window_control_left_snapped.icon
+++ b/ash/public/cpp/vector_icons/window_control_left_snapped.icon
@@ -12,5 +12,4 @@
 R_LINE_TO, 5, -4.77f,
 LINE_TO, 12.86f, 0,
 LINE_TO, 15, 2.05f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/public/cpp/vector_icons/window_control_maximize.1x.icon b/ash/public/cpp/vector_icons/window_control_maximize.1x.icon
index f1c56bb..d5b91ae 100644
--- a/ash/public/cpp/vector_icons/window_control_maximize.1x.icon
+++ b/ash/public/cpp/vector_icons/window_control_maximize.1x.icon
@@ -14,5 +14,4 @@
 V_LINE_TO, 3,
 R_H_LINE_TO, 6,
 R_V_LINE_TO, 6,
-CLOSE,
-END
+CLOSE
diff --git a/ash/public/cpp/vector_icons/window_control_maximize.icon b/ash/public/cpp/vector_icons/window_control_maximize.icon
index c186d5f..9eef1c7 100644
--- a/ash/public/cpp/vector_icons/window_control_maximize.icon
+++ b/ash/public/cpp/vector_icons/window_control_maximize.icon
@@ -14,5 +14,4 @@
 V_LINE_TO, 4,
 R_H_LINE_TO, 16,
 R_V_LINE_TO, 16,
-CLOSE,
-END
+CLOSE
diff --git a/ash/public/cpp/vector_icons/window_control_minimize.1x.icon b/ash/public/cpp/vector_icons/window_control_minimize.1x.icon
index da77c268..3064a7c8 100644
--- a/ash/public/cpp/vector_icons/window_control_minimize.1x.icon
+++ b/ash/public/cpp/vector_icons/window_control_minimize.1x.icon
@@ -7,5 +7,4 @@
 R_H_LINE_TO, 10,
 R_V_LINE_TO, 2,
 H_LINE_TO, 1,
-CLOSE,
-END
+CLOSE
diff --git a/ash/public/cpp/vector_icons/window_control_minimize.icon b/ash/public/cpp/vector_icons/window_control_minimize.icon
index 98629c7..680228f 100644
--- a/ash/public/cpp/vector_icons/window_control_minimize.icon
+++ b/ash/public/cpp/vector_icons/window_control_minimize.icon
@@ -7,5 +7,4 @@
 R_H_LINE_TO, 22,
 R_V_LINE_TO, 3,
 H_LINE_TO, 1,
-CLOSE,
-END
+CLOSE
diff --git a/ash/public/cpp/vector_icons/window_control_restore.1x.icon b/ash/public/cpp/vector_icons/window_control_restore.1x.icon
index 99449dd..3836338 100644
--- a/ash/public/cpp/vector_icons/window_control_restore.1x.icon
+++ b/ash/public/cpp/vector_icons/window_control_restore.1x.icon
@@ -22,5 +22,4 @@
 V_LINE_TO, 9,
 H_LINE_TO, 3,
 V_LINE_TO, 3,
-CLOSE,
-END
+CLOSE
diff --git a/ash/public/cpp/vector_icons/window_control_restore.icon b/ash/public/cpp/vector_icons/window_control_restore.icon
index f511b4c..037ad4e 100644
--- a/ash/public/cpp/vector_icons/window_control_restore.icon
+++ b/ash/public/cpp/vector_icons/window_control_restore.icon
@@ -22,5 +22,4 @@
 R_V_LINE_TO, -3,
 H_LINE_TO, 4,
 V_LINE_TO, 8,
-CLOSE,
-END
+CLOSE
diff --git a/ash/public/cpp/vector_icons/window_control_right_snapped.1x.icon b/ash/public/cpp/vector_icons/window_control_right_snapped.1x.icon
index 448e72c..2c6add2 100644
--- a/ash/public/cpp/vector_icons/window_control_right_snapped.1x.icon
+++ b/ash/public/cpp/vector_icons/window_control_right_snapped.1x.icon
@@ -11,5 +11,4 @@
 LINE_TO, 5.4f, 1,
 R_LINE_TO, 4.9f, 4.38f,
 LINE_TO, 11, 6,
-CLOSE,
-END
+CLOSE
diff --git a/ash/public/cpp/vector_icons/window_control_right_snapped.icon b/ash/public/cpp/vector_icons/window_control_right_snapped.icon
index f446d371..fc6cff21 100644
--- a/ash/public/cpp/vector_icons/window_control_right_snapped.icon
+++ b/ash/public/cpp/vector_icons/window_control_right_snapped.icon
@@ -12,5 +12,4 @@
 R_LINE_TO, -5, -4.77f,
 LINE_TO, 11.14f, 0,
 LINE_TO, 9, 2.05f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/captive_portal.1x.icon b/ash/resources/vector_icons/captive_portal.1x.icon
index e8fdc72..32f691f 100644
--- a/ash/resources/vector_icons/captive_portal.1x.icon
+++ b/ash/resources/vector_icons/captive_portal.1x.icon
@@ -57,5 +57,4 @@
 R_H_LINE_TO, 5.5f,
 R_LINE_TO, -2, 1.5f,
 LINE_TO, 18, 16,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/captive_portal.icon b/ash/resources/vector_icons/captive_portal.icon
index 64ba3f84..255f47d 100644
--- a/ash/resources/vector_icons/captive_portal.icon
+++ b/ash/resources/vector_icons/captive_portal.icon
@@ -57,5 +57,4 @@
 R_H_LINE_TO, 10.9f,
 R_LINE_TO, -3.29f, 3.31f,
 LINE_TO, 34, 30.72f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/check_circle.1x.icon b/ash/resources/vector_icons/check_circle.1x.icon
index 1fe038c..2ed8bab 100644
--- a/ash/resources/vector_icons/check_circle.1x.icon
+++ b/ash/resources/vector_icons/check_circle.1x.icon
@@ -16,5 +16,4 @@
 R_LINE_TO, 6.07f, -6.07f,
 LINE_TO, 15.6f, 6.8f,
 LINE_TO, 8.4f, 14,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/check_circle.icon b/ash/resources/vector_icons/check_circle.icon
index 7a320d7..f2ef12f 100644
--- a/ash/resources/vector_icons/check_circle.icon
+++ b/ash/resources/vector_icons/check_circle.icon
@@ -18,5 +18,4 @@
 R_LINE_TO, 12.14f, -12.14f,
 LINE_TO, 31.2f, 13.6f,
 LINE_TO, 16.8f, 28,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/ime_menu_emoticon.1x.icon b/ash/resources/vector_icons/ime_menu_emoticon.1x.icon
index 3766c426..c31d4f0 100644
--- a/ash/resources/vector_icons/ime_menu_emoticon.1x.icon
+++ b/ash/resources/vector_icons/ime_menu_emoticon.1x.icon
@@ -36,5 +36,4 @@
 LINE_TO, 5.91f, 11,
 CUBIC_TO, 6.55f, 12.75f, 8.14f, 14, 10, 14,
 LINE_TO, 10, 14,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/ime_menu_emoticon.icon b/ash/resources/vector_icons/ime_menu_emoticon.icon
index 22d6e0d..fa34c76a 100644
--- a/ash/resources/vector_icons/ime_menu_emoticon.icon
+++ b/ash/resources/vector_icons/ime_menu_emoticon.icon
@@ -36,5 +36,4 @@
 LINE_TO, 11.82f, 23,
 CUBIC_TO, 13.1f, 26.5f, 16.27f, 29, 20, 29,
 LINE_TO, 20, 29,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/ime_menu_microphone.1x.icon b/ash/resources/vector_icons/ime_menu_microphone.1x.icon
index 1d370e85..05253cc 100644
--- a/ash/resources/vector_icons/ime_menu_microphone.1x.icon
+++ b/ash/resources/vector_icons/ime_menu_microphone.1x.icon
@@ -23,5 +23,4 @@
 CUBIC_TO, 13.67f, 14.83f, 16, 12.46f, 16, 9.58f,
 LINE_TO, 14.54f, 9.58f,
 LINE_TO, 14.54f, 9.58f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/ime_menu_microphone.icon b/ash/resources/vector_icons/ime_menu_microphone.icon
index ba3a720..c248111d 100644
--- a/ash/resources/vector_icons/ime_menu_microphone.icon
+++ b/ash/resources/vector_icons/ime_menu_microphone.icon
@@ -23,5 +23,4 @@
 CUBIC_TO, 27.13f, 30.67f, 31.67f, 25.92f, 31.67f, 20.16f,
 LINE_TO, 28.83f, 20.16f,
 LINE_TO, 28.83f, 20.16f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/ime_menu_on_screen_keyboard.1x.icon b/ash/resources/vector_icons/ime_menu_on_screen_keyboard.1x.icon
index 27ef535..d21e3ac2a 100644
--- a/ash/resources/vector_icons/ime_menu_on_screen_keyboard.1x.icon
+++ b/ash/resources/vector_icons/ime_menu_on_screen_keyboard.1x.icon
@@ -54,5 +54,4 @@
 R_V_LINE_TO, 1,
 R_H_LINE_TO, -1,
 R_V_LINE_TO, -1,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/ime_menu_on_screen_keyboard.icon b/ash/resources/vector_icons/ime_menu_on_screen_keyboard.icon
index 34569528..0830899 100644
--- a/ash/resources/vector_icons/ime_menu_on_screen_keyboard.icon
+++ b/ash/resources/vector_icons/ime_menu_on_screen_keyboard.icon
@@ -66,5 +66,4 @@
 R_V_LINE_TO, 2,
 R_H_LINE_TO, -2,
 R_V_LINE_TO, -2,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/ime_menu_write.1x.icon b/ash/resources/vector_icons/ime_menu_write.1x.icon
index 4eed1d9..f261758 100644
--- a/ash/resources/vector_icons/ime_menu_write.1x.icon
+++ b/ash/resources/vector_icons/ime_menu_write.1x.icon
@@ -23,5 +23,4 @@
 LINE_TO, 12, 4.81f,
 LINE_TO, 15.19f, 8,
 LINE_TO, 16.75f, 6.44f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/ime_menu_write.icon b/ash/resources/vector_icons/ime_menu_write.icon
index 184715ba..2d2ca449 100644
--- a/ash/resources/vector_icons/ime_menu_write.icon
+++ b/ash/resources/vector_icons/ime_menu_write.icon
@@ -23,5 +23,4 @@
 LINE_TO, 25.22f, 8.53f,
 LINE_TO, 31.47f, 14.78f,
 LINE_TO, 34.52f, 11.73f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/lock_screen_alert.1x.icon b/ash/resources/vector_icons/lock_screen_alert.1x.icon
index c6c7d679..a22a1ae 100644
--- a/ash/resources/vector_icons/lock_screen_alert.1x.icon
+++ b/ash/resources/vector_icons/lock_screen_alert.1x.icon
@@ -19,5 +19,4 @@
 LINE_TO, 9.17f, 8.33f,
 LINE_TO, 10.83f, 8.33f,
 LINE_TO, 10.83f, 11.67f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/lock_screen_alert.icon b/ash/resources/vector_icons/lock_screen_alert.icon
index 02ef97e8..cc8f849 100644
--- a/ash/resources/vector_icons/lock_screen_alert.icon
+++ b/ash/resources/vector_icons/lock_screen_alert.icon
@@ -19,5 +19,4 @@
 LINE_TO, 18, 16,
 LINE_TO, 22, 16,
 LINE_TO, 22, 23,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/lock_screen_arrow.1x.icon b/ash/resources/vector_icons/lock_screen_arrow.1x.icon
index 4ddf012..079394de 100644
--- a/ash/resources/vector_icons/lock_screen_arrow.1x.icon
+++ b/ash/resources/vector_icons/lock_screen_arrow.1x.icon
@@ -12,5 +12,4 @@
 R_LINE_TO, -3.77f, 3.78f,
 LINE_TO, 10.42f, 15.83,
 R_LINE_TO, 5.42f, -5.42f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/lock_screen_arrow.icon b/ash/resources/vector_icons/lock_screen_arrow.icon
index 6ab6ea7b..61c1ed8 100644
--- a/ash/resources/vector_icons/lock_screen_arrow.icon
+++ b/ash/resources/vector_icons/lock_screen_arrow.icon
@@ -11,5 +11,4 @@
 LINE_TO, 21.71f, 34.71f,
 LINE_TO, 24, 37,
 R_LINE_TO, 13, -13,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/lock_screen_backspace.1x.icon b/ash/resources/vector_icons/lock_screen_backspace.1x.icon
index c804d87..1a675fe 100644
--- a/ash/resources/vector_icons/lock_screen_backspace.1x.icon
+++ b/ash/resources/vector_icons/lock_screen_backspace.1x.icon
@@ -27,5 +27,4 @@
 LINE_TO, 14.67f, 7.61f,
 LINE_TO, 12.27f, 10,
 LINE_TO, 14.67f, 12.39f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/lock_screen_backspace.icon b/ash/resources/vector_icons/lock_screen_backspace.icon
index a989bef..c047d5a 100644
--- a/ash/resources/vector_icons/lock_screen_backspace.icon
+++ b/ash/resources/vector_icons/lock_screen_backspace.icon
@@ -27,5 +27,4 @@
 LINE_TO, 29.33f, 15.21f,
 LINE_TO, 24.55f, 20,
 LINE_TO, 29.33f, 24.79f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/lock_screen_caps_lock.1x.icon b/ash/resources/vector_icons/lock_screen_caps_lock.1x.icon
index b5ced06..18a1e754 100644
--- a/ash/resources/vector_icons/lock_screen_caps_lock.1x.icon
+++ b/ash/resources/vector_icons/lock_screen_caps_lock.1x.icon
@@ -26,5 +26,4 @@
 LINE_TO, 15, 13.5f,
 LINE_TO, 5, 13.5f,
 LINE_TO, 5, 15,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/lock_screen_caps_lock.icon b/ash/resources/vector_icons/lock_screen_caps_lock.icon
index 53a6d8a..d04a5099 100644
--- a/ash/resources/vector_icons/lock_screen_caps_lock.icon
+++ b/ash/resources/vector_icons/lock_screen_caps_lock.icon
@@ -28,5 +28,4 @@
 LINE_TO, 30, 27,
 LINE_TO, 10, 27,
 LINE_TO, 10, 30,
-CLOSE,
-END
\ No newline at end of file
+CLOSE
diff --git a/ash/resources/vector_icons/lock_screen_dropdown.1x.icon b/ash/resources/vector_icons/lock_screen_dropdown.1x.icon
index c1cbfa2f..c926e74 100644
--- a/ash/resources/vector_icons/lock_screen_dropdown.1x.icon
+++ b/ash/resources/vector_icons/lock_screen_dropdown.1x.icon
@@ -10,5 +10,4 @@
 LINE_TO, 6, 10,
 R_LINE_TO, 6, 6,
 R_LINE_TO, 6, -6,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/lock_screen_dropdown.icon b/ash/resources/vector_icons/lock_screen_dropdown.icon
index 884944c..45090b59 100644
--- a/ash/resources/vector_icons/lock_screen_dropdown.icon
+++ b/ash/resources/vector_icons/lock_screen_dropdown.icon
@@ -9,5 +9,4 @@
 LINE_TO, 12, 20,
 R_LINE_TO, 12, 12,
 R_LINE_TO, 12, -12,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/login_screen_enterprise.1x.icon b/ash/resources/vector_icons/login_screen_enterprise.1x.icon
index bb0c84fd..af92587 100644
--- a/ash/resources/vector_icons/login_screen_enterprise.1x.icon
+++ b/ash/resources/vector_icons/login_screen_enterprise.1x.icon
@@ -84,5 +84,4 @@
 V_LINE_TO, 5,
 R_H_LINE_TO, 4,
 R_V_LINE_TO, 5,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/login_screen_enterprise.icon b/ash/resources/vector_icons/login_screen_enterprise.icon
index 523a4d2..44715279 100644
--- a/ash/resources/vector_icons/login_screen_enterprise.icon
+++ b/ash/resources/vector_icons/login_screen_enterprise.icon
@@ -84,5 +84,4 @@
 R_H_LINE_TO, 20,
 V_LINE_TO, 7,
 H_LINE_TO, 12,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/network_badge_add_other.1x.icon b/ash/resources/vector_icons/network_badge_add_other.1x.icon
index 6fdf200d..5d081e32 100644
--- a/ash/resources/vector_icons/network_badge_add_other.1x.icon
+++ b/ash/resources/vector_icons/network_badge_add_other.1x.icon
@@ -23,5 +23,4 @@
 R_V_LINE_TO, 2,
 R_H_LINE_TO, -2,
 R_V_LINE_TO, -2,
-CLOSE,
-END
\ No newline at end of file
+CLOSE
diff --git a/ash/resources/vector_icons/network_badge_add_other.icon b/ash/resources/vector_icons/network_badge_add_other.icon
index 43f7c8a9..17e3002 100644
--- a/ash/resources/vector_icons/network_badge_add_other.icon
+++ b/ash/resources/vector_icons/network_badge_add_other.icon
@@ -23,5 +23,4 @@
 R_V_LINE_TO, 4,
 R_H_LINE_TO, -4,
 R_V_LINE_TO, -4,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/network_badge_captive_portal.1x.icon b/ash/resources/vector_icons/network_badge_captive_portal.1x.icon
index ebe1ed0..8f616d7 100644
--- a/ash/resources/vector_icons/network_badge_captive_portal.1x.icon
+++ b/ash/resources/vector_icons/network_badge_captive_portal.1x.icon
@@ -20,5 +20,4 @@
 R_V_LINE_TO, 1,
 H_LINE_TO, 4,
 V_LINE_TO, 6,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/network_badge_captive_portal.icon b/ash/resources/vector_icons/network_badge_captive_portal.icon
index 83d3718..c592eb1 100644
--- a/ash/resources/vector_icons/network_badge_captive_portal.icon
+++ b/ash/resources/vector_icons/network_badge_captive_portal.icon
@@ -20,5 +20,4 @@
 R_V_LINE_TO, 2,
 H_LINE_TO, 7,
 R_V_LINE_TO, -2,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/network_badge_off.1x.icon b/ash/resources/vector_icons/network_badge_off.1x.icon
index d48903a..6fab9ad2 100644
--- a/ash/resources/vector_icons/network_badge_off.1x.icon
+++ b/ash/resources/vector_icons/network_badge_off.1x.icon
@@ -11,5 +11,4 @@
 CAP_SQUARE,
 STROKE, 2,
 MOVE_TO, 2, 1.5f,
-R_LINE_TO, 14, 14,
-END
+R_LINE_TO, 14, 14
diff --git a/ash/resources/vector_icons/network_badge_off.icon b/ash/resources/vector_icons/network_badge_off.icon
index d68754eb..3726648 100644
--- a/ash/resources/vector_icons/network_badge_off.icon
+++ b/ash/resources/vector_icons/network_badge_off.icon
@@ -11,5 +11,4 @@
 CAP_SQUARE,
 STROKE, 3,
 MOVE_TO, 4, 4,
-R_LINE_TO, 28, 28,
-END
+R_LINE_TO, 28, 28
diff --git a/ash/resources/vector_icons/network_badge_roaming.1x.icon b/ash/resources/vector_icons/network_badge_roaming.1x.icon
index 4841e2b..a028fb08 100644
--- a/ash/resources/vector_icons/network_badge_roaming.1x.icon
+++ b/ash/resources/vector_icons/network_badge_roaming.1x.icon
@@ -6,5 +6,4 @@
 MOVE_TO, 3.5f, 2,
 LINE_TO, 1, 6,
 R_H_LINE_TO, 5,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/network_badge_roaming.icon b/ash/resources/vector_icons/network_badge_roaming.icon
index 849c3ce1..1395081 100644
--- a/ash/resources/vector_icons/network_badge_roaming.icon
+++ b/ash/resources/vector_icons/network_badge_roaming.icon
@@ -6,5 +6,4 @@
 MOVE_TO, 8, 4,
 R_LINE_TO, -5, 8,
 R_H_LINE_TO, 10,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/network_badge_secure.1x.icon b/ash/resources/vector_icons/network_badge_secure.1x.icon
index 8d94712..d341cd2 100644
--- a/ash/resources/vector_icons/network_badge_secure.1x.icon
+++ b/ash/resources/vector_icons/network_badge_secure.1x.icon
@@ -36,5 +36,4 @@
 R_H_LINE_TO, -3,
 V_LINE_TO, 0,
 R_H_LINE_TO, 3,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/network_badge_secure.icon b/ash/resources/vector_icons/network_badge_secure.icon
index 07e54be..16b32d6 100644
--- a/ash/resources/vector_icons/network_badge_secure.icon
+++ b/ash/resources/vector_icons/network_badge_secure.icon
@@ -32,5 +32,4 @@
 H_LINE_TO, 6,
 V_LINE_TO, 5,
 CUBIC_TO, 6, 3.89f, 6.89f, 3, 8, 3,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/network_badge_technology_1x.1x.icon b/ash/resources/vector_icons/network_badge_technology_1x.1x.icon
index 817ce4a..68940a1 100644
--- a/ash/resources/vector_icons/network_badge_technology_1x.1x.icon
+++ b/ash/resources/vector_icons/network_badge_technology_1x.1x.icon
@@ -40,5 +40,4 @@
 R_V_LINE_TO, 1,
 H_LINE_TO, 5,
 V_LINE_TO, 2,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/network_badge_technology_1x.icon b/ash/resources/vector_icons/network_badge_technology_1x.icon
index cfab3cc..cb39af6 100644
--- a/ash/resources/vector_icons/network_badge_technology_1x.icon
+++ b/ash/resources/vector_icons/network_badge_technology_1x.icon
@@ -40,5 +40,4 @@
 R_V_LINE_TO, 2,
 R_H_LINE_TO, -2,
 V_LINE_TO, 4,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/network_badge_technology_3g.1x.icon b/ash/resources/vector_icons/network_badge_technology_3g.1x.icon
index 82c3f3c..3fc0c19 100644
--- a/ash/resources/vector_icons/network_badge_technology_3g.1x.icon
+++ b/ash/resources/vector_icons/network_badge_technology_3g.1x.icon
@@ -32,5 +32,4 @@
 R_V_LINE_TO, 1,
 H_LINE_TO, 0,
 V_LINE_TO, 4,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/network_badge_technology_3g.icon b/ash/resources/vector_icons/network_badge_technology_3g.icon
index d32b539..b599cbb5 100644
--- a/ash/resources/vector_icons/network_badge_technology_3g.icon
+++ b/ash/resources/vector_icons/network_badge_technology_3g.icon
@@ -28,5 +28,4 @@
 H_LINE_TO, 2,
 R_V_LINE_TO, 2,
 R_H_LINE_TO, 4,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/network_badge_technology_4g.1x.icon b/ash/resources/vector_icons/network_badge_technology_4g.1x.icon
index 93701b10..e3671d6 100644
--- a/ash/resources/vector_icons/network_badge_technology_4g.1x.icon
+++ b/ash/resources/vector_icons/network_badge_technology_4g.1x.icon
@@ -43,5 +43,4 @@
 H_LINE_TO, 6,
 V_LINE_TO, 1,
 R_H_LINE_TO, 3,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/network_badge_technology_4g.icon b/ash/resources/vector_icons/network_badge_technology_4g.icon
index 2d5b3f7..0476d56 100644
--- a/ash/resources/vector_icons/network_badge_technology_4g.icon
+++ b/ash/resources/vector_icons/network_badge_technology_4g.icon
@@ -43,5 +43,4 @@
 R_H_LINE_TO, -4,
 V_LINE_TO, 2,
 R_H_LINE_TO, 6,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/network_badge_technology_edge.1x.icon b/ash/resources/vector_icons/network_badge_technology_edge.1x.icon
index 3201fc5..eb063f0 100644
--- a/ash/resources/vector_icons/network_badge_technology_edge.1x.icon
+++ b/ash/resources/vector_icons/network_badge_technology_edge.1x.icon
@@ -15,5 +15,4 @@
 V_LINE_TO, 1,
 R_H_LINE_TO, 2,
 V_LINE_TO, 0,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/network_badge_technology_edge.icon b/ash/resources/vector_icons/network_badge_technology_edge.icon
index 750e5f3..d49cbc6 100644
--- a/ash/resources/vector_icons/network_badge_technology_edge.icon
+++ b/ash/resources/vector_icons/network_badge_technology_edge.icon
@@ -15,5 +15,4 @@
 V_LINE_TO, 2,
 R_H_LINE_TO, 4,
 V_LINE_TO, 0,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/network_badge_technology_evdo.1x.icon b/ash/resources/vector_icons/network_badge_technology_evdo.1x.icon
index 760ed29a..1fd544b 100644
--- a/ash/resources/vector_icons/network_badge_technology_evdo.1x.icon
+++ b/ash/resources/vector_icons/network_badge_technology_evdo.1x.icon
@@ -44,5 +44,4 @@
 R_V_LINE_TO, 1,
 H_LINE_TO, 6,
 V_LINE_TO, 4,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/network_badge_technology_evdo.icon b/ash/resources/vector_icons/network_badge_technology_evdo.icon
index 9127e6b..899db78 100644
--- a/ash/resources/vector_icons/network_badge_technology_evdo.icon
+++ b/ash/resources/vector_icons/network_badge_technology_evdo.icon
@@ -44,5 +44,4 @@
 R_V_LINE_TO, 2,
 R_H_LINE_TO, -2,
 V_LINE_TO, 8,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/network_badge_technology_gprs.1x.icon b/ash/resources/vector_icons/network_badge_technology_gprs.1x.icon
index 52a3a64..6eb86f0 100644
--- a/ash/resources/vector_icons/network_badge_technology_gprs.1x.icon
+++ b/ash/resources/vector_icons/network_badge_technology_gprs.1x.icon
@@ -15,5 +15,4 @@
 H_LINE_TO, 1,
 V_LINE_TO, 1,
 R_H_LINE_TO, 3,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/network_badge_technology_gprs.icon b/ash/resources/vector_icons/network_badge_technology_gprs.icon
index 0510519..5067630 100644
--- a/ash/resources/vector_icons/network_badge_technology_gprs.icon
+++ b/ash/resources/vector_icons/network_badge_technology_gprs.icon
@@ -15,5 +15,4 @@
 H_LINE_TO, 2,
 V_LINE_TO, 2,
 R_H_LINE_TO, 6,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/network_badge_technology_hspa.1x.icon b/ash/resources/vector_icons/network_badge_technology_hspa.1x.icon
index f09c088..fcc4378 100644
--- a/ash/resources/vector_icons/network_badge_technology_hspa.1x.icon
+++ b/ash/resources/vector_icons/network_badge_technology_hspa.1x.icon
@@ -15,5 +15,4 @@
 H_LINE_TO, 1,
 R_V_LINE_TO, 2,
 H_LINE_TO, 0,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/network_badge_technology_hspa.icon b/ash/resources/vector_icons/network_badge_technology_hspa.icon
index 658476b..e739db6 100644
--- a/ash/resources/vector_icons/network_badge_technology_hspa.icon
+++ b/ash/resources/vector_icons/network_badge_technology_hspa.icon
@@ -15,5 +15,4 @@
 H_LINE_TO, 2,
 R_V_LINE_TO, 4,
 H_LINE_TO, 0,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/network_badge_technology_hspa_plus.1x.icon b/ash/resources/vector_icons/network_badge_technology_hspa_plus.1x.icon
index 16033ae..531bd6c 100644
--- a/ash/resources/vector_icons/network_badge_technology_hspa_plus.1x.icon
+++ b/ash/resources/vector_icons/network_badge_technology_hspa_plus.1x.icon
@@ -28,5 +28,4 @@
 R_H_LINE_TO, 1,
 V_LINE_TO, 1,
 H_LINE_TO, 7,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/network_badge_technology_hspa_plus.icon b/ash/resources/vector_icons/network_badge_technology_hspa_plus.icon
index 0795621f..3b02ec6 100644
--- a/ash/resources/vector_icons/network_badge_technology_hspa_plus.icon
+++ b/ash/resources/vector_icons/network_badge_technology_hspa_plus.icon
@@ -27,5 +27,4 @@
 H_LINE_TO, 2,
 R_V_LINE_TO, 4,
 H_LINE_TO, 0,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/network_badge_technology_lte.1x.icon b/ash/resources/vector_icons/network_badge_technology_lte.1x.icon
index 6c3513d6..a29b7d2 100644
--- a/ash/resources/vector_icons/network_badge_technology_lte.1x.icon
+++ b/ash/resources/vector_icons/network_badge_technology_lte.1x.icon
@@ -29,5 +29,4 @@
 V_LINE_TO, 1,
 R_H_LINE_TO, 2,
 V_LINE_TO, 0,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/network_badge_technology_lte.icon b/ash/resources/vector_icons/network_badge_technology_lte.icon
index 216a9e1b..ef5d14f 100644
--- a/ash/resources/vector_icons/network_badge_technology_lte.icon
+++ b/ash/resources/vector_icons/network_badge_technology_lte.icon
@@ -29,5 +29,4 @@
 V_LINE_TO, 2,
 R_H_LINE_TO, 4,
 V_LINE_TO, 0,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/network_badge_technology_lte_advanced.1x.icon b/ash/resources/vector_icons/network_badge_technology_lte_advanced.1x.icon
index f6bbf39f..d4df8a6 100644
--- a/ash/resources/vector_icons/network_badge_technology_lte_advanced.1x.icon
+++ b/ash/resources/vector_icons/network_badge_technology_lte_advanced.1x.icon
@@ -42,5 +42,4 @@
 R_H_LINE_TO, 1,
 V_LINE_TO, 1,
 R_H_LINE_TO, -1,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/network_badge_technology_lte_advanced.icon b/ash/resources/vector_icons/network_badge_technology_lte_advanced.icon
index c5b67158..88e954a 100644
--- a/ash/resources/vector_icons/network_badge_technology_lte_advanced.icon
+++ b/ash/resources/vector_icons/network_badge_technology_lte_advanced.icon
@@ -41,5 +41,4 @@
 V_LINE_TO, 3,
 R_H_LINE_TO, -3,
 V_LINE_TO, 0,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/network_badge_vpn.1x.icon b/ash/resources/vector_icons/network_badge_vpn.1x.icon
index 442103a..c324612 100644
--- a/ash/resources/vector_icons/network_badge_vpn.1x.icon
+++ b/ash/resources/vector_icons/network_badge_vpn.1x.icon
@@ -22,5 +22,4 @@
 R_V_LINE_TO, 1,
 H_LINE_TO, 2,
 V_LINE_TO, 3,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/network_badge_vpn.icon b/ash/resources/vector_icons/network_badge_vpn.icon
index 0b41ec5d..7d67067e 100644
--- a/ash/resources/vector_icons/network_badge_vpn.icon
+++ b/ash/resources/vector_icons/network_badge_vpn.icon
@@ -22,5 +22,4 @@
 R_V_LINE_TO, 2,
 H_LINE_TO, 4,
 V_LINE_TO, 7,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/network_ethernet.1x.icon b/ash/resources/vector_icons/network_ethernet.1x.icon
index 118076b..06e490e 100644
--- a/ash/resources/vector_icons/network_ethernet.1x.icon
+++ b/ash/resources/vector_icons/network_ethernet.1x.icon
@@ -36,5 +36,4 @@
 LINE_TO, 17, 10.5f,
 LINE_TO, 12.99f, 6,
 LINE_TO, 12, 6.77f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/network_ethernet.icon b/ash/resources/vector_icons/network_ethernet.icon
index ac773a1..2d03672 100644
--- a/ash/resources/vector_icons/network_ethernet.icon
+++ b/ash/resources/vector_icons/network_ethernet.icon
@@ -36,5 +36,4 @@
 LINE_TO, 34, 20,
 R_LINE_TO, -7.23f, -8,
 LINE_TO, 25, 13.37f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/network_mobile_not_connected_x.1x.icon b/ash/resources/vector_icons/network_mobile_not_connected_x.1x.icon
index cfd01f5..ed4b5087 100644
--- a/ash/resources/vector_icons/network_mobile_not_connected_x.1x.icon
+++ b/ash/resources/vector_icons/network_mobile_not_connected_x.1x.icon
@@ -15,5 +15,4 @@
 LINE_TO, 8.8f, 9.5f,
 R_LINE_TO, 0.71f, -0.7f,
 LINE_TO, 6.71f, 6,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/network_mobile_not_connected_x.icon b/ash/resources/vector_icons/network_mobile_not_connected_x.icon
index 5b3dc34..01e70a8 100644
--- a/ash/resources/vector_icons/network_mobile_not_connected_x.icon
+++ b/ash/resources/vector_icons/network_mobile_not_connected_x.icon
@@ -15,5 +15,4 @@
 R_LINE_TO, 5.75f, 5.75f,
 R_LINE_TO, 1.45f, -1.45f,
 LINE_TO, 13.45f, 12,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/network_vpn.1x.icon b/ash/resources/vector_icons/network_vpn.1x.icon
index f571630..4bb19e3 100644
--- a/ash/resources/vector_icons/network_vpn.1x.icon
+++ b/ash/resources/vector_icons/network_vpn.1x.icon
@@ -21,5 +21,4 @@
 CUBIC_TO_SHORTHAND, 5.56f, 8, 6.36f, 8,
 R_CUBIC_TO, 0.8f, 0, 1.45f, 0.68f, 1.45f, 1.5f,
 CUBIC_TO_SHORTHAND, 7.16f, 11, 6.36f, 11,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/network_vpn.icon b/ash/resources/vector_icons/network_vpn.icon
index 14ee56d..bf71962 100644
--- a/ash/resources/vector_icons/network_vpn.icon
+++ b/ash/resources/vector_icons/network_vpn.icon
@@ -21,5 +21,4 @@
 R_CUBIC_TO, 0, -1.65f, 1.31f, -3, 2.91f, -3,
 R_CUBIC_TO, 1.6f, 0, 2.91f, 1.35f, 2.91f, 3,
 R_CUBIC_TO, 0, 1.65f, -1.31f, 3, -2.91f, 3,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/notification_accessibility.icon b/ash/resources/vector_icons/notification_accessibility.icon
index f421616..7daef85 100644
--- a/ash/resources/vector_icons/notification_accessibility.icon
+++ b/ash/resources/vector_icons/notification_accessibility.icon
@@ -22,5 +22,4 @@
 R_V_LINE_TO, -8,
 R_H_LINE_TO, 72,
 R_V_LINE_TO, 8,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/notification_accessibility_braille.icon b/ash/resources/vector_icons/notification_accessibility_braille.icon
index da8f4451..203bc18 100644
--- a/ash/resources/vector_icons/notification_accessibility_braille.icon
+++ b/ash/resources/vector_icons/notification_accessibility_braille.icon
@@ -44,5 +44,4 @@
 R_CUBIC_TO, 0, -4.42f, -3.58f, -8, -8, -8,
 R_CUBIC_TO, -4.42f, 0, -8, 3.58f, -8, 8,
 R_CUBIC_TO, 0, 4.42f, 3.58f, 8, 8, 8,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/notification_battery_critical.icon b/ash/resources/vector_icons/notification_battery_critical.icon
index 392effe..48de6c91 100644
--- a/ash/resources/vector_icons/notification_battery_critical.icon
+++ b/ash/resources/vector_icons/notification_battery_critical.icon
@@ -40,5 +40,4 @@
 H_LINE_TO, 33,
 R_CUBIC_TO, -3.31f, 0, -6, -2.69f, -6, -6,
 V_LINE_TO, 72,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/notification_battery_fluctuating.icon b/ash/resources/vector_icons/notification_battery_fluctuating.icon
index 55987dd0..5de9b4e 100644
--- a/ash/resources/vector_icons/notification_battery_fluctuating.icon
+++ b/ash/resources/vector_icons/notification_battery_fluctuating.icon
@@ -46,5 +46,4 @@
 R_CUBIC_TO, 5.59f, 0, 10.28f, -2.99f, 11.94f, -7.13f,
 R_CUBIC_TO, 0.03f, 4.39f, -1.3f, 7.95f, -3.97f, 10.69f,
 CUBIC_TO, 80.35f, 46.63f, 76.91f, 48, 72.68f, 48,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/notification_battery_low.icon b/ash/resources/vector_icons/notification_battery_low.icon
index 392effe..48de6c91 100644
--- a/ash/resources/vector_icons/notification_battery_low.icon
+++ b/ash/resources/vector_icons/notification_battery_low.icon
@@ -40,5 +40,4 @@
 H_LINE_TO, 33,
 R_CUBIC_TO, -3.31f, 0, -6, -2.69f, -6, -6,
 V_LINE_TO, 72,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/notification_bluetooth.icon b/ash/resources/vector_icons/notification_bluetooth.icon
index e60c6c32e..42cf2c1b 100644
--- a/ash/resources/vector_icons/notification_bluetooth.icon
+++ b/ash/resources/vector_icons/notification_bluetooth.icon
@@ -34,5 +34,4 @@
 R_LINE_TO, 4.7f, 4.8f,
 R_LINE_TO, -4.7f, 4.8f,
 R_V_LINE_TO, -9.6f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/notification_bluetooth_battery_warning.icon b/ash/resources/vector_icons/notification_bluetooth_battery_warning.icon
index af8cf513..d5d94aa 100644
--- a/ash/resources/vector_icons/notification_bluetooth_battery_warning.icon
+++ b/ash/resources/vector_icons/notification_bluetooth_battery_warning.icon
@@ -66,5 +66,4 @@
 R_LINE_TO, -4.44f, 4.32f,
 R_V_LINE_TO, -8.65f,
 R_LINE_TO, 4.44f, 4.32f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/notification_capslock.icon b/ash/resources/vector_icons/notification_capslock.icon
index adc9730..3342321 100644
--- a/ash/resources/vector_icons/notification_capslock.icon
+++ b/ash/resources/vector_icons/notification_capslock.icon
@@ -26,5 +26,4 @@
 H_LINE_TO, 28,
 R_V_LINE_TO, 6,
 R_H_LINE_TO, 40,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/notification_center_all_done.icon b/ash/resources/vector_icons/notification_center_all_done.icon
index 64945ba2..830202c2 100644
--- a/ash/resources/vector_icons/notification_center_all_done.icon
+++ b/ash/resources/vector_icons/notification_center_all_done.icon
@@ -24,5 +24,4 @@
 R_LINE_TO, 2.82f, -2.82f,
 LINE_TO, 22, 26.34f,
 LINE_TO, 41.18f, 7.16f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/notification_center_clear_all.icon b/ash/resources/vector_icons/notification_center_clear_all.icon
index d44a3959a..9fdd51a 100644
--- a/ash/resources/vector_icons/notification_center_clear_all.icon
+++ b/ash/resources/vector_icons/notification_center_clear_all.icon
@@ -20,5 +20,4 @@
 R_H_LINE_TO, 24,
 R_V_LINE_TO, -4,
 H_LINE_TO, 12,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/notification_center_collapse.icon b/ash/resources/vector_icons/notification_center_collapse.icon
index c6c3ae2..712c430 100644
--- a/ash/resources/vector_icons/notification_center_collapse.icon
+++ b/ash/resources/vector_icons/notification_center_collapse.icon
@@ -9,5 +9,4 @@
 LINE_TO, 32, 15.05f,
 LINE_TO, 20, 28,
 LINE_TO, 8, 15.05f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/notification_center_do_not_disturb_off.icon b/ash/resources/vector_icons/notification_center_do_not_disturb_off.icon
index 89ea4240..c2cc68d0 100644
--- a/ash/resources/vector_icons/notification_center_do_not_disturb_off.icon
+++ b/ash/resources/vector_icons/notification_center_do_not_disturb_off.icon
@@ -29,5 +29,4 @@
 R_H_LINE_TO, 2.5f,
 R_LINE_TO, 3, 4,
 H_LINE_TO, 12,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/notification_center_do_not_disturb_on.icon b/ash/resources/vector_icons/notification_center_do_not_disturb_on.icon
index 04c1bb3..fa642b5f 100644
--- a/ash/resources/vector_icons/notification_center_do_not_disturb_on.icon
+++ b/ash/resources/vector_icons/notification_center_do_not_disturb_on.icon
@@ -14,5 +14,4 @@
 R_V_LINE_TO, -4,
 R_H_LINE_TO, 16,
 R_V_LINE_TO, 4,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/notification_center_empty.icon b/ash/resources/vector_icons/notification_center_empty.icon
index 470c6c0..c86965e 100644
--- a/ash/resources/vector_icons/notification_center_empty.icon
+++ b/ash/resources/vector_icons/notification_center_empty.icon
@@ -20,5 +20,4 @@
 R_CUBIC_TO, 0, 2.21f, 1.79f, 4, 4, 4,
 R_CUBIC_TO, 2.21f, 0, 4, -1.79f, 4, -4,
 R_CUBIC_TO, 0, -2.21f, -1.79f, -4, -4, -4,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/notification_center_settings.icon b/ash/resources/vector_icons/notification_center_settings.icon
index 1b9b193..30268cc 100644
--- a/ash/resources/vector_icons/notification_center_settings.icon
+++ b/ash/resources/vector_icons/notification_center_settings.icon
@@ -48,5 +48,4 @@
 R_CUBIC_TO, 0, -3.09f, 2.58f, -5.6f, 5.76f, -5.6f,
 R_CUBIC_TO, 3.17f, 0, 5.76f, 2.51f, 5.76f, 5.6f,
 R_CUBIC_TO, 0, 3.09f, -2.58f, 5.6f, -5.76f, 5.6f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/notification_charging_usb_c.icon b/ash/resources/vector_icons/notification_charging_usb_c.icon
index 00901903..98ac5957 100644
--- a/ash/resources/vector_icons/notification_charging_usb_c.icon
+++ b/ash/resources/vector_icons/notification_charging_usb_c.icon
@@ -34,5 +34,4 @@
 R_CUBIC_TO, -3.87f, 0, -7, -3.13f, -7, -7,
 V_LINE_TO, 36,
 R_CUBIC_TO, 0, -3.87f, 3.13f, -7, 7, -7,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/notification_chromevox.icon b/ash/resources/vector_icons/notification_chromevox.icon
index 3f3370d..8764241 100644
--- a/ash/resources/vector_icons/notification_chromevox.icon
+++ b/ash/resources/vector_icons/notification_chromevox.icon
@@ -38,5 +38,4 @@
 R_CUBIC_TO, -1.09f, -3.06f, -2.49f, -6.01f, -4.06f, -8.85f,
 R_CUBIC_TO, -2.63f, -4.77f, -4.74f, -9.81f, -7.68f, -14.42f,
 R_CUBIC_TO, -0.55f, -0.02f, -1.13f, -0.04f, -1.73f, -0.08f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/notification_keyboard.icon b/ash/resources/vector_icons/notification_keyboard.icon
index 7869427..fb722a9 100644
--- a/ash/resources/vector_icons/notification_keyboard.icon
+++ b/ash/resources/vector_icons/notification_keyboard.icon
@@ -78,5 +78,4 @@
 R_V_LINE_TO, -8,
 R_H_LINE_TO, 8,
 R_V_LINE_TO, 8,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/notification_low_power_charger.icon b/ash/resources/vector_icons/notification_low_power_charger.icon
index 55987dd0..5de9b4e 100644
--- a/ash/resources/vector_icons/notification_low_power_charger.icon
+++ b/ash/resources/vector_icons/notification_low_power_charger.icon
@@ -46,5 +46,4 @@
 R_CUBIC_TO, 5.59f, 0, 10.28f, -2.99f, 11.94f, -7.13f,
 R_CUBIC_TO, 0.03f, 4.39f, -1.3f, 7.95f, -3.97f, 10.69f,
 CUBIC_TO, 80.35f, 46.63f, 76.91f, 48, 72.68f, 48,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/notification_monitor_warning.icon b/ash/resources/vector_icons/notification_monitor_warning.icon
index bd17076..81420a9 100644
--- a/ash/resources/vector_icons/notification_monitor_warning.icon
+++ b/ash/resources/vector_icons/notification_monitor_warning.icon
@@ -38,5 +38,4 @@
 R_H_LINE_TO, 4,
 R_V_LINE_TO, -4,
 R_H_LINE_TO, -4,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/notification_screen.icon b/ash/resources/vector_icons/notification_screen.icon
index 1c94d63..250b1c10 100644
--- a/ash/resources/vector_icons/notification_screen.icon
+++ b/ash/resources/vector_icons/notification_screen.icon
@@ -22,5 +22,4 @@
 R_H_LINE_TO, 64,
 V_LINE_TO, 24,
 H_LINE_TO, 16,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/notification_screenshare.icon b/ash/resources/vector_icons/notification_screenshare.icon
index 248789d..8352493 100644
--- a/ash/resources/vector_icons/notification_screenshare.icon
+++ b/ash/resources/vector_icons/notification_screenshare.icon
@@ -26,5 +26,4 @@
 LINE_TO, 68, 48,
 LINE_TO, 53.46f, 63,
 V_LINE_TO, 52.62f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/notification_settings.icon b/ash/resources/vector_icons/notification_settings.icon
index 9b861f29..133f039 100644
--- a/ash/resources/vector_icons/notification_settings.icon
+++ b/ash/resources/vector_icons/notification_settings.icon
@@ -48,5 +48,4 @@
 R_CUBIC_TO, 0, -1.66f, 1.34f, -3, 3, -3,
 R_CUBIC_TO, 1.66f, 0, 3, 1.34f, 3, 3,
 R_CUBIC_TO, 0, 1.66f, -1.34f, 3, -3, 3,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/notification_sms_sync.icon b/ash/resources/vector_icons/notification_sms_sync.icon
index ea0b8778..26fc6f6 100644
--- a/ash/resources/vector_icons/notification_sms_sync.icon
+++ b/ash/resources/vector_icons/notification_sms_sync.icon
@@ -30,5 +30,4 @@
 R_V_LINE_TO, 8,
 R_H_LINE_TO, 18,
 R_V_LINE_TO, 10,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/notification_stylus_battery_warning.icon b/ash/resources/vector_icons/notification_stylus_battery_warning.icon
index 478d28aa5..6ed0b4c 100644
--- a/ash/resources/vector_icons/notification_stylus_battery_warning.icon
+++ b/ash/resources/vector_icons/notification_stylus_battery_warning.icon
@@ -68,5 +68,4 @@
 R_CUBIC_TO, -2.65f, 0, -4.8f, -2.39f, -4.8f, -5.33f,
 V_LINE_TO, 77,
 R_H_LINE_TO, 24,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/notification_supervised.icon b/ash/resources/vector_icons/notification_supervised.icon
index c3f490a..c4de8d59 100644
--- a/ash/resources/vector_icons/notification_supervised.icon
+++ b/ash/resources/vector_icons/notification_supervised.icon
@@ -25,5 +25,4 @@
 R_LINE_TO, 6.11f, -9.32f,
 LINE_TO, 76.8f, 38.41f,
 LINE_TO, 49.54f, 9.6f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/notification_timer.icon b/ash/resources/vector_icons/notification_timer.icon
index c98846d..25038b6 100644
--- a/ash/resources/vector_icons/notification_timer.icon
+++ b/ash/resources/vector_icons/notification_timer.icon
@@ -30,5 +30,4 @@
 R_CUBIC_TO, 0, -15.48f, 12.52f, -28, 28, -28,
 R_CUBIC_TO, 15.48f, 0, 28, 12.52f, 28, 28,
 R_CUBIC_TO, 0, 15.48f, -12.52f, 28, -28, 28,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/overview_text_filter_search.icon b/ash/resources/vector_icons/overview_text_filter_search.icon
index 60f612d..363f869 100644
--- a/ash/resources/vector_icons/overview_text_filter_search.icon
+++ b/ash/resources/vector_icons/overview_text_filter_search.icon
@@ -20,5 +20,4 @@
 R_ARC_TO, 3.6f, 3.6f, 0, 0, 1, 3.6f, -3.6f,
 R_ARC_TO, 3.6f, 3.6f, 0, 0, 1, 3.6f, 3.6f,
 R_ARC_TO, 3.6f, 3.6f, 0, 0, 1, -3.6f, 3.6f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/overview_window_close.icon b/ash/resources/vector_icons/overview_window_close.icon
index 07a9f48..4ee6ebb 100644
--- a/ash/resources/vector_icons/overview_window_close.icon
+++ b/ash/resources/vector_icons/overview_window_close.icon
@@ -15,5 +15,4 @@
 LINE_TO, 17.59f, 19,
 LINE_TO, 19, 17.59f,
 LINE_TO, 13.42f, 12,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/palette_action_capture_region.1x.icon b/ash/resources/vector_icons/palette_action_capture_region.1x.icon
index 7934c78..38166de 100644
--- a/ash/resources/vector_icons/palette_action_capture_region.1x.icon
+++ b/ash/resources/vector_icons/palette_action_capture_region.1x.icon
@@ -91,5 +91,4 @@
 R_CUBIC_TO, 1.1f, 0, 2, -0.9f, 2, -2,
 R_H_LINE_TO, -2,
 R_V_LINE_TO, 2,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/palette_action_capture_region.icon b/ash/resources/vector_icons/palette_action_capture_region.icon
index d08e5d9..ec36ff1c 100644
--- a/ash/resources/vector_icons/palette_action_capture_region.icon
+++ b/ash/resources/vector_icons/palette_action_capture_region.icon
@@ -91,5 +91,4 @@
 R_CUBIC_TO, 1.65f, 0, 3, -1.35f, 3, -3,
 R_H_LINE_TO, -3,
 R_V_LINE_TO, 3,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/palette_action_capture_screen.1x.icon b/ash/resources/vector_icons/palette_action_capture_screen.1x.icon
index 01a9fc0..e31838c 100644
--- a/ash/resources/vector_icons/palette_action_capture_screen.1x.icon
+++ b/ash/resources/vector_icons/palette_action_capture_screen.1x.icon
@@ -79,5 +79,4 @@
 LINE_TO, 17, 15.5f,
 LINE_TO, 14.5f, 13,
 LINE_TO, 13, 14.5f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/palette_action_capture_screen.icon b/ash/resources/vector_icons/palette_action_capture_screen.icon
index 3e23bd0f..58384359 100644
--- a/ash/resources/vector_icons/palette_action_capture_screen.icon
+++ b/ash/resources/vector_icons/palette_action_capture_screen.icon
@@ -79,5 +79,4 @@
 R_V_LINE_TO, 4.49f,
 R_LINE_TO, -4.5f, -4.1f,
 R_LINE_TO, -2.38f, 2.29f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/palette_action_create_note.1x.icon b/ash/resources/vector_icons/palette_action_create_note.1x.icon
index 5668b89..5130810 100644
--- a/ash/resources/vector_icons/palette_action_create_note.1x.icon
+++ b/ash/resources/vector_icons/palette_action_create_note.1x.icon
@@ -31,5 +31,4 @@
 R_V_LINE_TO, 2,
 R_LINE_TO, 2, 0.02f,
 R_V_LINE_TO, 2.02f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/palette_action_create_note.icon b/ash/resources/vector_icons/palette_action_create_note.icon
index 3e009ae..7fff6de 100644
--- a/ash/resources/vector_icons/palette_action_create_note.icon
+++ b/ash/resources/vector_icons/palette_action_create_note.icon
@@ -31,5 +31,4 @@
 R_V_LINE_TO, 4.5f,
 H_LINE_TO, 26,
 R_V_LINE_TO, 3,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/palette_mode_laser_pointer.1x.icon b/ash/resources/vector_icons/palette_mode_laser_pointer.1x.icon
index 103cd67..da1e02f 100644
--- a/ash/resources/vector_icons/palette_mode_laser_pointer.1x.icon
+++ b/ash/resources/vector_icons/palette_mode_laser_pointer.1x.icon
@@ -39,5 +39,4 @@
 R_LINE_TO, 0.01f, -0.01f,
 R_CUBIC_TO, 0.16f, -0.11f, 0.32f, -0.24f, 0.45f, -0.38f,
 CUBIC_TO, 8.67f, 17.56f, 9, 16.82f, 9, 16,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/palette_mode_laser_pointer.icon b/ash/resources/vector_icons/palette_mode_laser_pointer.icon
index 8a0139b..7fbb157 100644
--- a/ash/resources/vector_icons/palette_mode_laser_pointer.icon
+++ b/ash/resources/vector_icons/palette_mode_laser_pointer.icon
@@ -38,5 +38,4 @@
 R_LINE_TO, 0.02f, -0.01f,
 R_CUBIC_TO, 0.33f, -0.22f, 0.63f, -0.48f, 0.91f, -0.76f,
 CUBIC_TO, 17.34f, 35.69f, 18, 34.21f, 18, 32.57f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/palette_mode_magnify.1x.icon b/ash/resources/vector_icons/palette_mode_magnify.1x.icon
index fe3d5fa..d78a6bd 100644
--- a/ash/resources/vector_icons/palette_mode_magnify.1x.icon
+++ b/ash/resources/vector_icons/palette_mode_magnify.1x.icon
@@ -32,5 +32,4 @@
 R_CUBIC_TO, 0, 2.76f, 2.24f, 5, 5, 5,
 R_CUBIC_TO, 2.76f, 0, 5, -2.24f, 5, -5,
 R_CUBIC_TO, 0, -2.76f, -2.24f, -5, -5, -5,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/palette_mode_magnify.icon b/ash/resources/vector_icons/palette_mode_magnify.icon
index 53f1c380..9dc94580 100644
--- a/ash/resources/vector_icons/palette_mode_magnify.icon
+++ b/ash/resources/vector_icons/palette_mode_magnify.icon
@@ -32,5 +32,4 @@
 R_CUBIC_TO, 0, 5.51f, 4.49f, 10, 10, 10,
 R_CUBIC_TO, 5.51f, 0, 10, -4.49f, 10, -10,
 R_CUBIC_TO, 0, -5.51f, -4.49f, -10, -10, -10,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/palette_mode_metalayer.1x.icon b/ash/resources/vector_icons/palette_mode_metalayer.1x.icon
index 787ebf33..af625a90 100644
--- a/ash/resources/vector_icons/palette_mode_metalayer.1x.icon
+++ b/ash/resources/vector_icons/palette_mode_metalayer.1x.icon
@@ -23,5 +23,4 @@
 CUBIC_TO, 4.12f, 2.92f, 2.21f, 4.83f, 2.21f, 7.19f,
 CUBIC_TO, 2.21f, 9.55f, 4.12f, 11.46f, 6.48f, 11.46f,
 CUBIC_TO, 8.83f, 11.46f, 10.74f, 9.55f, 10.74f, 7.19f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/palette_mode_metalayer.icon b/ash/resources/vector_icons/palette_mode_metalayer.icon
index 3f9b3c8..30f7b153 100644
--- a/ash/resources/vector_icons/palette_mode_metalayer.icon
+++ b/ash/resources/vector_icons/palette_mode_metalayer.icon
@@ -23,5 +23,4 @@
 CUBIC_TO, 8.24f, 5.84f, 4.42f, 9.66f, 4.42f, 14.38f,
 CUBIC_TO, 4.42f, 19.09f, 8.24f, 22.91f, 12.96f, 22.91f,
 CUBIC_TO, 17.67f, 22.91f, 21.49f, 19.09f, 21.49f, 14.38f,
-CLOSE,
-END
\ No newline at end of file
+CLOSE
diff --git a/ash/resources/vector_icons/palette_tray_icon_capture_region.1x.icon b/ash/resources/vector_icons/palette_tray_icon_capture_region.1x.icon
index 7e79e42f..fc023d8 100644
--- a/ash/resources/vector_icons/palette_tray_icon_capture_region.1x.icon
+++ b/ash/resources/vector_icons/palette_tray_icon_capture_region.1x.icon
@@ -91,5 +91,4 @@
 R_CUBIC_TO, 0.83f, 0, 1.5f, -0.67f, 1.5f, -1.5f,
 H_LINE_TO, 13,
 V_LINE_TO, 14,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/palette_tray_icon_capture_region.icon b/ash/resources/vector_icons/palette_tray_icon_capture_region.icon
index 6084e354..e625132 100644
--- a/ash/resources/vector_icons/palette_tray_icon_capture_region.icon
+++ b/ash/resources/vector_icons/palette_tray_icon_capture_region.icon
@@ -91,5 +91,4 @@
 R_CUBIC_TO, 1.65f, 0, 3, -1.35f, 3, -3,
 R_H_LINE_TO, -3,
 R_V_LINE_TO, 3,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/palette_tray_icon_default.1x.icon b/ash/resources/vector_icons/palette_tray_icon_default.1x.icon
index 9fbd3357..4fc848e9 100644
--- a/ash/resources/vector_icons/palette_tray_icon_default.1x.icon
+++ b/ash/resources/vector_icons/palette_tray_icon_default.1x.icon
@@ -24,5 +24,4 @@
 R_LINE_TO, 5.03f, -5.02f,
 R_LINE_TO, -2.5f, -2.5f,
 LINE_TO, 2, 11.5f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/palette_tray_icon_default.icon b/ash/resources/vector_icons/palette_tray_icon_default.icon
index 05da1c7e..6a13e8b 100644
--- a/ash/resources/vector_icons/palette_tray_icon_default.icon
+++ b/ash/resources/vector_icons/palette_tray_icon_default.icon
@@ -24,5 +24,4 @@
 R_LINE_TO, 10.05f, -10.04f,
 R_LINE_TO, -5, -5,
 LINE_TO, 4, 23,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/palette_tray_icon_laser_pointer.1x.icon b/ash/resources/vector_icons/palette_tray_icon_laser_pointer.1x.icon
index c14a706..640bf3a 100644
--- a/ash/resources/vector_icons/palette_tray_icon_laser_pointer.1x.icon
+++ b/ash/resources/vector_icons/palette_tray_icon_laser_pointer.1x.icon
@@ -38,5 +38,4 @@
 R_LINE_TO, 0.01f, 0,
 R_CUBIC_TO, 0.13f, -0.09f, 0.25f, -0.19f, 0.36f, -0.3f,
 R_CUBIC_TO, 0.43f, -0.43f, 0.69f, -1.02f, 0.69f, -1.68f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/palette_tray_icon_laser_pointer.icon b/ash/resources/vector_icons/palette_tray_icon_laser_pointer.icon
index f853141..66f7e02 100644
--- a/ash/resources/vector_icons/palette_tray_icon_laser_pointer.icon
+++ b/ash/resources/vector_icons/palette_tray_icon_laser_pointer.icon
@@ -38,5 +38,4 @@
 R_LINE_TO, 0.02f, -0.01f,
 R_CUBIC_TO, 0.26f, -0.18f, 0.51f, -0.38f, 0.73f, -0.61f,
 R_CUBIC_TO, 0.85f, -0.87f, 1.38f, -2.05f, 1.38f, -3.36f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/palette_tray_icon_magnify.1x.icon b/ash/resources/vector_icons/palette_tray_icon_magnify.1x.icon
index ec89944f..fd09e3d 100644
--- a/ash/resources/vector_icons/palette_tray_icon_magnify.1x.icon
+++ b/ash/resources/vector_icons/palette_tray_icon_magnify.1x.icon
@@ -32,5 +32,4 @@
 R_CUBIC_TO, 0, 2.21f, 1.79f, 4, 4, 4,
 R_CUBIC_TO, 2.2f, 0, 4, -1.79f, 4, -4,
 R_CUBIC_TO, 0, -2.21f, -1.8f, -4, -4, -4,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/palette_tray_icon_magnify.icon b/ash/resources/vector_icons/palette_tray_icon_magnify.icon
index 317e26f..229edf3 100644
--- a/ash/resources/vector_icons/palette_tray_icon_magnify.icon
+++ b/ash/resources/vector_icons/palette_tray_icon_magnify.icon
@@ -32,5 +32,4 @@
 R_CUBIC_TO, 0, 4.41f, 3.59f, 8, 8, 8,
 R_CUBIC_TO, 4.41f, 0, 8, -3.59f, 8, -8,
 R_CUBIC_TO, 0, -4.41f, -3.59f, -8, -8, -8,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/palette_tray_icon_metalayer.1x.icon b/ash/resources/vector_icons/palette_tray_icon_metalayer.1x.icon
index 2116990..cda823b 100644
--- a/ash/resources/vector_icons/palette_tray_icon_metalayer.1x.icon
+++ b/ash/resources/vector_icons/palette_tray_icon_metalayer.1x.icon
@@ -23,5 +23,4 @@
 CUBIC_TO, 3.3f, 2.34f, 1.77f, 3.87f, 1.77f, 5.75f,
 CUBIC_TO, 1.77f, 7.64f, 3.3f, 9.16f, 5.18f, 9.16f,
 CUBIC_TO, 7.07f, 9.16f, 8.6f, 7.64f, 8.6f, 5.75f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/palette_tray_icon_metalayer.icon b/ash/resources/vector_icons/palette_tray_icon_metalayer.icon
index 326b4430..485fe19 100644
--- a/ash/resources/vector_icons/palette_tray_icon_metalayer.icon
+++ b/ash/resources/vector_icons/palette_tray_icon_metalayer.icon
@@ -23,5 +23,4 @@
 CUBIC_TO, 6.59f, 4.68f, 3.54f, 7.73f, 3.54f, 11.5f,
 CUBIC_TO, 3.54f, 15.27f, 6.59f, 18.33f, 10.36f, 18.33f,
 CUBIC_TO, 14.13f, 18.33f, 17.19f, 15.27f, 17.19f, 11.5f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/shelf_add_person_button.1x.icon b/ash/resources/vector_icons/shelf_add_person_button.1x.icon
index f0833e4..8ddc616f 100644
--- a/ash/resources/vector_icons/shelf_add_person_button.1x.icon
+++ b/ash/resources/vector_icons/shelf_add_person_button.1x.icon
@@ -25,5 +25,4 @@
 R_CUBIC_TO, 0.62f, 0, 1.22f, -0.07f, 1.8f, -0.21f,
 R_CUBIC_TO, 0.17f, 0.57f, 0.26f, 1.18f, 0.26f, 1.81f,
 R_CUBIC_TO, 0, 3.53f, -2.87f, 6.4f, -6.4f, 6.4f,
-CLOSE,
-END
\ No newline at end of file
+CLOSE
diff --git a/ash/resources/vector_icons/shelf_add_person_button.icon b/ash/resources/vector_icons/shelf_add_person_button.icon
index 6a49c948..0095061 100644
--- a/ash/resources/vector_icons/shelf_add_person_button.icon
+++ b/ash/resources/vector_icons/shelf_add_person_button.icon
@@ -25,5 +25,4 @@
 R_CUBIC_TO, 1.25f, 0, 2.45f, -0.14f, 3.6f, -0.42f,
 R_CUBIC_TO, 0.34f, 1.14f, 0.53f, 2.35f, 0.53f, 3.62f,
 R_CUBIC_TO, 0, 7.06f, -5.74f, 12.8f, -12.8f, 12.8f,
-CLOSE,
-END
\ No newline at end of file
+CLOSE
diff --git a/ash/resources/vector_icons/shelf_back.1x.icon b/ash/resources/vector_icons/shelf_back.1x.icon
index fe152e3..01836db5 100644
--- a/ash/resources/vector_icons/shelf_back.1x.icon
+++ b/ash/resources/vector_icons/shelf_back.1x.icon
@@ -14,5 +14,4 @@
 R_LINE_TO, 6.9f, -7,
 LINE_TO, 10, 2.2f,
 LINE_TO, 5.2f, 7,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/shelf_back.icon b/ash/resources/vector_icons/shelf_back.icon
index 193bf72..2b21689 100644
--- a/ash/resources/vector_icons/shelf_back.icon
+++ b/ash/resources/vector_icons/shelf_back.icon
@@ -13,5 +13,4 @@
 R_LINE_TO, -9.86f, 9.99f,
 H_LINE_TO, 29,
 R_V_LINE_TO, 3,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/shelf_browse_as_guest_button.1x.icon b/ash/resources/vector_icons/shelf_browse_as_guest_button.1x.icon
index 1f37af71..65e2be2 100644
--- a/ash/resources/vector_icons/shelf_browse_as_guest_button.1x.icon
+++ b/ash/resources/vector_icons/shelf_browse_as_guest_button.1x.icon
@@ -16,5 +16,4 @@
 R_CUBIC_TO, 1.66f, 0, 4.97f, 0.95f, 5, 2.69f,
 R_CUBIC_TO, -1.07f, 1.69f, -2.92f, 2.81f, -5, 2.81f,
 R_CUBIC_TO, -2.08f, 0, -3.92f, -1.12f, -5, -2.81f,
-CLOSE,
-END
\ No newline at end of file
+CLOSE
diff --git a/ash/resources/vector_icons/shelf_browse_as_guest_button.icon b/ash/resources/vector_icons/shelf_browse_as_guest_button.icon
index 3f7b0473..7e8882f 100644
--- a/ash/resources/vector_icons/shelf_browse_as_guest_button.icon
+++ b/ash/resources/vector_icons/shelf_browse_as_guest_button.icon
@@ -16,5 +16,4 @@
 R_CUBIC_TO, 3.32f, 0, 9.95f, 1.9f, 10, 5.38f,
 CUBIC_TO, 27.85f, 29.77f, 24.17f, 32, 20, 32,
 R_CUBIC_TO, -4.17f, 0, -7.85f, -2.23f, -10, -5.62f,
-CLOSE,
-END
\ No newline at end of file
+CLOSE
diff --git a/ash/resources/vector_icons/shelf_cancel_button.1x.icon b/ash/resources/vector_icons/shelf_cancel_button.1x.icon
index bb20d0d..afb813a 100644
--- a/ash/resources/vector_icons/shelf_cancel_button.1x.icon
+++ b/ash/resources/vector_icons/shelf_cancel_button.1x.icon
@@ -9,5 +9,4 @@
 R_CUBIC_TO, 2.94f, 0, 5.44f, 2.05f, 6.31f, 4.89f,
 LINE_TO, 18, 12.31f,
 CUBIC_TO, 16.85f, 8.58f, 13.58f, 5.89f, 9.72f, 5.89f,
-CLOSE,
-END
\ No newline at end of file
+CLOSE
diff --git a/ash/resources/vector_icons/shelf_cancel_button.icon b/ash/resources/vector_icons/shelf_cancel_button.icon
index 38097bbb..049be591 100644
--- a/ash/resources/vector_icons/shelf_cancel_button.icon
+++ b/ash/resources/vector_icons/shelf_cancel_button.icon
@@ -9,5 +9,4 @@
 R_CUBIC_TO, 5.88f, 0, 10.88f, 3.85f, 12.62f, 9.17f,
 LINE_TO, 37, 24.7f,
 R_CUBIC_TO, -2.31f, -6.98f, -8.84f, -12.03f, -16.56f, -12.03f,
-CLOSE,
-END
\ No newline at end of file
+CLOSE
diff --git a/ash/resources/vector_icons/shelf_keyboard.1x.icon b/ash/resources/vector_icons/shelf_keyboard.1x.icon
index 16f2a693..f1e2695 100644
--- a/ash/resources/vector_icons/shelf_keyboard.1x.icon
+++ b/ash/resources/vector_icons/shelf_keyboard.1x.icon
@@ -78,5 +78,4 @@
 R_H_LINE_TO, 5,
 R_V_LINE_TO, 1,
 H_LINE_TO, 6,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/shelf_keyboard.icon b/ash/resources/vector_icons/shelf_keyboard.icon
index 6875e8e..a7baa914 100644
--- a/ash/resources/vector_icons/shelf_keyboard.icon
+++ b/ash/resources/vector_icons/shelf_keyboard.icon
@@ -78,5 +78,4 @@
 R_V_LINE_TO, -3,
 R_H_LINE_TO, 3,
 R_V_LINE_TO, 3,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/shelf_logout.1x.icon b/ash/resources/vector_icons/shelf_logout.1x.icon
index a2e068f3..87915739 100644
--- a/ash/resources/vector_icons/shelf_logout.1x.icon
+++ b/ash/resources/vector_icons/shelf_logout.1x.icon
@@ -31,5 +31,4 @@
 R_V_LINE_TO, -8.9f,
 CUBIC_TO, 15, 2, 13.96f, 1.03f, 12.46f, 1.03f,
 R_H_LINE_TO, -8.9f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/shelf_logout.icon b/ash/resources/vector_icons/shelf_logout.icon
index d695acc..aeca144b 100644
--- a/ash/resources/vector_icons/shelf_logout.icon
+++ b/ash/resources/vector_icons/shelf_logout.icon
@@ -31,5 +31,4 @@
 V_LINE_TO, 6.33f,
 CUBIC_TO, 29, 4.5f, 27.5f, 3, 25.67f, 3,
 H_LINE_TO, 6,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/shelf_notifications.1x.icon b/ash/resources/vector_icons/shelf_notifications.1x.icon
index 9c194d0..9ecfd7d 100644
--- a/ash/resources/vector_icons/shelf_notifications.1x.icon
+++ b/ash/resources/vector_icons/shelf_notifications.1x.icon
@@ -22,5 +22,4 @@
 R_H_LINE_TO, 10,
 R_V_LINE_TO, -0.71f,
 LINE_TO, 12, 10.1f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/shelf_notifications.icon b/ash/resources/vector_icons/shelf_notifications.icon
index 5f5989d..780a14d0 100644
--- a/ash/resources/vector_icons/shelf_notifications.icon
+++ b/ash/resources/vector_icons/shelf_notifications.icon
@@ -22,5 +22,4 @@
 R_H_LINE_TO, 22,
 R_V_LINE_TO, -1.5f,
 LINE_TO, 24, 21,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/shelf_overflow.1x.icon b/ash/resources/vector_icons/shelf_overflow.1x.icon
index 6caccb9..a13a532 100644
--- a/ash/resources/vector_icons/shelf_overflow.1x.icon
+++ b/ash/resources/vector_icons/shelf_overflow.1x.icon
@@ -15,5 +15,4 @@
 R_CUBIC_TO, 0.46f, 0, 0.83f, -0.38f, 0.83f, -0.86f,
 R_ARC_TO, 0.87f, 0.87f, 0, 0, 0, -0.24f, -0.61f,
 LINE_TO, 8.59f, 5.25f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/shelf_overflow.icon b/ash/resources/vector_icons/shelf_overflow.icon
index 00b4db1..7886947 100644
--- a/ash/resources/vector_icons/shelf_overflow.icon
+++ b/ash/resources/vector_icons/shelf_overflow.icon
@@ -16,5 +16,4 @@
 R_CUBIC_TO, 0.92f, 0, 1.67f, -0.77f, 1.67f, -1.71f,
 R_CUBIC_TO, 0, -0.47f, -0.19f, -0.9f, -0.49f, -1.21f,
 R_LINE_TO, -8.33f, -8.57f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/shelf_overview.1x.icon b/ash/resources/vector_icons/shelf_overview.1x.icon
index 1a6790c..bc606772 100644
--- a/ash/resources/vector_icons/shelf_overview.1x.icon
+++ b/ash/resources/vector_icons/shelf_overview.1x.icon
@@ -26,5 +26,4 @@
 R_V_LINE_TO, 8,
 R_H_LINE_TO, -1,
 V_LINE_TO, 4,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/shelf_overview.icon b/ash/resources/vector_icons/shelf_overview.icon
index 17f9031..b3b6e65 100644
--- a/ash/resources/vector_icons/shelf_overview.icon
+++ b/ash/resources/vector_icons/shelf_overview.icon
@@ -26,5 +26,4 @@
 R_V_LINE_TO, 18,
 R_H_LINE_TO, -3,
 V_LINE_TO, 7,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/shelf_shutdown_button.1x.icon b/ash/resources/vector_icons/shelf_shutdown_button.1x.icon
index 89e91cf..b6f277af 100644
--- a/ash/resources/vector_icons/shelf_shutdown_button.1x.icon
+++ b/ash/resources/vector_icons/shelf_shutdown_button.1x.icon
@@ -16,5 +16,4 @@
 R_CUBIC_TO, 0, 4.14f, 3.36f, 7.5f, 7.5f, 7.5f,
 R_CUBIC_TO, 4.14f, 0, 7.5f, -3.36f, 7.5f, -7.5f,
 R_CUBIC_TO, 0, -2.28f, -1.02f, -4.32f, -2.64f, -5.69f,
-CLOSE,
-END
\ No newline at end of file
+CLOSE
diff --git a/ash/resources/vector_icons/shelf_shutdown_button.icon b/ash/resources/vector_icons/shelf_shutdown_button.icon
index e177d6d..c7a3582 100644
--- a/ash/resources/vector_icons/shelf_shutdown_button.icon
+++ b/ash/resources/vector_icons/shelf_shutdown_button.icon
@@ -16,5 +16,4 @@
 R_CUBIC_TO, 0, 8.28f, 6.72f, 15, 15, 15,
 R_CUBIC_TO, 8.28f, 0, 15, -6.72f, 15, -15,
 R_CUBIC_TO, 0, -4.57f, -2.05f, -8.63f, -5.28f, -11.38f,
-CLOSE,
-END
\ No newline at end of file
+CLOSE
diff --git a/ash/resources/vector_icons/shelf_sign_out_button.1x.icon b/ash/resources/vector_icons/shelf_sign_out_button.1x.icon
index c2c4819..0d2816b 100644
--- a/ash/resources/vector_icons/shelf_sign_out_button.1x.icon
+++ b/ash/resources/vector_icons/shelf_sign_out_button.1x.icon
@@ -27,5 +27,4 @@
 V_LINE_TO, 4,
 R_CUBIC_TO, 0, -1, -1.02f, -2, -2, -2,
 H_LINE_TO, 4,
-CLOSE,
-END
\ No newline at end of file
+CLOSE
diff --git a/ash/resources/vector_icons/shelf_sign_out_button.icon b/ash/resources/vector_icons/shelf_sign_out_button.icon
index 8b7ac52..cb67a00 100644
--- a/ash/resources/vector_icons/shelf_sign_out_button.icon
+++ b/ash/resources/vector_icons/shelf_sign_out_button.icon
@@ -27,5 +27,4 @@
 V_LINE_TO, 8.33f,
 CUBIC_TO, 35, 6.5f, 33.5f, 5, 31.67f, 5,
 H_LINE_TO, 8.33f,
-CLOSE,
-END
\ No newline at end of file
+CLOSE
diff --git a/ash/resources/vector_icons/shelf_unlock_button.1x.icon b/ash/resources/vector_icons/shelf_unlock_button.1x.icon
index 5dbfa40..6f02f39 100644
--- a/ash/resources/vector_icons/shelf_unlock_button.1x.icon
+++ b/ash/resources/vector_icons/shelf_unlock_button.1x.icon
@@ -28,5 +28,4 @@
 V_LINE_TO, 10,
 R_H_LINE_TO, 12,
 R_V_LINE_TO, 10,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/shelf_unlock_button.icon b/ash/resources/vector_icons/shelf_unlock_button.icon
index 93f4156..05d82af 100644
--- a/ash/resources/vector_icons/shelf_unlock_button.icon
+++ b/ash/resources/vector_icons/shelf_unlock_button.icon
@@ -28,5 +28,4 @@
 V_LINE_TO, 20,
 R_H_LINE_TO, 24,
 R_V_LINE_TO, 20,
-CLOSE,
-END
\ No newline at end of file
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_accessibility.1x.icon b/ash/resources/vector_icons/system_menu_accessibility.1x.icon
index bd185994b..1db087d 100644
--- a/ash/resources/vector_icons/system_menu_accessibility.1x.icon
+++ b/ash/resources/vector_icons/system_menu_accessibility.1x.icon
@@ -21,5 +21,4 @@
 MOVE_TO, 10, 5,
 R_ARC_TO, 2, 2, 0, 1, 0, 0, -4,
 R_ARC_TO, 2, 2, 0, 0, 0, 0, 4,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_accessibility.icon b/ash/resources/vector_icons/system_menu_accessibility.icon
index 11bae49..c5033fb1 100644
--- a/ash/resources/vector_icons/system_menu_accessibility.icon
+++ b/ash/resources/vector_icons/system_menu_accessibility.icon
@@ -21,5 +21,4 @@
 R_MOVE_TO, 0, -2,
 R_ARC_TO, 3.5f, 3.5f, 0, 1, 0, 0, -7,
 R_ARC_TO, 3.5f, 3.5f, 0, 0, 0, 0, 7,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_accessibility_auto_click.1x.icon b/ash/resources/vector_icons/system_menu_accessibility_auto_click.1x.icon
index 2d2f1bb..85c15d8e 100644
--- a/ash/resources/vector_icons/system_menu_accessibility_auto_click.1x.icon
+++ b/ash/resources/vector_icons/system_menu_accessibility_auto_click.1x.icon
@@ -44,5 +44,4 @@
 V_LINE_TO, 2,
 R_H_LINE_TO, 1,
 R_V_LINE_TO, 1,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_accessibility_auto_click.icon b/ash/resources/vector_icons/system_menu_accessibility_auto_click.icon
index 9545200..b81c373 100644
--- a/ash/resources/vector_icons/system_menu_accessibility_auto_click.icon
+++ b/ash/resources/vector_icons/system_menu_accessibility_auto_click.icon
@@ -37,5 +37,4 @@
 R_V_LINE_TO, -1.94f,
 R_CUBIC_TO, 2.86f, 0, 5.17f, -2.31f, 5.17f, -5.17f,
 R_CUBIC_TO, 0, -1.01f, -0.3f, -1.96f, -0.8f, -2.75f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_accessibility_chromevox.1x.icon b/ash/resources/vector_icons/system_menu_accessibility_chromevox.1x.icon
index 97e8c052..0720f3b 100644
--- a/ash/resources/vector_icons/system_menu_accessibility_chromevox.1x.icon
+++ b/ash/resources/vector_icons/system_menu_accessibility_chromevox.1x.icon
@@ -38,5 +38,4 @@
 R_CUBIC_TO, -0.22f, -0.61f, -0.5f, -1.2f, -0.81f, -1.77f,
 R_CUBIC_TO, -0.53f, -0.95f, -0.95f, -1.96f, -1.54f, -2.88f,
 LINE_TO, 8.42f, 3.67f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_accessibility_chromevox.icon b/ash/resources/vector_icons/system_menu_accessibility_chromevox.icon
index 2626248..319b8bee 100644
--- a/ash/resources/vector_icons/system_menu_accessibility_chromevox.icon
+++ b/ash/resources/vector_icons/system_menu_accessibility_chromevox.icon
@@ -38,5 +38,4 @@
 R_CUBIC_TO, -0.43f, -1.23f, -0.99f, -2.4f, -1.62f, -3.54f,
 R_CUBIC_TO, -1.05f, -1.91f, -1.89f, -3.93f, -3.07f, -5.77f,
 R_CUBIC_TO, -0.22f, -0.01f, -0.45f, -0.02f, -0.69f, -0.03f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_accessibility_contrast.1x.icon b/ash/resources/vector_icons/system_menu_accessibility_contrast.1x.icon
index e607728..974f9352 100644
--- a/ash/resources/vector_icons/system_menu_accessibility_contrast.1x.icon
+++ b/ash/resources/vector_icons/system_menu_accessibility_contrast.1x.icon
@@ -13,5 +13,4 @@
 R_CUBIC_TO, 3.38f, 0, 6.12f, 2.74f, 6.12f, 6.12f,
 R_CUBIC_TO, 0, 3.38f, -2.74f, 6.12f, -6.12f, 6.12f,
 V_LINE_TO, 3.88f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_accessibility_contrast.icon b/ash/resources/vector_icons/system_menu_accessibility_contrast.icon
index 94bdd469f..c5f5813 100644
--- a/ash/resources/vector_icons/system_menu_accessibility_contrast.icon
+++ b/ash/resources/vector_icons/system_menu_accessibility_contrast.icon
@@ -13,5 +13,4 @@
 R_CUBIC_TO, 6.76f, 0, 12.24f, 5.48f, 12.24f, 12.24f,
 CUBIC_TO_SHORTHAND, 26.76f, 32.24f, 20, 32.24f,
 V_LINE_TO, 7.77f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_accessibility_docked_magnifier.1x.icon b/ash/resources/vector_icons/system_menu_accessibility_docked_magnifier.1x.icon
index 07b01daf..cb822666 100644
--- a/ash/resources/vector_icons/system_menu_accessibility_docked_magnifier.1x.icon
+++ b/ash/resources/vector_icons/system_menu_accessibility_docked_magnifier.1x.icon
@@ -32,5 +32,4 @@
 LINE_TO, 16, 8,
 LINE_TO, 16, 9,
 LINE_TO, 14, 9,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_accessibility_docked_magnifier.icon b/ash/resources/vector_icons/system_menu_accessibility_docked_magnifier.icon
index d2bc59b..b0f1f77 100644
--- a/ash/resources/vector_icons/system_menu_accessibility_docked_magnifier.icon
+++ b/ash/resources/vector_icons/system_menu_accessibility_docked_magnifier.icon
@@ -32,5 +32,4 @@
 LINE_TO, 33, 14,
 LINE_TO, 33, 16,
 LINE_TO, 30, 16,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_accessibility_fullscreen_magnifier.1x.icon b/ash/resources/vector_icons/system_menu_accessibility_fullscreen_magnifier.1x.icon
index 2f9bbc0..e266dbdd 100644
--- a/ash/resources/vector_icons/system_menu_accessibility_fullscreen_magnifier.1x.icon
+++ b/ash/resources/vector_icons/system_menu_accessibility_fullscreen_magnifier.1x.icon
@@ -32,5 +32,4 @@
 LINE_TO, 16, 8,
 LINE_TO, 16, 9,
 LINE_TO, 14, 9,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_accessibility_fullscreen_magnifier.icon b/ash/resources/vector_icons/system_menu_accessibility_fullscreen_magnifier.icon
index a1a64d0..5bd7acb 100644
--- a/ash/resources/vector_icons/system_menu_accessibility_fullscreen_magnifier.icon
+++ b/ash/resources/vector_icons/system_menu_accessibility_fullscreen_magnifier.icon
@@ -32,5 +32,4 @@
 LINE_TO, 33, 14,
 LINE_TO, 33, 16,
 LINE_TO, 30, 16,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_accessibility_select_to_speak.1x.icon b/ash/resources/vector_icons/system_menu_accessibility_select_to_speak.1x.icon
index d3c43ef..12336cc 100644
--- a/ash/resources/vector_icons/system_menu_accessibility_select_to_speak.1x.icon
+++ b/ash/resources/vector_icons/system_menu_accessibility_select_to_speak.1x.icon
@@ -47,5 +47,4 @@
 LINE_TO, 10.89f, 14,
 CUBIC_TO, 12.67f, 13.58f, 14, 11.95f, 14, 10,
 CUBIC_TO, 14, 8.05f, 12.67f, 6.42f, 10.89f, 6,
-CLOSE,
-END
\ No newline at end of file
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_accessibility_select_to_speak.icon b/ash/resources/vector_icons/system_menu_accessibility_select_to_speak.icon
index 756a7da..bdbc301c 100644
--- a/ash/resources/vector_icons/system_menu_accessibility_select_to_speak.icon
+++ b/ash/resources/vector_icons/system_menu_accessibility_select_to_speak.icon
@@ -47,5 +47,4 @@
 LINE_TO, 21.78f, 28,
 CUBIC_TO, 25.34f, 27.17f, 28, 23.9f, 28, 20,
 CUBIC_TO, 28, 16.1f, 25.34f, 12.83f, 21.78f, 12,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_add_connection.1x.icon b/ash/resources/vector_icons/system_menu_add_connection.1x.icon
index 5d11a0a..534bcfbd 100644
--- a/ash/resources/vector_icons/system_menu_add_connection.1x.icon
+++ b/ash/resources/vector_icons/system_menu_add_connection.1x.icon
@@ -22,5 +22,4 @@
 R_V_LINE_TO, 2,
 R_H_LINE_TO, 4,
 R_V_LINE_TO, 4,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_add_connection.icon b/ash/resources/vector_icons/system_menu_add_connection.icon
index c2b7fe4a..33d74ed 100644
--- a/ash/resources/vector_icons/system_menu_add_connection.icon
+++ b/ash/resources/vector_icons/system_menu_add_connection.icon
@@ -22,5 +22,4 @@
 R_V_LINE_TO, 4,
 R_H_LINE_TO, 7,
 R_V_LINE_TO, 7,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_arrow_back.1x.icon b/ash/resources/vector_icons/system_menu_arrow_back.1x.icon
index 7ac36be4..d45b7e6 100644
--- a/ash/resources/vector_icons/system_menu_arrow_back.1x.icon
+++ b/ash/resources/vector_icons/system_menu_arrow_back.1x.icon
@@ -12,5 +12,4 @@
 R_LINE_TO, -4, -4,
 R_H_LINE_TO, 9,
 V_LINE_TO, 9,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_arrow_back.icon b/ash/resources/vector_icons/system_menu_arrow_back.icon
index f4ce8649..128b826 100644
--- a/ash/resources/vector_icons/system_menu_arrow_back.icon
+++ b/ash/resources/vector_icons/system_menu_arrow_back.icon
@@ -12,5 +12,4 @@
 R_LINE_TO, -9.3f, -9.21f,
 H_LINE_TO, 33,
 R_V_LINE_TO, -3,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_arrow_right.1x.icon b/ash/resources/vector_icons/system_menu_arrow_right.1x.icon
index 30ee32c..21b5b76 100644
--- a/ash/resources/vector_icons/system_menu_arrow_right.1x.icon
+++ b/ash/resources/vector_icons/system_menu_arrow_right.1x.icon
@@ -6,5 +6,4 @@
 MOVE_TO, 8, 14,
 R_LINE_TO, 4, -4,
 R_LINE_TO, -4, -4,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_arrow_right.icon b/ash/resources/vector_icons/system_menu_arrow_right.icon
index 2dc5eac..5ea2cb4 100644
--- a/ash/resources/vector_icons/system_menu_arrow_right.icon
+++ b/ash/resources/vector_icons/system_menu_arrow_right.icon
@@ -6,5 +6,4 @@
 MOVE_TO, 16, 28,
 R_LINE_TO, 8, -8,
 R_LINE_TO, -8, -8,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_audio_input.1x.icon b/ash/resources/vector_icons/system_menu_audio_input.1x.icon
index 291b6547..384d224 100644
--- a/ash/resources/vector_icons/system_menu_audio_input.1x.icon
+++ b/ash/resources/vector_icons/system_menu_audio_input.1x.icon
@@ -23,5 +23,4 @@
 CUBIC_TO, 5.86f, 2, 2.5f, 5.31f, 2.5f, 9.39f,
 R_CUBIC_TO, 0, 2.25f, 1.02f, 4.25f, 2.64f, 5.61f,
 R_LINE_TO, 1.18f, -1.17f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_audio_input.icon b/ash/resources/vector_icons/system_menu_audio_input.icon
index 3328457a..1cfda15c 100644
--- a/ash/resources/vector_icons/system_menu_audio_input.icon
+++ b/ash/resources/vector_icons/system_menu_audio_input.icon
@@ -23,5 +23,4 @@
 R_CUBIC_TO, 0, -8.28f, -6.72f, -15, -15, -15,
 CUBIC_TO, 11.72f, 3, 5, 9.72f, 5, 18,
 R_CUBIC_TO, 0, 4.57f, 2.05f, 8.63f, 5.28f, 11.38f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_audio_output.1x.icon b/ash/resources/vector_icons/system_menu_audio_output.1x.icon
index 0a25ef73..2d0b8066 100644
--- a/ash/resources/vector_icons/system_menu_audio_output.1x.icon
+++ b/ash/resources/vector_icons/system_menu_audio_output.1x.icon
@@ -23,5 +23,4 @@
 CUBIC_TO, 5.86f, 2, 2.5f, 5.31f, 2.5f, 9.39f,
 R_CUBIC_TO, 0, 2.25f, 1.02f, 4.25f, 2.64f, 5.61f,
 R_LINE_TO, 1.18f, -1.17f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_audio_output.icon b/ash/resources/vector_icons/system_menu_audio_output.icon
index 6689be5..10e8663 100644
--- a/ash/resources/vector_icons/system_menu_audio_output.icon
+++ b/ash/resources/vector_icons/system_menu_audio_output.icon
@@ -23,5 +23,4 @@
 R_CUBIC_TO, 0, -8.28f, -6.72f, -15, -15, -15,
 CUBIC_TO, 11.72f, 3, 5, 9.72f, 5, 18,
 R_CUBIC_TO, 0, 4.57f, 2.05f, 8.63f, 5.28f, 11.38f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_bluetooth.1x.icon b/ash/resources/vector_icons/system_menu_bluetooth.1x.icon
index 12eb297..5b61141b 100644
--- a/ash/resources/vector_icons/system_menu_bluetooth.1x.icon
+++ b/ash/resources/vector_icons/system_menu_bluetooth.1x.icon
@@ -28,5 +28,4 @@
 R_V_LINE_TO, -3.13f,
 R_LINE_TO, 1.59f, 1.57f,
 R_LINE_TO, -1.59f, 1.57f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_bluetooth.icon b/ash/resources/vector_icons/system_menu_bluetooth.icon
index 613ea32e..fa4daafe 100644
--- a/ash/resources/vector_icons/system_menu_bluetooth.icon
+++ b/ash/resources/vector_icons/system_menu_bluetooth.icon
@@ -28,5 +28,4 @@
 R_V_LINE_TO, -6.27f,
 R_LINE_TO, 3.18f, 3.13f,
 R_LINE_TO, -3.18f, 3.13f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_bluetooth_connected.1x.icon b/ash/resources/vector_icons/system_menu_bluetooth_connected.1x.icon
index 81682cc..8fa4f96 100644
--- a/ash/resources/vector_icons/system_menu_bluetooth_connected.1x.icon
+++ b/ash/resources/vector_icons/system_menu_bluetooth_connected.1x.icon
@@ -40,5 +40,4 @@
 R_V_LINE_TO, -3.13f,
 R_LINE_TO, 1.59f, 1.57f,
 R_LINE_TO, -1.59f, 1.57f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_bluetooth_connected.icon b/ash/resources/vector_icons/system_menu_bluetooth_connected.icon
index 5287568..94b7c40 100644
--- a/ash/resources/vector_icons/system_menu_bluetooth_connected.icon
+++ b/ash/resources/vector_icons/system_menu_bluetooth_connected.icon
@@ -40,5 +40,4 @@
 R_LINE_TO, 3, 3,
 R_LINE_TO, -3, 3,
 R_LINE_TO, -3, -3,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_bluetooth_disabled.1x.icon b/ash/resources/vector_icons/system_menu_bluetooth_disabled.1x.icon
index 1ccee625..b166bd1b 100644
--- a/ash/resources/vector_icons/system_menu_bluetooth_disabled.1x.icon
+++ b/ash/resources/vector_icons/system_menu_bluetooth_disabled.1x.icon
@@ -31,5 +31,4 @@
 R_LINE_TO, 1.53f, 1.57f,
 R_LINE_TO, -1.53f, 1.57f,
 R_V_LINE_TO, -3.13f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_bluetooth_disabled.icon b/ash/resources/vector_icons/system_menu_bluetooth_disabled.icon
index c2c0029..d8f054a 100644
--- a/ash/resources/vector_icons/system_menu_bluetooth_disabled.icon
+++ b/ash/resources/vector_icons/system_menu_bluetooth_disabled.icon
@@ -31,5 +31,4 @@
 R_LINE_TO, 3.06f, 3.13f,
 R_LINE_TO, -3.05f, 3.13f,
 R_V_LINE_TO, -6.27f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_brightness.1x.icon b/ash/resources/vector_icons/system_menu_brightness.1x.icon
index 1228566..58eac7f 100644
--- a/ash/resources/vector_icons/system_menu_brightness.1x.icon
+++ b/ash/resources/vector_icons/system_menu_brightness.1x.icon
@@ -30,5 +30,4 @@
 R_MOVE_TO, 0, -1,
 R_ARC_TO, 3, 3, 0, 1, 0, 0, -6,
 R_ARC_TO, 3, 3, 0, 0, 0, 0, 6,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_brightness.icon b/ash/resources/vector_icons/system_menu_brightness.icon
index fdb50dc..daa5d6e 100644
--- a/ash/resources/vector_icons/system_menu_brightness.icon
+++ b/ash/resources/vector_icons/system_menu_brightness.icon
@@ -30,5 +30,4 @@
 R_MOVE_TO, 0, -2,
 R_ARC_TO, 6, 6, 0, 1, 0, 0, -12,
 R_ARC_TO, 6, 6, 0, 0, 0, 0, 12,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_business.1x.icon b/ash/resources/vector_icons/system_menu_business.1x.icon
index 5afdf44..8044ff29 100644
--- a/ash/resources/vector_icons/system_menu_business.1x.icon
+++ b/ash/resources/vector_icons/system_menu_business.1x.icon
@@ -58,5 +58,4 @@
 R_V_LINE_TO, 2,
 H_LINE_TO, 4,
 V_LINE_TO, 5,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_business.icon b/ash/resources/vector_icons/system_menu_business.icon
index 79ee98b..433fba4 100644
--- a/ash/resources/vector_icons/system_menu_business.icon
+++ b/ash/resources/vector_icons/system_menu_business.icon
@@ -84,5 +84,4 @@
 R_V_LINE_TO, 3,
 R_H_LINE_TO, 3,
 R_V_LINE_TO, -3,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_caps_lock.1x.icon b/ash/resources/vector_icons/system_menu_caps_lock.1x.icon
index 0ca0484..e090c70 100644
--- a/ash/resources/vector_icons/system_menu_caps_lock.1x.icon
+++ b/ash/resources/vector_icons/system_menu_caps_lock.1x.icon
@@ -26,5 +26,4 @@
 R_V_LINE_TO, -2,
 H_LINE_TO, 5,
 R_V_LINE_TO, 2,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_caps_lock.icon b/ash/resources/vector_icons/system_menu_caps_lock.icon
index e6856480..725eb542 100644
--- a/ash/resources/vector_icons/system_menu_caps_lock.icon
+++ b/ash/resources/vector_icons/system_menu_caps_lock.icon
@@ -26,5 +26,4 @@
 R_V_LINE_TO, -3,
 H_LINE_TO, 10,
 R_V_LINE_TO, 3,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_cast.1x.icon b/ash/resources/vector_icons/system_menu_cast.1x.icon
index 3b87f097..35401944 100644
--- a/ash/resources/vector_icons/system_menu_cast.1x.icon
+++ b/ash/resources/vector_icons/system_menu_cast.1x.icon
@@ -34,5 +34,4 @@
 V_LINE_TO, 5.44f,
 CUBIC_TO, 18, 4.65f, 17.35f, 4, 16.55f, 4,
 H_LINE_TO, 3.46f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_cast.icon b/ash/resources/vector_icons/system_menu_cast.icon
index 8276ab9..f9aa938 100644
--- a/ash/resources/vector_icons/system_menu_cast.icon
+++ b/ash/resources/vector_icons/system_menu_cast.icon
@@ -34,5 +34,4 @@
 V_LINE_TO, 10.89f,
 CUBIC_TO, 36, 9.3f, 34.69f, 8, 33.09f, 8,
 H_LINE_TO, 6.91f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_cast_audio.1x.icon b/ash/resources/vector_icons/system_menu_cast_audio.1x.icon
index 1ad9839..e02895b 100644
--- a/ash/resources/vector_icons/system_menu_cast_audio.1x.icon
+++ b/ash/resources/vector_icons/system_menu_cast_audio.1x.icon
@@ -30,5 +30,4 @@
 R_CUBIC_TO, 0, 1.11f, 0.89f, 2, 2, 2,
 R_CUBIC_TO, 1.11f, 0, 2, -0.89f, 2, -2,
 R_CUBIC_TO, 0, -1.11f, -0.89f, -2, -2, -2,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_cast_audio.icon b/ash/resources/vector_icons/system_menu_cast_audio.icon
index 86804198..b1f7e4e 100644
--- a/ash/resources/vector_icons/system_menu_cast_audio.icon
+++ b/ash/resources/vector_icons/system_menu_cast_audio.icon
@@ -30,5 +30,4 @@
 R_CUBIC_TO, 0, 2.77f, 2.23f, 5, 5, 5,
 R_CUBIC_TO, 2.77f, 0, 5, -2.23f, 5, -5,
 R_CUBIC_TO, 0, -2.77f, -2.23f, -5, -5, -5,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_cast_audio_group.1x.icon b/ash/resources/vector_icons/system_menu_cast_audio_group.1x.icon
index 5733fe29..7a67c1a 100644
--- a/ash/resources/vector_icons/system_menu_cast_audio_group.1x.icon
+++ b/ash/resources/vector_icons/system_menu_cast_audio_group.1x.icon
@@ -34,5 +34,4 @@
 R_V_LINE_TO, -2,
 H_LINE_TO, 5,
 V_LINE_TO, 4,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_cast_audio_group.icon b/ash/resources/vector_icons/system_menu_cast_audio_group.icon
index 702e44e..510789a 100644
--- a/ash/resources/vector_icons/system_menu_cast_audio_group.icon
+++ b/ash/resources/vector_icons/system_menu_cast_audio_group.icon
@@ -34,5 +34,4 @@
 R_V_LINE_TO, -4,
 H_LINE_TO, 10,
 V_LINE_TO, 8,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_cast_device.1x.icon b/ash/resources/vector_icons/system_menu_cast_device.1x.icon
index ef8c28dd..82e40fe 100644
--- a/ash/resources/vector_icons/system_menu_cast_device.1x.icon
+++ b/ash/resources/vector_icons/system_menu_cast_device.1x.icon
@@ -39,5 +39,4 @@
 R_H_LINE_TO, 3.83f,
 R_CUBIC_TO, 0.3f, 0.74f, 0.47f, 1.55f, 0.47f, 2.4f,
 R_CUBIC_TO, 0, 3.54f, -2.86f, 6.4f, -6.4f, 6.4f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_cast_device.icon b/ash/resources/vector_icons/system_menu_cast_device.icon
index 9605bab..9c633d8 100644
--- a/ash/resources/vector_icons/system_menu_cast_device.icon
+++ b/ash/resources/vector_icons/system_menu_cast_device.icon
@@ -39,5 +39,4 @@
 R_H_LINE_TO, 7.66f,
 R_CUBIC_TO, 0.61f, 1.49f, 0.94f, 3.1f, 0.94f, 4.8f,
 R_CUBIC_TO, 0, 7.07f, -5.73f, 12.8f, -12.8f, 12.8f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_cast_education.1x.icon b/ash/resources/vector_icons/system_menu_cast_education.1x.icon
index a39e7a4..34da227a 100644
--- a/ash/resources/vector_icons/system_menu_cast_education.1x.icon
+++ b/ash/resources/vector_icons/system_menu_cast_education.1x.icon
@@ -48,5 +48,4 @@
 R_LINE_TO, 4.5f, 2.33f,
 R_LINE_TO, 4.5f, -2.33f,
 R_LINE_TO, -4.5f, -2.33f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_cast_education.icon b/ash/resources/vector_icons/system_menu_cast_education.icon
index c1eca4e..e4fde4e 100644
--- a/ash/resources/vector_icons/system_menu_cast_education.icon
+++ b/ash/resources/vector_icons/system_menu_cast_education.icon
@@ -48,5 +48,4 @@
 R_LINE_TO, 9, 4.67f,
 R_LINE_TO, 9, -4.67f,
 R_LINE_TO, -9, -4.67f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_cast_enabled.1x.icon b/ash/resources/vector_icons/system_menu_cast_enabled.1x.icon
index e64c418..cdefe94 100644
--- a/ash/resources/vector_icons/system_menu_cast_enabled.1x.icon
+++ b/ash/resources/vector_icons/system_menu_cast_enabled.1x.icon
@@ -41,5 +41,4 @@
 H_LINE_TO, 15,
 V_LINE_TO, 7,
 H_LINE_TO, 5,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_cast_enabled.icon b/ash/resources/vector_icons/system_menu_cast_enabled.icon
index a1dfd2e..6efd4ab 100644
--- a/ash/resources/vector_icons/system_menu_cast_enabled.icon
+++ b/ash/resources/vector_icons/system_menu_cast_enabled.icon
@@ -41,5 +41,4 @@
 H_LINE_TO, 30,
 V_LINE_TO, 14,
 H_LINE_TO, 10,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_cast_generic.1x.icon b/ash/resources/vector_icons/system_menu_cast_generic.1x.icon
index b57b0da..96b67ab0 100644
--- a/ash/resources/vector_icons/system_menu_cast_generic.1x.icon
+++ b/ash/resources/vector_icons/system_menu_cast_generic.1x.icon
@@ -22,5 +22,4 @@
 V_LINE_TO, 4.56f,
 R_H_LINE_TO, 15,
 V_LINE_TO, 13.5f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_cast_generic.icon b/ash/resources/vector_icons/system_menu_cast_generic.icon
index dc4cd94c..5c8a6703 100644
--- a/ash/resources/vector_icons/system_menu_cast_generic.icon
+++ b/ash/resources/vector_icons/system_menu_cast_generic.icon
@@ -22,5 +22,4 @@
 V_LINE_TO, 9,
 R_H_LINE_TO, 30,
 R_V_LINE_TO, 18,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_cast_hangout.1x.icon b/ash/resources/vector_icons/system_menu_cast_hangout.1x.icon
index f1ad1e1..df91815 100644
--- a/ash/resources/vector_icons/system_menu_cast_hangout.1x.icon
+++ b/ash/resources/vector_icons/system_menu_cast_hangout.1x.icon
@@ -28,5 +28,4 @@
 R_V_LINE_TO, -2.34f,
 R_H_LINE_TO, 2.47f,
 R_V_LINE_TO, 2.34f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_cast_hangout.icon b/ash/resources/vector_icons/system_menu_cast_hangout.icon
index 86d532e..3edba278 100644
--- a/ash/resources/vector_icons/system_menu_cast_hangout.icon
+++ b/ash/resources/vector_icons/system_menu_cast_hangout.icon
@@ -28,5 +28,4 @@
 R_V_LINE_TO, -5,
 R_H_LINE_TO, 5,
 R_V_LINE_TO, 5,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_cast_meeting.1x.icon b/ash/resources/vector_icons/system_menu_cast_meeting.1x.icon
index 41fdfe3..9ed8a77 100644
--- a/ash/resources/vector_icons/system_menu_cast_meeting.1x.icon
+++ b/ash/resources/vector_icons/system_menu_cast_meeting.1x.icon
@@ -19,5 +19,4 @@
 R_V_LINE_TO, 1.5f,
 LINE_TO, 14, 7,
 R_V_LINE_TO, 4,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_cast_meeting.icon b/ash/resources/vector_icons/system_menu_cast_meeting.icon
index 980875e..5b185bf 100644
--- a/ash/resources/vector_icons/system_menu_cast_meeting.icon
+++ b/ash/resources/vector_icons/system_menu_cast_meeting.icon
@@ -19,5 +19,4 @@
 R_V_LINE_TO, 3,
 R_LINE_TO, 5, -3,
 R_V_LINE_TO, 8,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_cast_message.1x.icon b/ash/resources/vector_icons/system_menu_cast_message.1x.icon
index f2fd0cf7..f13d2fd 100644
--- a/ash/resources/vector_icons/system_menu_cast_message.1x.icon
+++ b/ash/resources/vector_icons/system_menu_cast_message.1x.icon
@@ -30,5 +30,4 @@
 V_LINE_TO, 5,
 R_H_LINE_TO, 10,
 R_V_LINE_TO, 1.5f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_cast_message.icon b/ash/resources/vector_icons/system_menu_cast_message.icon
index 3547d3a6..71c2779f 100644
--- a/ash/resources/vector_icons/system_menu_cast_message.icon
+++ b/ash/resources/vector_icons/system_menu_cast_message.icon
@@ -30,5 +30,4 @@
 R_V_LINE_TO, -3,
 R_H_LINE_TO, 20,
 R_V_LINE_TO, 3,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_child_user.1x.icon b/ash/resources/vector_icons/system_menu_child_user.1x.icon
index 45746de..54b7a08 100644
--- a/ash/resources/vector_icons/system_menu_child_user.1x.icon
+++ b/ash/resources/vector_icons/system_menu_child_user.1x.icon
@@ -21,5 +21,4 @@
 R_LINE_TO, 1.27f, -1.94f,
 LINE_TO, 16, 8,
 LINE_TO, 10.32f, 2,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_child_user.icon b/ash/resources/vector_icons/system_menu_child_user.icon
index e3dacc5c..5c566026 100644
--- a/ash/resources/vector_icons/system_menu_child_user.icon
+++ b/ash/resources/vector_icons/system_menu_child_user.icon
@@ -21,5 +21,4 @@
 R_LINE_TO, 2.55f, -3.89f,
 LINE_TO, 32, 16,
 LINE_TO, 20.64f, 4,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_computer.1x.icon b/ash/resources/vector_icons/system_menu_computer.1x.icon
index e20aa42e..2cdfb48 100644
--- a/ash/resources/vector_icons/system_menu_computer.1x.icon
+++ b/ash/resources/vector_icons/system_menu_computer.1x.icon
@@ -22,5 +22,4 @@
 R_V_LINE_TO, 6,
 H_LINE_TO, 5,
 V_LINE_TO, 6,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_computer.icon b/ash/resources/vector_icons/system_menu_computer.icon
index dbaeeab1..607d8be 100644
--- a/ash/resources/vector_icons/system_menu_computer.icon
+++ b/ash/resources/vector_icons/system_menu_computer.icon
@@ -22,5 +22,4 @@
 R_V_LINE_TO, 15,
 H_LINE_TO, 8,
 V_LINE_TO, 11,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_gamepad.1x.icon b/ash/resources/vector_icons/system_menu_gamepad.1x.icon
index 117beaa9..d19e9f6d 100644
--- a/ash/resources/vector_icons/system_menu_gamepad.1x.icon
+++ b/ash/resources/vector_icons/system_menu_gamepad.1x.icon
@@ -30,5 +30,4 @@
 R_H_LINE_TO, 4,
 V_LINE_TO, 7,
 R_H_LINE_TO, -4,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_gamepad.icon b/ash/resources/vector_icons/system_menu_gamepad.icon
index 76c89f2..4841b639 100644
--- a/ash/resources/vector_icons/system_menu_gamepad.icon
+++ b/ash/resources/vector_icons/system_menu_gamepad.icon
@@ -30,5 +30,4 @@
 H_LINE_TO, 36,
 V_LINE_TO, 15,
 R_H_LINE_TO, -9.06f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_guest.1x.icon b/ash/resources/vector_icons/system_menu_guest.1x.icon
index 1756b74..a713ed7 100644
--- a/ash/resources/vector_icons/system_menu_guest.1x.icon
+++ b/ash/resources/vector_icons/system_menu_guest.1x.icon
@@ -20,5 +20,4 @@
 R_CUBIC_TO, 0.03f, -1.67f, 3.33f, -2.58f, 5, -2.58f,
 R_CUBIC_TO, 1.66f, 0, 4.97f, 0.91f, 5, 2.58f,
 R_CUBIC_TO, -1.07f, 1.63f, -2.92f, 2.7f, -5, 2.7f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_guest.icon b/ash/resources/vector_icons/system_menu_guest.icon
index a4293bb..21c18cf 100644
--- a/ash/resources/vector_icons/system_menu_guest.icon
+++ b/ash/resources/vector_icons/system_menu_guest.icon
@@ -20,5 +20,4 @@
 R_CUBIC_TO, 3.32f, 0, 9.95f, 1.9f, 10, 5.38f,
 CUBIC_TO, 27.85f, 29.77f, 24.17f, 32, 20, 32,
 R_CUBIC_TO, -4.17f, 0, -7.85f, -2.23f, -10, -5.62f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_hdmi.1x.icon b/ash/resources/vector_icons/system_menu_hdmi.1x.icon
index a70e5ef6..3e56ac0e 100644
--- a/ash/resources/vector_icons/system_menu_hdmi.1x.icon
+++ b/ash/resources/vector_icons/system_menu_hdmi.1x.icon
@@ -32,5 +32,4 @@
 H_LINE_TO, 7,
 V_LINE_TO, 4,
 R_H_LINE_TO, 6,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_hdmi.icon b/ash/resources/vector_icons/system_menu_hdmi.icon
index c9e2183..69c33cdff 100644
--- a/ash/resources/vector_icons/system_menu_hdmi.icon
+++ b/ash/resources/vector_icons/system_menu_hdmi.icon
@@ -32,5 +32,4 @@
 V_LINE_TO, 12,
 H_LINE_TO, 13,
 V_LINE_TO, 7,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_headset.1x.icon b/ash/resources/vector_icons/system_menu_headset.1x.icon
index c01f734b..fd67785c 100644
--- a/ash/resources/vector_icons/system_menu_headset.1x.icon
+++ b/ash/resources/vector_icons/system_menu_headset.1x.icon
@@ -20,5 +20,4 @@
 V_LINE_TO, 9.58f,
 CUBIC_TO, 18, 5.39f, 14.14f, 2, 10, 2,
 CUBIC_TO, 5.86f, 2, 2, 5.39f, 2, 9.58f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_headset.icon b/ash/resources/vector_icons/system_menu_headset.icon
index 67cc0dc..64eeccd 100644
--- a/ash/resources/vector_icons/system_menu_headset.icon
+++ b/ash/resources/vector_icons/system_menu_headset.icon
@@ -20,5 +20,4 @@
 R_V_LINE_TO, -11.79f,
 CUBIC_TO, 35, 10.79f, 28.28f, 4, 20, 4,
 CUBIC_TO, 11.72f, 4, 5, 10.79f, 5, 19.16f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_help.1x.icon b/ash/resources/vector_icons/system_menu_help.1x.icon
index eeeedf8..c9a6a25 100644
--- a/ash/resources/vector_icons/system_menu_help.1x.icon
+++ b/ash/resources/vector_icons/system_menu_help.1x.icon
@@ -29,5 +29,4 @@
 R_CUBIC_TO, 0, -1.77f, 1.43f, -3.2f, 3.2f, -3.2f,
 R_CUBIC_TO, 1.77f, 0, 3.2f, 1.43f, 3.2f, 3.2f,
 R_CUBIC_TO, 0, 0.7f, -0.29f, 1.34f, -0.74f, 1.8f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_help.icon b/ash/resources/vector_icons/system_menu_help.icon
index 9205b83d..83d28d6 100644
--- a/ash/resources/vector_icons/system_menu_help.icon
+++ b/ash/resources/vector_icons/system_menu_help.icon
@@ -29,5 +29,4 @@
 R_CUBIC_TO, 0, -3.54f, 2.86f, -6.4f, 6.4f, -6.4f,
 R_CUBIC_TO, 3.54f, 0, 6.4f, 2.86f, 6.4f, 6.4f,
 R_CUBIC_TO, 0, 1.41f, -0.58f, 2.69f, -1.49f, 3.6f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_info.1x.icon b/ash/resources/vector_icons/system_menu_info.1x.icon
index 5fb614f..98303d3 100644
--- a/ash/resources/vector_icons/system_menu_info.1x.icon
+++ b/ash/resources/vector_icons/system_menu_info.1x.icon
@@ -20,5 +20,4 @@
 V_LINE_TO, 6,
 R_H_LINE_TO, 2,
 R_V_LINE_TO, 2,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_info.icon b/ash/resources/vector_icons/system_menu_info.icon
index 39db157..fe44ba7 100644
--- a/ash/resources/vector_icons/system_menu_info.icon
+++ b/ash/resources/vector_icons/system_menu_info.icon
@@ -20,5 +20,4 @@
 R_V_LINE_TO, -3,
 R_H_LINE_TO, 3,
 R_V_LINE_TO, 3,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_keyboard.1x.icon b/ash/resources/vector_icons/system_menu_keyboard.1x.icon
index 234ce33c..a489093 100644
--- a/ash/resources/vector_icons/system_menu_keyboard.1x.icon
+++ b/ash/resources/vector_icons/system_menu_keyboard.1x.icon
@@ -78,5 +78,4 @@
 V_LINE_TO, 8,
 R_H_LINE_TO, 1,
 R_V_LINE_TO, 1,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_keyboard.icon b/ash/resources/vector_icons/system_menu_keyboard.icon
index 34bc444..2be7249 100644
--- a/ash/resources/vector_icons/system_menu_keyboard.icon
+++ b/ash/resources/vector_icons/system_menu_keyboard.icon
@@ -78,5 +78,4 @@
 R_V_LINE_TO, -3,
 R_H_LINE_TO, 3,
 R_V_LINE_TO, 3,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_keyboard_brightness.1x.icon b/ash/resources/vector_icons/system_menu_keyboard_brightness.1x.icon
index 1b97e21..5c9028e 100644
--- a/ash/resources/vector_icons/system_menu_keyboard_brightness.1x.icon
+++ b/ash/resources/vector_icons/system_menu_keyboard_brightness.1x.icon
@@ -56,5 +56,4 @@
 R_V_LINE_TO, 2,
 R_H_LINE_TO, -2.45f,
 R_V_LINE_TO, -2,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_keyboard_brightness.icon b/ash/resources/vector_icons/system_menu_keyboard_brightness.icon
index 2316beb..23ba163b 100644
--- a/ash/resources/vector_icons/system_menu_keyboard_brightness.icon
+++ b/ash/resources/vector_icons/system_menu_keyboard_brightness.icon
@@ -56,5 +56,4 @@
 V_LINE_TO, 27,
 R_H_LINE_TO, -4.64f,
 R_V_LINE_TO, -3.01f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_lock.1x.icon b/ash/resources/vector_icons/system_menu_lock.1x.icon
index c24e335..9bb0992 100644
--- a/ash/resources/vector_icons/system_menu_lock.1x.icon
+++ b/ash/resources/vector_icons/system_menu_lock.1x.icon
@@ -28,5 +28,4 @@
 R_CUBIC_TO, 1.1f, 0, 2.5f, 0.49f, 2.5f, 2,
 V_LINE_TO, 8,
 R_H_LINE_TO, -5,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_lock.icon b/ash/resources/vector_icons/system_menu_lock.icon
index ab77272..a6e6d8fb 100644
--- a/ash/resources/vector_icons/system_menu_lock.icon
+++ b/ash/resources/vector_icons/system_menu_lock.icon
@@ -30,5 +30,4 @@
 R_CUBIC_TO, 3.31f, 0, 6, 2.45f, 6, 5.47f,
 V_LINE_TO, 15,
 H_LINE_TO, 14,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_mouse.1x.icon b/ash/resources/vector_icons/system_menu_mouse.1x.icon
index 252dd06..675be538 100644
--- a/ash/resources/vector_icons/system_menu_mouse.1x.icon
+++ b/ash/resources/vector_icons/system_menu_mouse.1x.icon
@@ -19,5 +19,4 @@
 CUBIC_TO, 6.2f, 3.31f, 4, 5.43f, 4, 8,
 R_H_LINE_TO, 5.04f,
 V_LINE_TO, 3,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_mouse.icon b/ash/resources/vector_icons/system_menu_mouse.icon
index 1dfe048a..7e427f9 100644
--- a/ash/resources/vector_icons/system_menu_mouse.icon
+++ b/ash/resources/vector_icons/system_menu_mouse.icon
@@ -19,5 +19,4 @@
 R_CUBIC_TO, -6.21f, 0.74f, -11, 5.83f, -11, 12,
 R_H_LINE_TO, 11,
 V_LINE_TO, 4,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_new_user.1x.icon b/ash/resources/vector_icons/system_menu_new_user.1x.icon
index 6855519..8c7a0e13 100644
--- a/ash/resources/vector_icons/system_menu_new_user.1x.icon
+++ b/ash/resources/vector_icons/system_menu_new_user.1x.icon
@@ -29,5 +29,4 @@
 R_CUBIC_TO, 0.62f, 0, 1.22f, -0.07f, 1.8f, -0.21f,
 R_CUBIC_TO, 0.17f, 0.57f, 0.26f, 1.18f, 0.26f, 1.81f,
 R_CUBIC_TO, 0, 3.53f, -2.87f, 6.4f, -6.4f, 6.4f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_new_user.icon b/ash/resources/vector_icons/system_menu_new_user.icon
index d5ebc5b..68e24b77 100644
--- a/ash/resources/vector_icons/system_menu_new_user.icon
+++ b/ash/resources/vector_icons/system_menu_new_user.icon
@@ -29,5 +29,4 @@
 R_CUBIC_TO, 1.25f, 0, 2.45f, -0.14f, 3.6f, -0.42f,
 R_CUBIC_TO, 0.34f, 1.14f, 0.53f, 2.35f, 0.53f, 3.62f,
 R_CUBIC_TO, 0, 7.06f, -5.74f, 12.8f, -12.8f, 12.8f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_night_light_off.1x.icon b/ash/resources/vector_icons/system_menu_night_light_off.1x.icon
index e7f4aa3..3c71773 100644
--- a/ash/resources/vector_icons/system_menu_night_light_off.1x.icon
+++ b/ash/resources/vector_icons/system_menu_night_light_off.1x.icon
@@ -30,5 +30,4 @@
 R_LINE_TO, 14.31f, 14.31f,
 R_LINE_TO, -1.06f, 1.06f,
 LINE_TO, 2.5f, 3.06f,
-CLOSE,
-END
\ No newline at end of file
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_night_light_off.icon b/ash/resources/vector_icons/system_menu_night_light_off.icon
index 1e7bc9f..660bb50 100644
--- a/ash/resources/vector_icons/system_menu_night_light_off.icon
+++ b/ash/resources/vector_icons/system_menu_night_light_off.icon
@@ -30,5 +30,4 @@
 R_LINE_TO, 28.63f, 28.63f,
 R_LINE_TO, -2.12f, 2.12f,
 LINE_TO, 5, 6.12f,
-CLOSE,
-END
\ No newline at end of file
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_night_light_on.1x.icon b/ash/resources/vector_icons/system_menu_night_light_on.1x.icon
index 64623ec..34b4c54 100644
--- a/ash/resources/vector_icons/system_menu_night_light_on.1x.icon
+++ b/ash/resources/vector_icons/system_menu_night_light_on.1x.icon
@@ -16,5 +16,4 @@
 CUBIC_TO, 8.85f, 14.93f, 7.29f, 12.67f, 7.29f, 10,
 R_CUBIC_TO, 0, -2.67f, 1.56f, -4.93f, 3.71f, -5.71f,
 CUBIC_TO, 10.48f, 4.1f, 9.93f, 4, 9.35f, 4,
-CLOSE,
-END
\ No newline at end of file
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_night_light_on.icon b/ash/resources/vector_icons/system_menu_night_light_on.icon
index 513dce8..f1cd0aa 100644
--- a/ash/resources/vector_icons/system_menu_night_light_on.icon
+++ b/ash/resources/vector_icons/system_menu_night_light_on.icon
@@ -16,5 +16,4 @@
 R_CUBIC_TO, 1.4f, 0, 2.74f, -0.22f, 4, -0.63f,
 R_CUBIC_TO, -5.22f, -1.69f, -9, -6.59f, -9, -12.37f,
 R_CUBIC_TO, 0, -5.78f, 3.78f, -10.69f, 9, -12.37f,
-CLOSE,
-END
\ No newline at end of file
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_phone.1x.icon b/ash/resources/vector_icons/system_menu_phone.1x.icon
index 17bc0ee..c837268 100644
--- a/ash/resources/vector_icons/system_menu_phone.1x.icon
+++ b/ash/resources/vector_icons/system_menu_phone.1x.icon
@@ -18,5 +18,4 @@
 R_V_LINE_TO, 10,
 H_LINE_TO, 7,
 V_LINE_TO, 5,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_phone.icon b/ash/resources/vector_icons/system_menu_phone.icon
index 22d78fbb..2c0ec69d 100644
--- a/ash/resources/vector_icons/system_menu_phone.icon
+++ b/ash/resources/vector_icons/system_menu_phone.icon
@@ -18,5 +18,4 @@
 V_LINE_TO, 10,
 R_H_LINE_TO, 14,
 R_V_LINE_TO, 20,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_power.1x.icon b/ash/resources/vector_icons/system_menu_power.1x.icon
index 82429a6..806d0f6 100644
--- a/ash/resources/vector_icons/system_menu_power.1x.icon
+++ b/ash/resources/vector_icons/system_menu_power.1x.icon
@@ -20,5 +20,4 @@
 CUBIC_TO, 2, 14.44f, 5.58f, 18, 10, 18,
 R_CUBIC_TO, 4.42f, 0, 8, -3.56f, 8, -7.96f,
 R_CUBIC_TO, 0, -2.42f, -1.09f, -4.58f, -2.82f, -6.04f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_power.icon b/ash/resources/vector_icons/system_menu_power.icon
index 0680184a..5cdb93d 100644
--- a/ash/resources/vector_icons/system_menu_power.icon
+++ b/ash/resources/vector_icons/system_menu_power.icon
@@ -20,5 +20,4 @@
 R_CUBIC_TO, 0, 8.28f, 6.72f, 15, 15, 15,
 R_CUBIC_TO, 8.28f, 0, 15, -6.72f, 15, -15,
 R_CUBIC_TO, 0, -4.57f, -2.05f, -8.63f, -5.28f, -11.38f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_rotation_lock_auto.1x.icon b/ash/resources/vector_icons/system_menu_rotation_lock_auto.1x.icon
index 6d8f8d2..6cfe68ab 100644
--- a/ash/resources/vector_icons/system_menu_rotation_lock_auto.1x.icon
+++ b/ash/resources/vector_icons/system_menu_rotation_lock_auto.1x.icon
@@ -38,5 +38,4 @@
 R_CUBIC_TO, 0.57f, 0.6f, 1.51f, 0.59f, 2.09f, -0.01f,
 R_LINE_TO, 5.23f, -5.45f,
 R_CUBIC_TO, 0.58f, -0.6f, 0.58f, -1.58f, 0, -2.18f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_rotation_lock_auto.icon b/ash/resources/vector_icons/system_menu_rotation_lock_auto.icon
index cf0f07e..a3ad737 100644
--- a/ash/resources/vector_icons/system_menu_rotation_lock_auto.icon
+++ b/ash/resources/vector_icons/system_menu_rotation_lock_auto.icon
@@ -38,5 +38,4 @@
 R_CUBIC_TO, 1.15f, 1.17f, 3.02f, 1.16f, 4.17f, -0.01f,
 R_LINE_TO, 10.46f, -10.6f,
 R_CUBIC_TO, 1.15f, -1.17f, 1.15f, -3.08f, 0, -4.24f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_rotation_lock_landscape.1x.icon b/ash/resources/vector_icons/system_menu_rotation_lock_landscape.1x.icon
index a229a01..1183c3c 100644
--- a/ash/resources/vector_icons/system_menu_rotation_lock_landscape.1x.icon
+++ b/ash/resources/vector_icons/system_menu_rotation_lock_landscape.1x.icon
@@ -18,5 +18,4 @@
 R_V_LINE_TO, 8,
 H_LINE_TO, 5,
 V_LINE_TO, 6,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_rotation_lock_landscape.icon b/ash/resources/vector_icons/system_menu_rotation_lock_landscape.icon
index d22e2fd..35363c3a 100644
--- a/ash/resources/vector_icons/system_menu_rotation_lock_landscape.icon
+++ b/ash/resources/vector_icons/system_menu_rotation_lock_landscape.icon
@@ -18,5 +18,4 @@
 V_LINE_TO, 11,
 R_H_LINE_TO, 20,
 R_V_LINE_TO, 18,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_rotation_lock_portrait.1x.icon b/ash/resources/vector_icons/system_menu_rotation_lock_portrait.1x.icon
index 29d46ab..60b6fa2 100644
--- a/ash/resources/vector_icons/system_menu_rotation_lock_portrait.1x.icon
+++ b/ash/resources/vector_icons/system_menu_rotation_lock_portrait.1x.icon
@@ -18,5 +18,4 @@
 R_H_LINE_TO, 8,
 V_LINE_TO, 4,
 H_LINE_TO, 6,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_rotation_lock_portrait.icon b/ash/resources/vector_icons/system_menu_rotation_lock_portrait.icon
index b301e12..12b4b2a 100644
--- a/ash/resources/vector_icons/system_menu_rotation_lock_portrait.icon
+++ b/ash/resources/vector_icons/system_menu_rotation_lock_portrait.icon
@@ -18,5 +18,4 @@
 R_H_LINE_TO, 16,
 V_LINE_TO, 8,
 H_LINE_TO, 12,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_screen_share.1x.icon b/ash/resources/vector_icons/system_menu_screen_share.1x.icon
index faba58f..55e47c6 100644
--- a/ash/resources/vector_icons/system_menu_screen_share.1x.icon
+++ b/ash/resources/vector_icons/system_menu_screen_share.1x.icon
@@ -26,5 +26,4 @@
 R_LINE_TO, 3, 3.5f,
 R_LINE_TO, -3, 3.5f,
 R_V_LINE_TO, -2,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_screen_share.icon b/ash/resources/vector_icons/system_menu_screen_share.icon
index 42355ab..e6d8797c 100644
--- a/ash/resources/vector_icons/system_menu_screen_share.icon
+++ b/ash/resources/vector_icons/system_menu_screen_share.icon
@@ -26,5 +26,4 @@
 R_LINE_TO, 6, 6,
 R_LINE_TO, -6, 6,
 R_V_LINE_TO, -4,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_settings.1x.icon b/ash/resources/vector_icons/system_menu_settings.1x.icon
index c5785188..6707c8a6 100644
--- a/ash/resources/vector_icons/system_menu_settings.1x.icon
+++ b/ash/resources/vector_icons/system_menu_settings.1x.icon
@@ -48,5 +48,4 @@
 R_CUBIC_TO, 0, -1.65f, 1.35f, -3, 3, -3,
 R_CUBIC_TO, 1.65f, 0, 3, 1.35f, 3, 3,
 R_CUBIC_TO, 0, 1.65f, -1.35f, 3, -3, 3,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_settings.icon b/ash/resources/vector_icons/system_menu_settings.icon
index a38b947f..77dca19 100644
--- a/ash/resources/vector_icons/system_menu_settings.icon
+++ b/ash/resources/vector_icons/system_menu_settings.icon
@@ -48,5 +48,4 @@
 R_CUBIC_TO, 0, -3.21f, 2.69f, -5.82f, 5.98f, -5.82f,
 R_CUBIC_TO, 3.3f, 0, 5.98f, 2.61f, 5.98f, 5.82f,
 R_CUBIC_TO, 0, 3.21f, -2.68f, 5.82f, -5.98f, 5.82f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_supervised_user.1x.icon b/ash/resources/vector_icons/system_menu_supervised_user.1x.icon
index aee7f15..426d646 100644
--- a/ash/resources/vector_icons/system_menu_supervised_user.1x.icon
+++ b/ash/resources/vector_icons/system_menu_supervised_user.1x.icon
@@ -29,5 +29,4 @@
 R_CUBIC_TO, 0, -0.73f, 0, -2, 2, -2.9f,
 R_CUBIC_TO, -0.83f, -0.15f, -1.87f, 0, -2.5f, 0,
 R_CUBIC_TO, -2.24f, 0, -6.5f, 0.76f, -6.5f, 2.76f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_supervised_user.icon b/ash/resources/vector_icons/system_menu_supervised_user.icon
index f93efb2..2c27f93b 100644
--- a/ash/resources/vector_icons/system_menu_supervised_user.icon
+++ b/ash/resources/vector_icons/system_menu_supervised_user.icon
@@ -28,5 +28,4 @@
 R_V_LINE_TO, -3.8f,
 R_CUBIC_TO, 0, -1.44f, 0.56f, -3.95f, 4.03f, -5.87f,
 R_CUBIC_TO, -1.48f, -0.3f, -2.91f, -0.47f, -4.03f, -0.47f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_tablet.1x.icon b/ash/resources/vector_icons/system_menu_tablet.1x.icon
index e078da3..4fdcf72 100644
--- a/ash/resources/vector_icons/system_menu_tablet.1x.icon
+++ b/ash/resources/vector_icons/system_menu_tablet.1x.icon
@@ -18,5 +18,4 @@
 R_V_LINE_TO, 8,
 H_LINE_TO, 5,
 V_LINE_TO, 6,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_tablet.icon b/ash/resources/vector_icons/system_menu_tablet.icon
index 595873d..49cb10e 100644
--- a/ash/resources/vector_icons/system_menu_tablet.icon
+++ b/ash/resources/vector_icons/system_menu_tablet.icon
@@ -18,5 +18,4 @@
 V_LINE_TO, 11,
 R_H_LINE_TO, 20,
 R_V_LINE_TO, 18,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_timer.1x.icon b/ash/resources/vector_icons/system_menu_timer.1x.icon
index bfc0b90..7f9d8c6 100644
--- a/ash/resources/vector_icons/system_menu_timer.1x.icon
+++ b/ash/resources/vector_icons/system_menu_timer.1x.icon
@@ -28,5 +28,4 @@
 V_LINE_TO, 8,
 H_LINE_TO, 9,
 R_V_LINE_TO, 4,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_timer.icon b/ash/resources/vector_icons/system_menu_timer.icon
index b3e4bb97..22f61938 100644
--- a/ash/resources/vector_icons/system_menu_timer.icon
+++ b/ash/resources/vector_icons/system_menu_timer.icon
@@ -30,5 +30,4 @@
 R_V_LINE_TO, -8,
 R_H_LINE_TO, -3,
 R_V_LINE_TO, 8,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_tracing.1x.icon b/ash/resources/vector_icons/system_menu_tracing.1x.icon
index ca67b2c..8e6bcf3 100644
--- a/ash/resources/vector_icons/system_menu_tracing.1x.icon
+++ b/ash/resources/vector_icons/system_menu_tracing.1x.icon
@@ -30,5 +30,4 @@
 R_V_LINE_TO, -4,
 R_H_LINE_TO, 2,
 R_V_LINE_TO, 4,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_tracing.icon b/ash/resources/vector_icons/system_menu_tracing.icon
index ecdbaa5..14f7eb40 100644
--- a/ash/resources/vector_icons/system_menu_tracing.icon
+++ b/ash/resources/vector_icons/system_menu_tracing.icon
@@ -30,5 +30,4 @@
 R_V_LINE_TO, -7,
 R_H_LINE_TO, 3,
 R_V_LINE_TO, 7,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_update.1x.icon b/ash/resources/vector_icons/system_menu_update.1x.icon
index 8a65ffb..b13dfe1b 100644
--- a/ash/resources/vector_icons/system_menu_update.1x.icon
+++ b/ash/resources/vector_icons/system_menu_update.1x.icon
@@ -17,5 +17,4 @@
 R_LINE_TO, -5, 6,
 R_H_LINE_TO, 3,
 R_V_LINE_TO, 3,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_update.icon b/ash/resources/vector_icons/system_menu_update.icon
index 1da0254..28a0cadc 100644
--- a/ash/resources/vector_icons/system_menu_update.icon
+++ b/ash/resources/vector_icons/system_menu_update.icon
@@ -17,5 +17,4 @@
 LINE_TO, 10, 23,
 R_H_LINE_TO, 6,
 R_V_LINE_TO, 6,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_usb.1x.icon b/ash/resources/vector_icons/system_menu_usb.1x.icon
index d7ceaa62d..e9f5b7e 100644
--- a/ash/resources/vector_icons/system_menu_usb.1x.icon
+++ b/ash/resources/vector_icons/system_menu_usb.1x.icon
@@ -35,5 +35,4 @@
 R_V_LINE_TO, -3.02f,
 R_H_LINE_TO, -2.96f,
 R_V_LINE_TO, 3.02f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_usb.icon b/ash/resources/vector_icons/system_menu_usb.icon
index 2ca56a8..0d2713d 100644
--- a/ash/resources/vector_icons/system_menu_usb.icon
+++ b/ash/resources/vector_icons/system_menu_usb.icon
@@ -35,5 +35,4 @@
 R_V_LINE_TO, -6.04f,
 R_H_LINE_TO, -5.91f,
 R_V_LINE_TO, 6.04f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_videocam.1x.icon b/ash/resources/vector_icons/system_menu_videocam.1x.icon
index e9e933d..6035f7d7 100644
--- a/ash/resources/vector_icons/system_menu_videocam.1x.icon
+++ b/ash/resources/vector_icons/system_menu_videocam.1x.icon
@@ -18,5 +18,4 @@
 R_V_LINE_TO, 9,
 LINE_TO, 14, 12,
 V_LINE_TO, 8.5f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_videocam.icon b/ash/resources/vector_icons/system_menu_videocam.icon
index dc3d2091..4c484c9 100644
--- a/ash/resources/vector_icons/system_menu_videocam.icon
+++ b/ash/resources/vector_icons/system_menu_videocam.icon
@@ -18,5 +18,4 @@
 R_V_LINE_TO, 18,
 R_LINE_TO, -6, -5,
 R_V_LINE_TO, -7,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_volume_high.1x.icon b/ash/resources/vector_icons/system_menu_volume_high.1x.icon
index 1144ee66..80835fc2 100644
--- a/ash/resources/vector_icons/system_menu_volume_high.1x.icon
+++ b/ash/resources/vector_icons/system_menu_volume_high.1x.icon
@@ -23,5 +23,4 @@
 R_CUBIC_TO, 3.44f, -0.78f, 6, -3.84f, 6, -7.5f,
 R_CUBIC_TO, 0, -3.66f, -2.56f, -6.72f, -6, -7.5f,
 R_V_LINE_TO, 1.76f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_volume_high.icon b/ash/resources/vector_icons/system_menu_volume_high.icon
index c4d53f0a4..ba69d04 100644
--- a/ash/resources/vector_icons/system_menu_volume_high.icon
+++ b/ash/resources/vector_icons/system_menu_volume_high.icon
@@ -23,5 +23,4 @@
 R_CUBIC_TO, 6.87f, -1.56f, 12, -7.68f, 12, -15,
 CUBIC_TO_SHORTHAND, 29.87f, 6.56f, 23, 5,
 R_V_LINE_TO, 3.52f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_volume_low.1x.icon b/ash/resources/vector_icons/system_menu_volume_low.1x.icon
index f886c6d..db8b384 100644
--- a/ash/resources/vector_icons/system_menu_volume_low.1x.icon
+++ b/ash/resources/vector_icons/system_menu_volume_low.1x.icon
@@ -9,5 +9,4 @@
 V_LINE_TO, 3,
 LINE_TO, 5.47f, 7,
 H_LINE_TO, 2,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_volume_low.icon b/ash/resources/vector_icons/system_menu_volume_low.icon
index f37f4d5..a8ea90d 100644
--- a/ash/resources/vector_icons/system_menu_volume_low.icon
+++ b/ash/resources/vector_icons/system_menu_volume_low.icon
@@ -9,5 +9,4 @@
 R_LINE_TO, 8.5f, 9,
 V_LINE_TO, 6,
 R_LINE_TO, -8.5f, 9,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_volume_medium.1x.icon b/ash/resources/vector_icons/system_menu_volume_medium.1x.icon
index fead053..c3ecec8 100644
--- a/ash/resources/vector_icons/system_menu_volume_medium.1x.icon
+++ b/ash/resources/vector_icons/system_menu_volume_medium.1x.icon
@@ -15,5 +15,4 @@
 R_V_LINE_TO, 7,
 R_CUBIC_TO, 1.78f, -0.63f, 2.5f, -2.5f, 2.5f, -3.5f,
 R_CUBIC_TO, 0, -1, -0.72f, -2.86f, -2.5f, -3.5f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_volume_medium.icon b/ash/resources/vector_icons/system_menu_volume_medium.icon
index 47f4f965..ee3bc081 100644
--- a/ash/resources/vector_icons/system_menu_volume_medium.icon
+++ b/ash/resources/vector_icons/system_menu_volume_medium.icon
@@ -15,5 +15,4 @@
 R_LINE_TO, -8.45f, 9,
 H_LINE_TO, 5,
 R_V_LINE_TO, 10,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_volume_mute.1x.icon b/ash/resources/vector_icons/system_menu_volume_mute.1x.icon
index a3019c62..61ef7f6 100644
--- a/ash/resources/vector_icons/system_menu_volume_mute.1x.icon
+++ b/ash/resources/vector_icons/system_menu_volume_mute.1x.icon
@@ -38,5 +38,4 @@
 LINE_TO, 8.14f, 4.75f,
 LINE_TO, 10, 6.6f,
 V_LINE_TO, 2.89f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_menu_volume_mute.icon b/ash/resources/vector_icons/system_menu_volume_mute.icon
index 7467f11..d06982d 100644
--- a/ash/resources/vector_icons/system_menu_volume_mute.icon
+++ b/ash/resources/vector_icons/system_menu_volume_mute.icon
@@ -38,5 +38,4 @@
 R_LINE_TO, -3.48f, 3.48f,
 LINE_TO, 20, 13.63f,
 V_LINE_TO, 6.67f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_power_button_menu_power_off.1x.icon b/ash/resources/vector_icons/system_power_button_menu_power_off.1x.icon
index 7ec17a8a..c3e5729 100644
--- a/ash/resources/vector_icons/system_power_button_menu_power_off.1x.icon
+++ b/ash/resources/vector_icons/system_power_button_menu_power_off.1x.icon
@@ -20,5 +20,4 @@
 CUBIC_TO, 3, 16.97f, 7.03f, 21, 12, 21,
 CUBIC_TO, 16.97f, 21, 21, 16.97f, 21, 12,
 CUBIC_TO, 21, 9.26f, 19.77f, 6.82f, 17.83f, 5.17f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_power_button_menu_power_off.icon b/ash/resources/vector_icons/system_power_button_menu_power_off.icon
index 16dcf407..290036b 100644
--- a/ash/resources/vector_icons/system_power_button_menu_power_off.icon
+++ b/ash/resources/vector_icons/system_power_button_menu_power_off.icon
@@ -19,5 +19,4 @@
 CUBIC_TO, 6, 33.94f, 14.06f, 42, 24, 42,
 CUBIC_TO, 33.94f, 42, 42, 33.94f, 42, 24,
 CUBIC_TO, 42, 18.52f, 39.54f, 13.64f, 35.66f, 10.34f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_power_button_menu_sign_out.1x.icon b/ash/resources/vector_icons/system_power_button_menu_sign_out.1x.icon
index 12b7a60..1ce82f4d 100644
--- a/ash/resources/vector_icons/system_power_button_menu_sign_out.1x.icon
+++ b/ash/resources/vector_icons/system_power_button_menu_sign_out.1x.icon
@@ -31,5 +31,4 @@
 CUBIC_TO, 20.1f, 21, 21, 20.1f, 21, 19,
 LINE_TO, 21, 5,
 CUBIC_TO, 21, 3.9f, 20.1f, 3, 19, 3,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_power_button_menu_sign_out.icon b/ash/resources/vector_icons/system_power_button_menu_sign_out.icon
index e369261..40486df 100644
--- a/ash/resources/vector_icons/system_power_button_menu_sign_out.icon
+++ b/ash/resources/vector_icons/system_power_button_menu_sign_out.icon
@@ -30,5 +30,4 @@
 CUBIC_TO, 40.2f, 42, 42, 40.2f, 42, 38,
 LINE_TO, 42, 10,
 CUBIC_TO, 42, 7.8f, 40.2f, 6, 38, 6,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_tray_accessibility.1x.icon b/ash/resources/vector_icons/system_tray_accessibility.1x.icon
index 0187049..be68c83 100644
--- a/ash/resources/vector_icons/system_tray_accessibility.1x.icon
+++ b/ash/resources/vector_icons/system_tray_accessibility.1x.icon
@@ -23,5 +23,4 @@
 CUBIC_TO, 9.85f, 3.59f, 9.25f, 3, 8.52f, 3,
 R_CUBIC_TO, -0.73f, 0, -1.33f, 0.59f, -1.33f, 1.31f,
 R_CUBIC_TO, 0, 0.72f, 0.6f, 1.31f, 1.33f, 1.31f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_tray_accessibility.icon b/ash/resources/vector_icons/system_tray_accessibility.icon
index 8c3f1ce..f24ceb9 100644
--- a/ash/resources/vector_icons/system_tray_accessibility.icon
+++ b/ash/resources/vector_icons/system_tray_accessibility.icon
@@ -21,5 +21,4 @@
 R_MOVE_TO, 0, -1.94f,
 R_ARC_TO, 2.5f, 2.5f, 0, 1, 0, 0, -5,
 R_ARC_TO, 2.5f, 2.5f, 0, 0, 0, 0, 5,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_tray_battery_alert.1x.icon b/ash/resources/vector_icons/system_tray_battery_alert.1x.icon
index cc7d6a1..91e7fb3f 100644
--- a/ash/resources/vector_icons/system_tray_battery_alert.1x.icon
+++ b/ash/resources/vector_icons/system_tray_battery_alert.1x.icon
@@ -14,5 +14,4 @@
 R_V_LINE_TO, 2,
 H_LINE_TO, 7,
 R_V_LINE_TO, -2,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_tray_battery_alert.icon b/ash/resources/vector_icons/system_tray_battery_alert.icon
index 3da507dc..8670cb6f 100644
--- a/ash/resources/vector_icons/system_tray_battery_alert.icon
+++ b/ash/resources/vector_icons/system_tray_battery_alert.icon
@@ -14,5 +14,4 @@
 R_V_LINE_TO, 2,
 R_H_LINE_TO, -2,
 R_V_LINE_TO, -2,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_tray_battery_bolt.1x.icon b/ash/resources/vector_icons/system_tray_battery_bolt.1x.icon
index 2e66eb2..87bdf57 100644
--- a/ash/resources/vector_icons/system_tray_battery_bolt.1x.icon
+++ b/ash/resources/vector_icons/system_tray_battery_bolt.1x.icon
@@ -9,5 +9,4 @@
 R_V_LINE_TO, 3.5f,
 H_LINE_TO, 10,
 LINE_TO, 7.52f, 12,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_tray_battery_bolt.icon b/ash/resources/vector_icons/system_tray_battery_bolt.icon
index 413dd9a..6f64a3c 100644
--- a/ash/resources/vector_icons/system_tray_battery_bolt.icon
+++ b/ash/resources/vector_icons/system_tray_battery_bolt.icon
@@ -9,5 +9,4 @@
 R_V_LINE_TO, 7,
 H_LINE_TO, 20,
 R_LINE_TO, -4.97f, 9,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_tray_battery_unreliable.1x.icon b/ash/resources/vector_icons/system_tray_battery_unreliable.1x.icon
index ce744ea6..e489428 100644
--- a/ash/resources/vector_icons/system_tray_battery_unreliable.1x.icon
+++ b/ash/resources/vector_icons/system_tray_battery_unreliable.1x.icon
@@ -12,5 +12,4 @@
 R_V_LINE_TO, 1.19f,
 R_CUBIC_TO, 0, 0, -0.19f, 0.63f, -1.22f, 0.63f,
 R_CUBIC_TO, -1.03f, 0, -1.53f, -1.25f, -2.53f, -1.23f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_tray_battery_unreliable.icon b/ash/resources/vector_icons/system_tray_battery_unreliable.icon
index 371f6b2..4c8920d 100644
--- a/ash/resources/vector_icons/system_tray_battery_unreliable.icon
+++ b/ash/resources/vector_icons/system_tray_battery_unreliable.icon
@@ -12,5 +12,4 @@
 R_V_LINE_TO, 1.98f,
 R_CUBIC_TO, 0, 0, -0.38f, 1.05f, -2.44f, 1.05f,
 R_CUBIC_TO, -2.06f, 0, -3.07f, -2.08f, -5.06f, -2.05f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_tray_battery_x.1x.icon b/ash/resources/vector_icons/system_tray_battery_x.1x.icon
index 294277a..81e484d 100644
--- a/ash/resources/vector_icons/system_tray_battery_x.1x.icon
+++ b/ash/resources/vector_icons/system_tray_battery_x.1x.icon
@@ -16,5 +16,4 @@
 LINE_TO, 9.33f, 11,
 R_LINE_TO, 0.67f, -0.67f,
 LINE_TO, 8.67f, 9,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_tray_battery_x.icon b/ash/resources/vector_icons/system_tray_battery_x.icon
index 2bf2cfe..9d8fd327e 100644
--- a/ash/resources/vector_icons/system_tray_battery_x.icon
+++ b/ash/resources/vector_icons/system_tray_battery_x.icon
@@ -16,5 +16,4 @@
 LINE_TO, 18.67f, 22,
 LINE_TO, 20, 20.67f,
 LINE_TO, 17.33f, 18,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_tray_caps_lock.1x.icon b/ash/resources/vector_icons/system_tray_caps_lock.1x.icon
index 07342fa..95a9126 100644
--- a/ash/resources/vector_icons/system_tray_caps_lock.1x.icon
+++ b/ash/resources/vector_icons/system_tray_caps_lock.1x.icon
@@ -16,5 +16,4 @@
 R_V_LINE_TO, -2,
 H_LINE_TO, 4,
 R_V_LINE_TO, 2,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_tray_caps_lock.icon b/ash/resources/vector_icons/system_tray_caps_lock.icon
index d8cd7bc..7a5c551 100644
--- a/ash/resources/vector_icons/system_tray_caps_lock.icon
+++ b/ash/resources/vector_icons/system_tray_caps_lock.icon
@@ -16,5 +16,4 @@
 R_V_LINE_TO, -3,
 H_LINE_TO, 8,
 R_V_LINE_TO, 3,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_tray_cast.1x.icon b/ash/resources/vector_icons/system_tray_cast.1x.icon
index 3d540eb..09d17d1 100644
--- a/ash/resources/vector_icons/system_tray_cast.1x.icon
+++ b/ash/resources/vector_icons/system_tray_cast.1x.icon
@@ -41,5 +41,4 @@
 R_CUBIC_TO, 0.55f, 0, 1, -0.45f, 1, -1,
 V_LINE_TO, 5,
 R_CUBIC_TO, 0, -0.55f, -0.45f, -1, -1, -1,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_tray_cast.icon b/ash/resources/vector_icons/system_tray_cast.icon
index 7de458f..4ffc1401 100644
--- a/ash/resources/vector_icons/system_tray_cast.icon
+++ b/ash/resources/vector_icons/system_tray_cast.icon
@@ -51,5 +51,4 @@
 R_CUBIC_TO, 1.1f, 0, 2, -0.9f, 2, -2,
 V_LINE_TO, 9,
 R_CUBIC_TO, 0, -1.1f, -0.9f, -2, -2, -2,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_tray_night_light.1x.icon b/ash/resources/vector_icons/system_tray_night_light.1x.icon
index 17b0c5c..e05838fa 100644
--- a/ash/resources/vector_icons/system_tray_night_light.1x.icon
+++ b/ash/resources/vector_icons/system_tray_night_light.1x.icon
@@ -17,5 +17,4 @@
 CUBIC_TO, 6.54f, 11.93f, 4.76f, 9.67f, 4.76f, 7,
 CUBIC_TO, 4.76f, 4.33f, 6.54f, 2.07f, 9, 1.29f,
 LINE_TO, 9, 1.29f,
-CLOSE,
-END
\ No newline at end of file
+CLOSE
diff --git a/ash/resources/vector_icons/system_tray_night_light.icon b/ash/resources/vector_icons/system_tray_night_light.icon
index 8d49fe7..1ccd9c5 100644
--- a/ash/resources/vector_icons/system_tray_night_light.icon
+++ b/ash/resources/vector_icons/system_tray_night_light.icon
@@ -16,5 +16,4 @@
 R_CUBIC_TO, 1.15f, 0, 2.26f, -0.19f, 3.29f, -0.53f,
 R_CUBIC_TO, -4.3f, -1.43f, -7.41f, -5.58f, -7.41f, -10.47f,
 R_CUBIC_TO, 0, -4.89f, 3.11f, -9.04f, 7.41f, -10.47f,
-CLOSE,
-END
\ No newline at end of file
+CLOSE
diff --git a/ash/resources/vector_icons/system_tray_recording.1x.icon b/ash/resources/vector_icons/system_tray_recording.1x.icon
index 67c6d7a5..1d33b65 100644
--- a/ash/resources/vector_icons/system_tray_recording.1x.icon
+++ b/ash/resources/vector_icons/system_tray_recording.1x.icon
@@ -5,5 +5,4 @@
 CANVAS_DIMENSIONS, 16,
 CIRCLE, 8, 8, 6,
 CIRCLE, 8, 8, 4.5f,
-CIRCLE, 8, 8, 3,
-END
+CIRCLE, 8, 8, 3
diff --git a/ash/resources/vector_icons/system_tray_recording.icon b/ash/resources/vector_icons/system_tray_recording.icon
index 4cc5b47c..bdc4091 100644
--- a/ash/resources/vector_icons/system_tray_recording.icon
+++ b/ash/resources/vector_icons/system_tray_recording.icon
@@ -5,5 +5,4 @@
 CANVAS_DIMENSIONS, 32,
 CIRCLE, 16, 16, 12,
 CIRCLE, 16, 16, 9,
-CIRCLE, 16, 16, 7,
-END
+CIRCLE, 16, 16, 7
diff --git a/ash/resources/vector_icons/system_tray_rotation_lock_auto.1x.icon b/ash/resources/vector_icons/system_tray_rotation_lock_auto.1x.icon
index 827ae49..a21753db 100644
--- a/ash/resources/vector_icons/system_tray_rotation_lock_auto.1x.icon
+++ b/ash/resources/vector_icons/system_tray_rotation_lock_auto.1x.icon
@@ -37,5 +37,4 @@
 R_CUBIC_TO, 0.47f, 0.47f, 1.25f, 0.47f, 1.72f, 0,
 R_LINE_TO, 4.31f, -4.27f,
 R_CUBIC_TO, 0.47f, -0.47f, 0.47f, -1.24f, 0, -1.71f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_tray_rotation_lock_auto.icon b/ash/resources/vector_icons/system_tray_rotation_lock_auto.icon
index c1b196fb..52d9765 100644
--- a/ash/resources/vector_icons/system_tray_rotation_lock_auto.icon
+++ b/ash/resources/vector_icons/system_tray_rotation_lock_auto.icon
@@ -37,5 +37,4 @@
 R_CUBIC_TO, 0.95f, 0.94f, 2.49f, 0.93f, 3.44f, -0.01f,
 R_LINE_TO, 8.62f, -8.53f,
 R_CUBIC_TO, 0.95f, -0.94f, 0.95f, -2.48f, 0, -3.42f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_tray_rotation_lock_locked.1x.icon b/ash/resources/vector_icons/system_tray_rotation_lock_locked.1x.icon
index f015dfb..45286a6 100644
--- a/ash/resources/vector_icons/system_tray_rotation_lock_locked.1x.icon
+++ b/ash/resources/vector_icons/system_tray_rotation_lock_locked.1x.icon
@@ -48,5 +48,4 @@
 R_CUBIC_TO, -0.31f, 0, -0.57f, 0.25f, -0.57f, 0.56f,
 R_V_LINE_TO, 2.22f,
 R_CUBIC_TO, 0, 0.31f, 0.26f, 0.56f, 0.57f, 0.56f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_tray_rotation_lock_locked.icon b/ash/resources/vector_icons/system_tray_rotation_lock_locked.icon
index a2d2402b..be80263a 100644
--- a/ash/resources/vector_icons/system_tray_rotation_lock_locked.icon
+++ b/ash/resources/vector_icons/system_tray_rotation_lock_locked.icon
@@ -48,5 +48,4 @@
 R_CUBIC_TO, -0.63f, 0, -1.14f, 0.5f, -1.14f, 1.11f,
 R_V_LINE_TO, 4.44f,
 CUBIC_TO, 19, 13.5f, 19.52f, 14, 20.14f, 14,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_tray_screen_share.1x.icon b/ash/resources/vector_icons/system_tray_screen_share.1x.icon
index 316ad37..661d84c 100644
--- a/ash/resources/vector_icons/system_tray_screen_share.1x.icon
+++ b/ash/resources/vector_icons/system_tray_screen_share.1x.icon
@@ -26,5 +26,4 @@
 LINE_TO, 11, 8,
 R_LINE_TO, -2.64f, 2,
 V_LINE_TO, 8.67f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_tray_screen_share.icon b/ash/resources/vector_icons/system_tray_screen_share.icon
index 517fac6..32b8cfc 100644
--- a/ash/resources/vector_icons/system_tray_screen_share.icon
+++ b/ash/resources/vector_icons/system_tray_screen_share.icon
@@ -26,5 +26,4 @@
 R_LINE_TO, 5.5f, 4.5f,
 LINE_TO, 17, 20,
 R_V_LINE_TO, -3,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_tray_tracing.1x.icon b/ash/resources/vector_icons/system_tray_tracing.1x.icon
index 9edaf34..a761968 100644
--- a/ash/resources/vector_icons/system_tray_tracing.1x.icon
+++ b/ash/resources/vector_icons/system_tray_tracing.1x.icon
@@ -30,5 +30,4 @@
 V_LINE_TO, 8,
 R_H_LINE_TO, 2,
 R_V_LINE_TO, 4,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_tray_tracing.icon b/ash/resources/vector_icons/system_tray_tracing.icon
index 2a47ba2..6d4b8d8 100644
--- a/ash/resources/vector_icons/system_tray_tracing.icon
+++ b/ash/resources/vector_icons/system_tray_tracing.icon
@@ -30,5 +30,4 @@
 R_V_LINE_TO, -7,
 R_H_LINE_TO, 3,
 R_V_LINE_TO, 7,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_tray_update.1x.icon b/ash/resources/vector_icons/system_tray_update.1x.icon
index dc3a3a3..92de678 100644
--- a/ash/resources/vector_icons/system_tray_update.1x.icon
+++ b/ash/resources/vector_icons/system_tray_update.1x.icon
@@ -17,5 +17,4 @@
 LINE_TO, 3.5f, 9,
 R_H_LINE_TO, 2.65f,
 R_V_LINE_TO, 3,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_tray_update.icon b/ash/resources/vector_icons/system_tray_update.icon
index 007cfc09..bb2c67f 100644
--- a/ash/resources/vector_icons/system_tray_update.icon
+++ b/ash/resources/vector_icons/system_tray_update.icon
@@ -17,5 +17,4 @@
 LINE_TO, 7, 18,
 R_H_LINE_TO, 5,
 R_V_LINE_TO, 6,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_tray_volume_mute.1x.icon b/ash/resources/vector_icons/system_tray_volume_mute.1x.icon
index 1d7202e..c2810f15 100644
--- a/ash/resources/vector_icons/system_tray_volume_mute.1x.icon
+++ b/ash/resources/vector_icons/system_tray_volume_mute.1x.icon
@@ -38,5 +38,4 @@
 LINE_TO, 6.61f, 4.06f,
 LINE_TO, 8, 5.45f,
 V_LINE_TO, 2.67f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/system_tray_volume_mute.icon b/ash/resources/vector_icons/system_tray_volume_mute.icon
index e2bbd094..a2479b9 100644
--- a/ash/resources/vector_icons/system_tray_volume_mute.icon
+++ b/ash/resources/vector_icons/system_tray_volume_mute.icon
@@ -38,5 +38,4 @@
 LINE_TO, 13.21f, 8.12f,
 LINE_TO, 16, 10.91f,
 V_LINE_TO, 5.33f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/touch_calibration_complete_check.1x.icon b/ash/resources/vector_icons/touch_calibration_complete_check.1x.icon
index fb32c214..0b8d779 100644
--- a/ash/resources/vector_icons/touch_calibration_complete_check.1x.icon
+++ b/ash/resources/vector_icons/touch_calibration_complete_check.1x.icon
@@ -18,5 +18,4 @@
 LINE_TO, 50.67f, 21.33f,
 LINE_TO, 26.67f, 45.33f,
 LINE_TO, 26.67f, 45.33f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/touch_calibration_complete_check.icon b/ash/resources/vector_icons/touch_calibration_complete_check.icon
index 7c6f4f5c..14b14f0 100644
--- a/ash/resources/vector_icons/touch_calibration_complete_check.icon
+++ b/ash/resources/vector_icons/touch_calibration_complete_check.icon
@@ -18,5 +18,4 @@
 LINE_TO, 101.33f, 42.67f,
 LINE_TO, 53.33f, 90.67f,
 LINE_TO, 53.33f, 90.67f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/touch_calibration_hand.icon b/ash/resources/vector_icons/touch_calibration_hand.icon
index cca81278..63501ec9 100644
--- a/ash/resources/vector_icons/touch_calibration_hand.icon
+++ b/ash/resources/vector_icons/touch_calibration_hand.icon
@@ -28,5 +28,4 @@
 LINE_TO, 22.98f, 20.89f,
 LINE_TO, 14.58f, 23.23f,
 LINE_TO, 23.02f, 20.89f,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/tray_action_new_lock_screen_note.1x.icon b/ash/resources/vector_icons/tray_action_new_lock_screen_note.1x.icon
index 6d9de85..e3fd929 100644
--- a/ash/resources/vector_icons/tray_action_new_lock_screen_note.1x.icon
+++ b/ash/resources/vector_icons/tray_action_new_lock_screen_note.1x.icon
@@ -17,5 +17,4 @@
 LINE_TO, 9, 2.53f,
 LINE_TO, 12.54f, 6,
 LINE_TO, 9, 6,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/tray_action_new_lock_screen_note.icon b/ash/resources/vector_icons/tray_action_new_lock_screen_note.icon
index 2793144..df9d179 100644
--- a/ash/resources/vector_icons/tray_action_new_lock_screen_note.icon
+++ b/ash/resources/vector_icons/tray_action_new_lock_screen_note.icon
@@ -17,5 +17,4 @@
 LINE_TO, 17.33f, 4.67f,
 LINE_TO, 24.67f, 12,
 LINE_TO, 17.33f, 12,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/window_control_back.1x.icon b/ash/resources/vector_icons/window_control_back.1x.icon
index 54a037c..d7865b2 100644
--- a/ash/resources/vector_icons/window_control_back.1x.icon
+++ b/ash/resources/vector_icons/window_control_back.1x.icon
@@ -15,5 +15,4 @@
 LINE_TO, 6.6f, 1,
 LINE_TO, 8, 2.25f,
 LINE_TO, 4.92f, 5,
-CLOSE,
-END
+CLOSE
diff --git a/ash/resources/vector_icons/window_control_back.icon b/ash/resources/vector_icons/window_control_back.icon
index 679d4d1..1820b1a8 100644
--- a/ash/resources/vector_icons/window_control_back.icon
+++ b/ash/resources/vector_icons/window_control_back.icon
@@ -16,5 +16,4 @@
 LINE_TO, 12.86f, 0,
 LINE_TO, 15, 2.05f,
 LINE_TO, 6.83f, 10,
-CLOSE,
-END
+CLOSE
diff --git a/ash/shelf/app_list_shelf_item_delegate.cc b/ash/shelf/app_list_shelf_item_delegate.cc
index db19d98a..5f34826 100644
--- a/ash/shelf/app_list_shelf_item_delegate.cc
+++ b/ash/shelf/app_list_shelf_item_delegate.cc
@@ -22,8 +22,8 @@
                                             int64_t display_id,
                                             ShelfLaunchSource source,
                                             ItemSelectedCallback callback) {
-  Shell::Get()->app_list_controller()->ToggleAppList(display_id,
-                                                     app_list::kShelfButton);
+  Shell::Get()->app_list_controller()->ToggleAppList(
+      display_id, app_list::kShelfButton, event->time_stamp());
   std::move(callback).Run(SHELF_ACTION_APP_LIST_SHOWN, base::nullopt);
 }
 
diff --git a/ash/shelf/shelf_layout_manager.cc b/ash/shelf/shelf_layout_manager.cc
index eda5b98..3864947 100644
--- a/ash/shelf/shelf_layout_manager.cc
+++ b/ash/shelf/shelf_layout_manager.cc
@@ -1131,7 +1131,7 @@
         display::Screen::GetScreen()
             ->GetDisplayNearestWindow(shelf_widget_->GetNativeWindow())
             .id(),
-        app_list::kSwipeFromShelf);
+        app_list::kSwipeFromShelf, gesture_in_screen.time_stamp());
     Shell::Get()->app_list_controller()->UpdateYPositionAndOpacity(
         shelf_bounds.y(), GetAppListBackgroundOpacityOnShelfOpacity());
     launcher_above_shelf_bottom_amount_ =
diff --git a/ash/wm/splitview/split_view_controller.cc b/ash/wm/splitview/split_view_controller.cc
index 85b971ec..006da6f 100644
--- a/ash/wm/splitview/split_view_controller.cc
+++ b/ash/wm/splitview/split_view_controller.cc
@@ -350,6 +350,24 @@
   return bounds;
 }
 
+gfx::Rect SplitViewController::GetSnappedWindowBoundsInScreenUnadjusted(
+    aura::Window* window,
+    SnapPosition snap_position) {
+  const gfx::Rect work_area_bounds_in_screen =
+      GetDisplayWorkAreaBoundsInScreen(window);
+  if (snap_position == NONE)
+    return work_area_bounds_in_screen;
+
+  gfx::Rect left_or_top_rect, right_or_bottom_rect;
+  GetSnappedWindowBoundsInScreenInternal(window, &left_or_top_rect,
+                                         &right_or_bottom_rect);
+
+  if (IsCurrentScreenOrientationPrimary())
+    return (snap_position == LEFT) ? left_or_top_rect : right_or_bottom_rect;
+  else
+    return (snap_position == LEFT) ? right_or_bottom_rect : left_or_top_rect;
+}
+
 void SplitViewController::StartResize(const gfx::Point& location_in_screen) {
   DCHECK(IsSplitViewModeActive());
   is_resizing_ = true;
diff --git a/ash/wm/splitview/split_view_controller.h b/ash/wm/splitview/split_view_controller.h
index 1a9ac07c..2f4be52 100644
--- a/ash/wm/splitview/split_view_controller.h
+++ b/ash/wm/splitview/split_view_controller.h
@@ -104,7 +104,10 @@
   aura::Window* GetDefaultSnappedWindow();
 
   // Gets the window bounds according to the snap state |snap_state| and the
-  // separator position |separator_position_|.
+  // divider position |divider_position_|. The returned snapped window bounds
+  // are adjusted to its minimum size if the desired bounds are smaller than
+  // its minumum bounds. Note: the snapped window bounds can't be pushed
+  // outside of the workspace area.
   gfx::Rect GetSnappedWindowBoundsInParent(aura::Window* window,
                                            SnapPosition snap_position);
   gfx::Rect GetSnappedWindowBoundsInScreen(aura::Window* window,
@@ -112,6 +115,11 @@
   gfx::Rect GetDisplayWorkAreaBoundsInParent(aura::Window* window) const;
   gfx::Rect GetDisplayWorkAreaBoundsInScreen(aura::Window* window) const;
 
+  // Gets the desired snapped window bounds accoridng to the snap state
+  // |snap_state| and the divider pistion |divider_position_|.
+  gfx::Rect GetSnappedWindowBoundsInScreenUnadjusted(aura::Window* window,
+                                                     SnapPosition snap_postion);
+
   void StartResize(const gfx::Point& location_in_screen);
   void Resize(const gfx::Point& location_in_screen);
   void EndResize(const gfx::Point& location_in_screen);
diff --git a/ash/wm/workspace/backdrop_controller.cc b/ash/wm/workspace/backdrop_controller.cc
index 18d13a38..0af7260 100644
--- a/ash/wm/workspace/backdrop_controller.cc
+++ b/ash/wm/workspace/backdrop_controller.cc
@@ -127,8 +127,7 @@
   if (window->GetRootWindow() != backdrop_window_->GetRootWindow())
     return;
 
-  if (!backdrop_->IsVisible())
-    Show();
+  Show();
 
   // Since the backdrop needs to be immediately behind the window and the
   // stacking functions only guarantee a "it's above or below", we need
@@ -157,11 +156,29 @@
     RemoveForceHidden();
 }
 
+void BackdropController::OnSplitViewModeStarting() {
+  Shell::Get()->split_view_controller()->AddObserver(this);
+}
+
+void BackdropController::OnSplitViewModeEnded() {
+  Shell::Get()->split_view_controller()->RemoveObserver(this);
+}
+
 void BackdropController::OnAccessibilityStatusChanged(
     AccessibilityNotificationVisibility notify) {
   UpdateBackdrop();
 }
 
+void BackdropController::OnSplitViewStateChanged(
+    SplitViewController::State previous_state,
+    SplitViewController::State state) {
+  UpdateBackdrop();
+}
+
+void BackdropController::OnSplitViewDividerPositionChanged() {
+  UpdateBackdrop();
+}
+
 void BackdropController::EnsureBackdropWidget() {
   if (backdrop_)
     return;
@@ -236,8 +253,12 @@
 }
 
 void BackdropController::Show() {
+  // Makes sure that the backdrop has the correct bounds if it should not be
+  // fullscreen size.
+  backdrop_->SetFullscreen(BackdropShouldFullscreen());
+  if (!BackdropShouldFullscreen())
+    backdrop_->SetBounds(GetBackdropBounds());
   backdrop_->Show();
-  backdrop_->SetFullscreen(true);
 }
 
 void BackdropController::Hide() {
@@ -268,4 +289,36 @@
     UpdateBackdrop();
 }
 
+bool BackdropController::BackdropShouldFullscreen() {
+  aura::Window* window = GetTopmostWindowWithBackdrop();
+  SplitViewController* split_view_controller =
+      Shell::Get()->split_view_controller();
+  SplitViewController::State state = split_view_controller->state();
+  if ((state == SplitViewController::LEFT_SNAPPED &&
+       window == split_view_controller->left_window()) ||
+      (state == SplitViewController::RIGHT_SNAPPED &&
+       window == split_view_controller->right_window())) {
+    return false;
+  }
+
+  return true;
+}
+
+gfx::Rect BackdropController::GetBackdropBounds() {
+  DCHECK(!BackdropShouldFullscreen());
+
+  SplitViewController* split_view_controller =
+      Shell::Get()->split_view_controller();
+  SplitViewController::State state = split_view_controller->state();
+  DCHECK(state == SplitViewController::LEFT_SNAPPED ||
+         state == SplitViewController::RIGHT_SNAPPED);
+  aura::Window* snapped_window =
+      split_view_controller->GetDefaultSnappedWindow();
+  SplitViewController::SnapPosition snap_position =
+      (state == SplitViewController::LEFT_SNAPPED) ? SplitViewController::LEFT
+                                                   : SplitViewController::RIGHT;
+  return split_view_controller->GetSnappedWindowBoundsInScreenUnadjusted(
+      snapped_window, snap_position);
+}
+
 }  // namespace ash
diff --git a/ash/wm/workspace/backdrop_controller.h b/ash/wm/workspace/backdrop_controller.h
index bfd72f0..9e5b460 100644
--- a/ash/wm/workspace/backdrop_controller.h
+++ b/ash/wm/workspace/backdrop_controller.h
@@ -9,6 +9,7 @@
 
 #include "ash/accessibility/accessibility_observer.h"
 #include "ash/shell_observer.h"
+#include "ash/wm/splitview/split_view_controller.h"
 #include "base/macros.h"
 
 namespace aura {
@@ -41,7 +42,9 @@
 // 1) Has a aura::client::kHasBackdrop property = true.
 // 2) BackdropDelegate::HasBackdrop(aura::Window* window) returns true.
 // 3) Active ARC window when the spoken feedback is enabled.
-class BackdropController : public ShellObserver, public AccessibilityObserver {
+class BackdropController : public ShellObserver,
+                           public AccessibilityObserver,
+                           public SplitViewController::Observer {
  public:
   explicit BackdropController(aura::Window* container);
   ~BackdropController() override;
@@ -64,11 +67,18 @@
   void OnOverviewModeEnded() override;
   void OnAppListVisibilityChanged(bool shown,
                                   aura::Window* root_window) override;
+  void OnSplitViewModeStarting() override;
+  void OnSplitViewModeEnded() override;
 
   // AccessibilityObserver:
   void OnAccessibilityStatusChanged(
       AccessibilityNotificationVisibility notify) override;
 
+  // SplitViewController::Observer:
+  void OnSplitViewStateChanged(SplitViewController::State previous_state,
+                               SplitViewController::State state) override;
+  void OnSplitViewDividerPositionChanged() override;
+
  private:
   friend class WorkspaceControllerTestApi;
 
@@ -93,6 +103,18 @@
   // Decrement |force_hidden_counter_| and then update backdrop state.
   void RemoveForceHidden();
 
+  // Returns true if the backdrop window should be fullscreen. It should not be
+  // fullscreen only if 1) split view is active and 2) there is only one snapped
+  // window and 3) the snapped window is the topmost window which should have
+  // the backdrop.
+  bool BackdropShouldFullscreen();
+
+  // Gets the bounds for the backdrop window if it should not be fullscreen.
+  // It's the case for splitview mode, if there is only one snapped window, the
+  // backdrop should not cover the non-snapped side of the screen, thus the
+  // backdrop bounds should be the bounds of the snapped window.
+  gfx::Rect GetBackdropBounds();
+
   // The backdrop which covers the rest of the screen.
   views::Widget* backdrop_ = nullptr;
 
diff --git a/ash/wm/workspace/workspace_layout_manager_unittest.cc b/ash/wm/workspace/workspace_layout_manager_unittest.cc
index 6d74359..804db01f 100644
--- a/ash/wm/workspace/workspace_layout_manager_unittest.cc
+++ b/ash/wm/workspace/workspace_layout_manager_unittest.cc
@@ -1755,15 +1755,14 @@
             default_container()->children()[0]->bounds());
 
   // Snap the window to left. Test that the backdrop window is still visible
-  // and is the second child in the container. Its bounds should still be the
-  // same as the container bounds.
+  // and is the second child in the container. Its bounds should be the same
+  // as the snapped window's bounds.
   split_view_controller->SnapWindow(window1.get(), SplitViewController::LEFT);
   EXPECT_EQ(2U, default_container()->children().size());
   for (auto* child : default_container()->children())
     EXPECT_TRUE(child->IsVisible());
   EXPECT_EQ(window1.get(), default_container()->children()[1]);
-  EXPECT_EQ(default_container()->bounds(),
-            default_container()->children()[0]->bounds());
+  EXPECT_EQ(window1->bounds(), default_container()->children()[0]->bounds());
 
   // Now snap another window to right. Test that the backdrop window is still
   // visible but is now the third window in the container. Its bounds should
diff --git a/base/android/java/templates/BuildConfig.template b/base/android/java/templates/BuildConfig.template
index 8d6f440..2b4d1a6f 100644
--- a/base/android/java/templates/BuildConfig.template
+++ b/base/android/java/templates/BuildConfig.template
@@ -18,18 +18,11 @@
  */
 public class BuildConfig {
 
-    /** Whether multidex is enabled for this target.
-     *
-     *  This has to be a function instead of a static final boolean s.t. the initial false value
-     *  doesn't get optimized into {@link ChromiumMultiDexInstaller} at base_java compile time.
-     */
-    public static boolean isMultidexEnabled() {
 #if defined(ENABLE_MULTIDEX)
-        return true;
+    public static MAYBE_FINAL boolean IS_MULTIDEX_ENABLED = true;
 #else
-        return false;
+    public static MAYBE_FINAL boolean IS_MULTIDEX_ENABLED = false;
 #endif
-    }
 
 #if defined(_FIREBASE_APP_ID)
     public static MAYBE_FINAL String FIREBASE_APP_ID = QUOTE(_FIREBASE_APP_ID);
diff --git a/base/message_loop/message_loop.cc b/base/message_loop/message_loop.cc
index 028cf9f..252cd04c 100644
--- a/base/message_loop/message_loop.cc
+++ b/base/message_loop/message_loop.cc
@@ -225,8 +225,6 @@
 
 void MessageLoop::SetNestableTasksAllowed(bool allowed) {
   if (allowed) {
-    CHECK(RunLoop::IsNestingAllowedOnCurrentThread());
-
     // Kick the native pump just in case we enter a OS-driven nested message
     // loop that does not go through RunLoop::Run().
     pump_->ScheduleWork();
@@ -243,13 +241,11 @@
 // implementation detail. http://crbug.com/703346
 void MessageLoop::AddTaskObserver(TaskObserver* task_observer) {
   DCHECK_EQ(this, current());
-  CHECK(allow_task_observers_);
   task_observers_.AddObserver(task_observer);
 }
 
 void MessageLoop::RemoveTaskObserver(TaskObserver* task_observer) {
   DCHECK_EQ(this, current());
-  CHECK(allow_task_observers_);
   task_observers_.RemoveObserver(task_observer);
 }
 
diff --git a/base/message_loop/message_loop.h b/base/message_loop/message_loop.h
index 27ee7fe..2f4f24f 100644
--- a/base/message_loop/message_loop.h
+++ b/base/message_loop/message_loop.h
@@ -276,10 +276,6 @@
   // Runs the specified PendingTask.
   void RunTask(PendingTask* pending_task);
 
-  // Disallow task observers. After this is called, calling
-  // Add/RemoveTaskObserver() on this MessageLoop will crash.
-  void DisallowTaskObservers() { allow_task_observers_ = false; }
-
   //----------------------------------------------------------------------------
  protected:
   std::unique_ptr<MessagePump> pump_;
@@ -399,9 +395,6 @@
   // MessageLoop is bound to its thread and constant forever after.
   PlatformThreadId thread_id_ = kInvalidThreadId;
 
-  // Whether task observers are allowed.
-  bool allow_task_observers_ = true;
-
   // Holds data stored through the SequenceLocalStorageSlot API.
   internal::SequenceLocalStorageMap sequence_local_storage_map_;
 
diff --git a/base/process/process_metrics.h b/base/process/process_metrics.h
index 52adb693..71ff0484 100644
--- a/base/process/process_metrics.h
+++ b/base/process/process_metrics.h
@@ -147,9 +147,6 @@
   // usage in bytes, as per definition of WorkingSetBytes. Note that this
   // function is somewhat expensive on Windows (a few ms per process).
   bool GetWorkingSetKBytes(WorkingSetKBytes* ws_usage) const;
-  // Computes pss (proportional set size) of a process. Note that this
-  // function is somewhat expensive on Windows (a few ms per process).
-  bool GetProportionalSetSizeBytes(uint64_t* pss_bytes) const;
 
 #if defined(OS_LINUX) || defined(OS_ANDROID)
   // Resident Set Size is a Linux/Android specific memory concept. Do not
diff --git a/base/process/process_metrics_win.cc b/base/process/process_metrics_win.cc
index e3b053bd..6d1c7d5 100644
--- a/base/process/process_metrics_win.cc
+++ b/base/process/process_metrics_win.cc
@@ -219,27 +219,6 @@
   return true;
 }
 
-// This function calculates the proportional set size for a process.
-bool ProcessMetrics::GetProportionalSetSizeBytes(uint64_t* pss_bytes) const {
-  double ws_pss = 0.0;
-
-  WorkingSetInformationBuffer buffer;
-  if (!buffer.QueryPageEntries(process_.Get()))
-    return false;
-
-  size_t num_page_entries = buffer.GetPageEntryCount();
-  for (size_t i = 0; i < num_page_entries; i++) {
-    if (buffer->WorkingSetInfo[i].Shared &&
-        buffer->WorkingSetInfo[i].ShareCount > 0)
-      ws_pss += 1.0 / buffer->WorkingSetInfo[i].ShareCount;
-    else
-      ws_pss += 1.0;
-  }
-
-  *pss_bytes = static_cast<uint64_t>(ws_pss * GetPageSize());
-  return true;
-}
-
 static uint64_t FileTimeToUTC(const FILETIME& ftime) {
   LARGE_INTEGER li;
   li.LowPart = ftime.dwLowDateTime;
diff --git a/base/run_loop.cc b/base/run_loop.cc
index 467e2d83..30d8c4ea 100644
--- a/base/run_loop.cc
+++ b/base/run_loop.cc
@@ -103,9 +103,6 @@
   DCHECK(delegate_) << "A RunLoop::Delegate must be bound to this thread prior "
                        "to using RunLoop.";
   DCHECK(origin_task_runner_);
-
-  DCHECK(IsNestingAllowedOnCurrentThread() ||
-         type_ != Type::kNestableTasksAllowed);
 }
 
 RunLoop::~RunLoop() {
@@ -219,7 +216,6 @@
 void RunLoop::AddNestingObserverOnCurrentThread(NestingObserver* observer) {
   Delegate* delegate = tls_delegate.Get().Get();
   DCHECK(delegate);
-  CHECK(delegate->allow_nesting_);
   delegate->nesting_observers_.AddObserver(observer);
 }
 
@@ -227,21 +223,10 @@
 void RunLoop::RemoveNestingObserverOnCurrentThread(NestingObserver* observer) {
   Delegate* delegate = tls_delegate.Get().Get();
   DCHECK(delegate);
-  CHECK(delegate->allow_nesting_);
   delegate->nesting_observers_.RemoveObserver(observer);
 }
 
 // static
-bool RunLoop::IsNestingAllowedOnCurrentThread() {
-  return tls_delegate.Get().Get()->allow_nesting_;
-}
-
-// static
-void RunLoop::DisallowNestingOnCurrentThread() {
-  tls_delegate.Get().Get()->allow_nesting_ = false;
-}
-
-// static
 void RunLoop::QuitCurrentDeprecated() {
   DCHECK(IsRunningOnCurrentThread());
   tls_delegate.Get().Get()->active_run_loops_.top()->Quit();
@@ -301,7 +286,6 @@
   const bool is_nested = active_run_loops_.size() > 1;
 
   if (is_nested) {
-    CHECK(delegate_->allow_nesting_);
     for (auto& observer : delegate_->nesting_observers_)
       observer.OnBeginNestedRunLoop();
     if (type_ == Type::kNestableTasksAllowed)
diff --git a/base/run_loop.h b/base/run_loop.h
index b7c594e1..d3858fce 100644
--- a/base/run_loop.h
+++ b/base/run_loop.h
@@ -50,9 +50,7 @@
   // recursive task processing is disabled.
   //
   // In general, nestable RunLoops are to be avoided. They are dangerous and
-  // difficult to get right, so please use with extreme caution. To further
-  // protect this: kNestableTasksAllowed RunLoops are only allowed on threads
-  // where IsNestingAllowedOnCurrentThread().
+  // difficult to get right, so please use with extreme caution.
   //
   // A specific example where this makes a difference is:
   // - The thread is running a RunLoop.
@@ -145,13 +143,6 @@
   static void AddNestingObserverOnCurrentThread(NestingObserver* observer);
   static void RemoveNestingObserverOnCurrentThread(NestingObserver* observer);
 
-  // Returns true if nesting is allowed on this thread.
-  static bool IsNestingAllowedOnCurrentThread();
-
-  // Disallow nesting. After this is called, running a nested RunLoop or calling
-  // Add/RemoveNestingObserverOnCurrentThread() on this thread will crash.
-  static void DisallowNestingOnCurrentThread();
-
   // A RunLoop::Delegate is a generic interface that allows RunLoop to be
   // separate from the underlying implementation of the message loop for this
   // thread. It holds private state used by RunLoops on its associated thread.
@@ -207,7 +198,6 @@
     // have more than a few entries.
     using RunLoopStack = base::stack<RunLoop*, std::vector<RunLoop*>>;
 
-    bool allow_nesting_ = true;
     RunLoopStack active_run_loops_;
     ObserverList<RunLoop::NestingObserver> nesting_observers_;
 
diff --git a/base/run_loop_unittest.cc b/base/run_loop_unittest.cc
index 96060f4a..ee12ea5 100644
--- a/base/run_loop_unittest.cc
+++ b/base/run_loop_unittest.cc
@@ -596,8 +596,6 @@
 }  // namespace
 
 TEST_P(RunLoopTest, NestingObservers) {
-  EXPECT_TRUE(RunLoop::IsNestingAllowedOnCurrentThread());
-
   testing::StrictMock<MockNestingObserver> nesting_observer;
   testing::StrictMock<MockTask> mock_task_a;
   testing::StrictMock<MockTask> mock_task_b;
@@ -606,10 +604,6 @@
 
   const RepeatingClosure run_nested_loop = Bind([]() {
     RunLoop nested_run_loop(RunLoop::Type::kNestableTasksAllowed);
-    ThreadTaskRunnerHandle::Get()->PostTask(
-        FROM_HERE, BindOnce([]() {
-          EXPECT_TRUE(RunLoop::IsNestingAllowedOnCurrentThread());
-        }));
     ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
                                             nested_run_loop.QuitClosure());
     nested_run_loop.Run();
@@ -617,7 +611,9 @@
 
   // Generate a stack of nested RunLoops. OnBeginNestedRunLoop() is expected
   // when beginning each nesting depth and OnExitNestedRunLoop() is expected
-  // when exiting each nesting depth.
+  // when exiting each nesting depth. Each one of these tasks is ahead of the
+  // QuitClosures as those are only posted at the end of the queue when
+  // |run_nested_loop| is executed.
   ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, run_nested_loop);
   ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
@@ -640,21 +636,6 @@
   RunLoop::RemoveNestingObserverOnCurrentThread(&nesting_observer);
 }
 
-// Disabled on Android per http://crbug.com/643760.
-#if defined(GTEST_HAS_DEATH_TEST) && !defined(OS_ANDROID)
-TEST_P(RunLoopTest, DisallowNestingDeathTest) {
-  EXPECT_TRUE(RunLoop::IsNestingAllowedOnCurrentThread());
-  RunLoop::DisallowNestingOnCurrentThread();
-  EXPECT_FALSE(RunLoop::IsNestingAllowedOnCurrentThread());
-
-  ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, BindOnce([]() {
-                                            RunLoop nested_run_loop;
-                                            nested_run_loop.RunUntilIdle();
-                                          }));
-  EXPECT_DEATH({ run_loop_.RunUntilIdle(); }, "");
-}
-#endif  // defined(GTEST_HAS_DEATH_TEST) && !defined(OS_ANDROID)
-
 TEST_P(RunLoopTest, DisallowRunningForTesting) {
   RunLoop::ScopedDisallowRunningForTesting disallow_running;
   EXPECT_DCHECK_DEATH({ run_loop_.Run(); });
diff --git a/base/test/BUILD.gn b/base/test/BUILD.gn
index b64b9840..5537bbd4 100644
--- a/base/test/BUILD.gn
+++ b/base/test/BUILD.gn
@@ -2,6 +2,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import("//build/compiled_action.gni")
 import("//build/config/ui.gni")
 import("//build/config/nacl/config.gni")
 
@@ -184,6 +185,17 @@
     ]
   }
 
+  if (is_linux) {
+    public_deps += [ ":fontconfig_util_linux" ]
+    data_deps = [
+      "//third_party/test_fonts",
+    ]
+    if (current_toolchain == host_toolchain) {
+      data_deps += [ ":do_generate_fontconfig_caches" ]
+      data += [ "$root_out_dir/fontconfig_caches/" ]
+    }
+  }
+
   if (is_ios) {
     set_sources_assignment_filter([])
     sources += [ "test_file_util_mac.cc" ]
@@ -317,6 +329,43 @@
 }
 
 if (is_linux) {
+  source_set("fontconfig_util_linux") {
+    sources = [
+      "fontconfig_util_linux.cc",
+      "fontconfig_util_linux.h",
+    ]
+    deps = [
+      "//base",
+      "//third_party/fontconfig",
+    ]
+  }
+
+  if (current_toolchain == host_toolchain) {
+    executable("generate_fontconfig_caches") {
+      testonly = true
+      sources = [
+        "generate_fontconfig_caches.cc",
+      ]
+      deps = [
+        ":fontconfig_util_linux",
+        "//base",
+        "//build/config:exe_and_shlib_deps",
+      ]
+    }
+
+    compiled_action("do_generate_fontconfig_caches") {
+      testonly = true
+      tool = ":generate_fontconfig_caches"
+      data_deps = [
+        "//third_party/test_fonts",
+      ]
+      args = []
+      outputs = [
+        "$root_out_dir/fontconfig_caches/STAMP",
+      ]
+    }
+  }
+
   shared_library("malloc_wrapper") {
     testonly = true
     sources = [
diff --git a/base/test/fontconfig_util_linux.cc b/base/test/fontconfig_util_linux.cc
new file mode 100644
index 0000000..cc5d496a
--- /dev/null
+++ b/base/test/fontconfig_util_linux.cc
@@ -0,0 +1,458 @@
+// 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 "base/test/fontconfig_util_linux.h"
+
+#include <fontconfig/fontconfig.h>
+
+#include "base/base_paths.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/path_service.h"
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+
+namespace base {
+
+namespace {
+
+const char kFontsConfTemplate[] = R"(<?xml version="1.0"?>
+<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
+<fontconfig>
+
+  <!-- Cache location. -->
+  <cachedir>$1</cachedir>
+
+  <!-- GCS-synced fonts. -->
+  <dir>$2</dir>
+
+  <!-- System fonts.  TODO(thomasanderson): Remove these. -->
+  <dir>/usr/share/fonts/opentype/ipafont-gothic</dir>
+  <dir>/usr/share/fonts/opentype/ipafont-mincho</dir>
+  <dir>/usr/share/fonts/truetype/msttcorefonts</dir>
+
+  <!-- Default properties. -->
+  <match target="font">
+    <edit name="embeddedbitmap" mode="append_last">
+      <bool>false</bool>
+    </edit>
+  </match>
+
+  <!-- TODO(thomasanderson): Remove once Tinos is added to GCS fonts. -->
+  <match target="pattern">
+    <test name="family" compare="eq">
+      <string>Tinos</string>
+    </test>
+    <test name="prgname" compare="eq">
+      <string>chromevox_tests</string>
+    </test>
+    <edit name="hintstyle" mode="assign">
+      <const>hintslight</const>
+    </edit>
+    <edit name="family" mode="assign">
+      <string>Times New Roman</string>
+    </edit>
+  </match>
+
+  <match target="pattern">
+    <test qual="any" name="family">
+      <string>Times</string>
+    </test>
+    <edit name="family" mode="assign">
+      <string>Times New Roman</string>
+    </edit>
+  </match>
+
+  <match target="pattern">
+    <test qual="any" name="family">
+      <string>sans</string>
+    </test>
+    <edit name="family" mode="assign">
+      <string>DejaVu Sans</string>
+    </edit>
+  </match>
+
+  <match target="pattern">
+    <test qual="any" name="family">
+      <string>sans serif</string>
+    </test>
+    <edit name="family" mode="assign">
+      <string>Arial</string>
+    </edit>
+  </match>
+
+  <!-- Some layout tests specify Helvetica as a family and we need to make sure
+       that we don't fallback to Times New Roman for them -->
+  <match target="pattern">
+    <test qual="any" name="family">
+      <string>Helvetica</string>
+    </test>
+    <edit name="family" mode="assign">
+      <string>Arial</string>
+    </edit>
+  </match>
+
+  <match target="pattern">
+    <test qual="any" name="family">
+      <string>sans-serif</string>
+    </test>
+    <edit name="family" mode="assign">
+      <string>Arial</string>
+    </edit>
+  </match>
+
+  <match target="pattern">
+    <test qual="any" name="family">
+      <string>serif</string>
+    </test>
+    <edit name="family" mode="assign">
+      <string>Times New Roman</string>
+    </edit>
+  </match>
+
+  <match target="pattern">
+    <test qual="any" name="family">
+      <string>mono</string>
+    </test>
+    <edit name="family" mode="assign">
+      <string>Courier New</string>
+    </edit>
+  </match>
+
+  <match target="pattern">
+    <test qual="any" name="family">
+      <string>monospace</string>
+    </test>
+    <edit name="family" mode="assign">
+      <string>Courier New</string>
+    </edit>
+  </match>
+
+  <match target="pattern">
+    <test qual="any" name="family">
+      <string>Courier</string>
+    </test>
+    <edit name="family" mode="assign">
+      <string>Courier New</string>
+    </edit>
+  </match>
+
+  <match target="pattern">
+    <test qual="any" name="family">
+      <string>cursive</string>
+    </test>
+    <edit name="family" mode="assign">
+      <string>Comic Sans MS</string>
+    </edit>
+  </match>
+
+  <match target="pattern">
+    <test qual="any" name="family">
+      <string>fantasy</string>
+    </test>
+    <edit name="family" mode="assign">
+      <string>Impact</string>
+    </edit>
+  </match>
+
+  <match target="pattern">
+    <test qual="any" name="family">
+      <string>Monaco</string>
+    </test>
+    <edit name="family" mode="assign">
+      <string>Times New Roman</string>
+    </edit>
+  </match>
+
+  <!-- TODO(thomasanderson): Move these configs to be test-specific. -->
+  <match target="pattern">
+    <test name="family" compare="eq">
+      <string>NonAntiAliasedSans</string>
+    </test>
+    <edit name="family" mode="assign">
+      <string>Arial</string>
+    </edit>
+    <edit name="antialias" mode="assign">
+      <bool>false</bool>
+    </edit>
+  </match>
+
+  <match target="pattern">
+    <test name="family" compare="eq">
+      <string>SlightHintedGeorgia</string>
+    </test>
+    <edit name="family" mode="assign">
+      <string>Georgia</string>
+    </edit>
+    <edit name="hintstyle" mode="assign">
+      <const>hintslight</const>
+    </edit>
+  </match>
+
+  <match target="pattern">
+    <test name="family" compare="eq">
+      <string>NonHintedSans</string>
+    </test>
+    <edit name="family" mode="assign">
+      <string>Verdana</string>
+    </edit>
+    <!-- These deliberately contradict each other. The 'hinting' preference
+         should take priority -->
+    <edit name="hintstyle" mode="assign">
+      <const>hintfull</const>
+    </edit>
+   <edit name="hinting" mode="assign">
+      <bool>false</bool>
+    </edit>
+  </match>
+
+  <match target="pattern">
+    <test name="family" compare="eq">
+      <string>AutohintedSerif</string>
+    </test>
+    <edit name="family" mode="assign">
+      <string>Arial</string>
+    </edit>
+    <edit name="autohint" mode="assign">
+      <bool>true</bool>
+    </edit>
+    <edit name="hintstyle" mode="assign">
+      <const>hintmedium</const>
+    </edit>
+  </match>
+
+  <match target="pattern">
+    <test name="family" compare="eq">
+      <string>HintedSerif</string>
+    </test>
+    <edit name="family" mode="assign">
+      <string>Arial</string>
+    </edit>
+    <edit name="autohint" mode="assign">
+      <bool>false</bool>
+    </edit>
+    <edit name="hintstyle" mode="assign">
+      <const>hintmedium</const>
+    </edit>
+  </match>
+
+  <match target="pattern">
+    <test name="family" compare="eq">
+      <string>FullAndAutoHintedSerif</string>
+    </test>
+    <edit name="family" mode="assign">
+      <string>Arial</string>
+    </edit>
+    <edit name="autohint" mode="assign">
+      <bool>true</bool>
+    </edit>
+    <edit name="hintstyle" mode="assign">
+      <const>hintfull</const>
+    </edit>
+  </match>
+
+  <match target="pattern">
+    <test name="family" compare="eq">
+      <string>SubpixelEnabledArial</string>
+    </test>
+    <edit name="family" mode="assign">
+      <string>Arial</string>
+    </edit>
+    <edit name="rgba" mode="assign">
+      <const>rgb</const>
+    </edit>
+  </match>
+
+  <match target="pattern">
+    <test name="family" compare="eq">
+      <string>SubpixelDisabledArial</string>
+    </test>
+    <edit name="family" mode="assign">
+      <string>Arial</string>
+    </edit>
+    <edit name="rgba" mode="assign">
+      <const>none</const>
+    </edit>
+  </match>
+
+  <match target="pattern">
+    <!-- FontConfig doesn't currently provide a well-defined way to turn on
+         subpixel positioning.  This is just an arbitrary pattern to use after
+         turning subpixel positioning on globally to ensure that we don't have
+         issues with our style getting cached for other tests. -->
+    <test name="family" compare="eq">
+      <string>SubpixelPositioning</string>
+    </test>
+    <edit name="family" mode="assign">
+      <string>Times New Roman</string>
+    </edit>
+  </match>
+
+  <match target="pattern">
+    <!-- See comments above -->
+    <test name="family" compare="eq">
+      <string>SubpixelPositioningAhem</string>
+    </test>
+    <edit name="family" mode="assign">
+      <string>ahem</string>
+    </edit>
+  </match>
+
+  <match target="pattern">
+    <test name="family" compare="eq">
+      <string>SlightHintedTimesNewRoman</string>
+    </test>
+    <edit name="family" mode="assign">
+      <string>Times New Roman</string>
+    </edit>
+    <edit name="hintstyle" mode="assign">
+      <const>hintslight</const>
+    </edit>
+  </match>
+
+  <!-- When we encounter a character that the current font doesn't
+       support, gfx::GetFallbackFontForChar() returns the first font
+       that does have a glyph for the character. The list of fonts is
+       sorted by a pattern that includes the current locale, but doesn't
+       include a font family (which means that the fallback font depends
+       on the locale but not on the current font).
+
+       DejaVu Sans is commonly the only font that supports some
+       characters, such as "⇧", and even when other candidates are
+       available, DejaVu Sans is commonly first among them, because of
+       the way Fontconfig is ordinarily configured. For example, the
+       configuration in the Fonconfig source lists DejaVu Sans under the
+       sans-serif generic family, and appends sans-serif to patterns
+       that don't already include a generic family (such as the pattern
+       in gfx::GetFallbackFontForChar()).
+
+       To get the same fallback font in the layout tests, we could
+       duplicate this configuration here, or more directly, simply
+       append DejaVu Sans to all patterns. -->
+  <match target="pattern">
+    <edit name="family" mode="append_last">
+      <string>DejaVu Sans</string>
+    </edit>
+  </match>
+
+</fontconfig>
+)";
+
+}  // namespace
+
+void SetUpFontconfig() {
+  FilePath dir_module;
+  PathService::Get(DIR_MODULE, &dir_module);
+  FilePath font_cache = dir_module.Append("fontconfig_caches");
+  FilePath test_fonts = dir_module.Append("test_fonts");
+  std::string fonts_conf = ReplaceStringPlaceholders(
+      kFontsConfTemplate, {font_cache.value(), test_fonts.value()}, nullptr);
+
+  FcConfig* config = FcConfigCreate();
+  CHECK(config);
+#if FC_VERSION >= 21205
+  CHECK(FcConfigParseAndLoadFromMemory(
+      config, reinterpret_cast<const FcChar8*>(fonts_conf.c_str()), FcTrue));
+#else
+  FilePath temp;
+  CHECK(CreateTemporaryFile(&temp));
+  CHECK(WriteFile(temp, fonts_conf.c_str(), fonts_conf.size()));
+  CHECK(FcConfigParseAndLoad(
+      config, reinterpret_cast<const FcChar8*>(temp.value().c_str()), FcTrue));
+  CHECK(DeleteFile(temp, false));
+#endif
+  CHECK(FcConfigBuildFonts(config));
+  CHECK(FcConfigSetCurrent(config));
+
+  // Decrement the reference count for |config|.  It's now owned by fontconfig.
+  FcConfigDestroy(config);
+}
+
+void TearDownFontconfig() {
+  FcFini();
+}
+
+bool LoadFontIntoFontconfig(const FilePath& path) {
+  if (!PathExists(path)) {
+    LOG(ERROR) << "You are missing " << path.value() << ". Try re-running "
+               << "build/install-build-deps.sh. "
+               << "Please make sure that "
+               << "third_party/test_fonts/ has downloaded "
+               << "and extracted the test_fonts."
+               << "Also see "
+               << "https://chromium.googlesource.com/chromium/src/+/master/"
+               << "docs/layout_tests_linux.md";
+    return false;
+  }
+
+  if (!FcConfigAppFontAddFile(
+          NULL, reinterpret_cast<const FcChar8*>(path.value().c_str()))) {
+    LOG(ERROR) << "Failed to load font " << path.value();
+    return false;
+  }
+
+  return true;
+}
+
+bool LoadConfigFileIntoFontconfig(const FilePath& path) {
+  // Unlike other FcConfig functions, FcConfigParseAndLoad() doesn't default to
+  // the current config when passed NULL. So that's cool.
+  if (!FcConfigParseAndLoad(
+          FcConfigGetCurrent(),
+          reinterpret_cast<const FcChar8*>(path.value().c_str()), FcTrue)) {
+    LOG(ERROR) << "Fontconfig failed to load " << path.value();
+    return false;
+  }
+  return true;
+}
+
+bool LoadConfigDataIntoFontconfig(const FilePath& temp_dir,
+                                  const std::string& data) {
+  FilePath path;
+  if (!CreateTemporaryFileInDir(temp_dir, &path)) {
+    PLOG(ERROR) << "Unable to create temporary file in " << temp_dir.value();
+    return false;
+  }
+  if (WriteFile(path, data.data(), data.size()) !=
+      static_cast<int>(data.size())) {
+    PLOG(ERROR) << "Unable to write config data to " << path.value();
+    return false;
+  }
+  return LoadConfigFileIntoFontconfig(path);
+}
+
+std::string CreateFontconfigEditStanza(const std::string& name,
+                                       const std::string& type,
+                                       const std::string& value) {
+  return StringPrintf(
+      "    <edit name=\"%s\" mode=\"assign\">\n"
+      "      <%s>%s</%s>\n"
+      "    </edit>\n",
+      name.c_str(), type.c_str(), value.c_str(), type.c_str());
+}
+
+std::string CreateFontconfigTestStanza(const std::string& name,
+                                       const std::string& op,
+                                       const std::string& type,
+                                       const std::string& value) {
+  return StringPrintf(
+      "    <test name=\"%s\" compare=\"%s\" qual=\"any\">\n"
+      "      <%s>%s</%s>\n"
+      "    </test>\n",
+      name.c_str(), op.c_str(), type.c_str(), value.c_str(), type.c_str());
+}
+
+std::string CreateFontconfigAliasStanza(const std::string& original_family,
+                                        const std::string& preferred_family) {
+  return StringPrintf(
+      "  <alias>\n"
+      "    <family>%s</family>\n"
+      "    <prefer><family>%s</family></prefer>\n"
+      "  </alias>\n",
+      original_family.c_str(), preferred_family.c_str());
+}
+
+}  // namespace base
diff --git a/base/test/fontconfig_util_linux.h b/base/test/fontconfig_util_linux.h
new file mode 100644
index 0000000..ac7037a
--- /dev/null
+++ b/base/test/fontconfig_util_linux.h
@@ -0,0 +1,51 @@
+// 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 BASE_TEST_FONTCONFIG_UTIL_LINUX_H_
+#define BASE_TEST_FONTCONFIG_UTIL_LINUX_H_
+
+#include <stddef.h>
+
+#include <string>
+
+namespace base {
+class FilePath;
+
+// Initializes Fontconfig with a custom configuration suitable for tests.
+void SetUpFontconfig();
+
+// Deinitializes Fontconfig.
+void TearDownFontconfig();
+
+// Loads the font file at |path| into the current config, returning true on
+// success.
+bool LoadFontIntoFontconfig(const FilePath& path);
+
+// Instructs Fontconfig to load |path|, an XML configuration file, into the
+// current config, returning true on success.
+bool LoadConfigFileIntoFontconfig(const FilePath& path);
+
+// Writes |data| to a file in |temp_dir| and passes it to
+// LoadConfigFileIntoFontconfig().
+bool LoadConfigDataIntoFontconfig(const FilePath& temp_dir,
+                                  const std::string& data);
+
+// Returns a Fontconfig <edit> stanza.
+std::string CreateFontconfigEditStanza(const std::string& name,
+                                       const std::string& type,
+                                       const std::string& value);
+
+// Returns a Fontconfig <test> stanza.
+std::string CreateFontconfigTestStanza(const std::string& name,
+                                       const std::string& op,
+                                       const std::string& type,
+                                       const std::string& value);
+
+// Returns a Fontconfig <alias> stanza.
+std::string CreateFontconfigAliasStanza(const std::string& original_family,
+                                        const std::string& preferred_family);
+
+}  // namespace base
+
+#endif  // BASE_TEST_FONTCONFIG_UTIL_LINUX_H_
diff --git a/base/test/generate_fontconfig_caches.cc b/base/test/generate_fontconfig_caches.cc
new file mode 100644
index 0000000..681ed24
--- /dev/null
+++ b/base/test/generate_fontconfig_caches.cc
@@ -0,0 +1,24 @@
+// 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 <string>
+
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/path_service.h"
+#include "base/test/fontconfig_util_linux.h"
+
+int main(void) {
+  base::SetUpFontconfig();
+  base::TearDownFontconfig();
+
+  base::FilePath dir_module;
+  CHECK(PathService::Get(base::DIR_MODULE, &dir_module));
+  base::FilePath fontconfig_caches = dir_module.Append("fontconfig_caches");
+  CHECK(base::DirectoryExists(fontconfig_caches));
+  base::FilePath stamp = fontconfig_caches.Append("STAMP");
+  CHECK_EQ(0, base::WriteFile(stamp, "", 0));
+
+  return 0;
+}
diff --git a/base/test/test_suite.cc b/base/test/test_suite.cc
index 4cb2208..3d53097 100644
--- a/base/test/test_suite.cc
+++ b/base/test/test_suite.cc
@@ -62,6 +62,10 @@
 #include "base/test/test_support_ios.h"
 #endif
 
+#if defined(OS_LINUX)
+#include "base/test/fontconfig_util_linux.h"
+#endif
+
 namespace base {
 
 namespace {
@@ -456,6 +460,12 @@
 #endif
 #endif
 
+#if defined(OS_LINUX)
+  // TODO(thomasanderson): Call TearDownFontconfig() in Shutdown().  It would
+  // currently crash because of leaked FcFontSet's in font_fallback_linux.cc.
+  SetUpFontconfig();
+#endif
+
   CatchMaybeTests();
   ResetCommandLine();
   AddTestLauncherResultPrinter();
diff --git a/build/android/pylib/local/device/local_device_instrumentation_test_run.py b/build/android/pylib/local/device/local_device_instrumentation_test_run.py
index b3517ba..da74494f 100644
--- a/build/android/pylib/local/device/local_device_instrumentation_test_run.py
+++ b/build/android/pylib/local/device/local_device_instrumentation_test_run.py
@@ -39,6 +39,7 @@
 from py_utils import tempfile_ext
 import tombstones
 
+
 with host_paths.SysPath(
     os.path.join(host_paths.DIR_SOURCE_ROOT, 'third_party'), 0):
   import jinja2  # pylint: disable=import-error
@@ -75,8 +76,6 @@
 _EXTRA_TEST_LIST = (
     'org.chromium.base.test.BaseChromiumAndroidJUnitRunner.TestList')
 
-UI_CAPTURE_DIRS = ['chromium_tests_root', 'UiCapture']
-
 FEATURE_ANNOTATION = 'Feature'
 RENDER_TEST_FEATURE_ANNOTATION = 'RenderTest'
 
@@ -126,7 +125,6 @@
     super(LocalDeviceInstrumentationTestRun, self).__init__(
         env, test_instance)
     self._flag_changers = {}
-    self._ui_capture_dir = dict()
     self._replace_package_contextmanager = None
 
   #override
@@ -253,21 +251,8 @@
         valgrind_tools.SetChromeTimeoutScale(
             dev, self._test_instance.timeout_scale)
 
-      @trace_event.traced
-      def setup_ui_capture_dir(dev):
-        # Make sure the UI capture directory exists and is empty by deleting
-        # and recreating it.
-        # TODO (aberent) once DeviceTempDir exists use it here.
-        self._ui_capture_dir[dev] = posixpath.join(
-            dev.GetExternalStoragePath(),
-            *UI_CAPTURE_DIRS)
-
-        if dev.PathExists(self._ui_capture_dir[dev]):
-          dev.RunShellCommand(['rm', '-rf', self._ui_capture_dir[dev]])
-        dev.RunShellCommand(['mkdir', self._ui_capture_dir[dev]])
-
       steps += [set_debug_app, edit_shared_prefs, push_test_data,
-                create_flag_changer, setup_ui_capture_dir]
+                create_flag_changer]
 
       def bind_crash_handler(step, dev):
         return lambda: crash_handler.RetryOnSystemCrash(step, dev)
@@ -372,7 +357,11 @@
         device.adb, suffix='.png', dir=device.GetExternalStoragePath())
     extras[EXTRA_SCREENSHOT_FILE] = screenshot_device_file.name
 
-    extras[EXTRA_UI_CAPTURE_DIR] = self._ui_capture_dir[device]
+    # Set up the screenshot directory. This needs to be done for each test so
+    # that we only get screenshots created by that test.
+    ui_capture_dir = device_temp_file.NamedDeviceTemporaryDirectory(
+        device.adb)
+    extras[EXTRA_UI_CAPTURE_DIR] = ui_capture_dir.name
 
     if self._env.trace_output:
       trace_device_file = device_temp_file.DeviceTempFile(
@@ -450,114 +439,116 @@
         time.strftime('%Y%m%dT%H%M%S-UTC', time.gmtime()),
         device.serial)
 
-    with self._env.output_manager.ArchivedTempfile(
-        stream_name, 'logcat') as logcat_file:
-      try:
-        with logcat_monitor.LogcatMonitor(
-            device.adb,
-            filter_specs=local_device_environment.LOGCAT_FILTERS,
-            output_file=logcat_file.name,
-            transform_func=self._test_instance.MaybeDeobfuscateLines) as logmon:
-          with _LogTestEndpoints(device, test_name):
-            with contextlib_ext.Optional(
-                trace_event.trace(test_name),
-                self._env.trace_output):
-              output = device.StartInstrumentation(
-                  target, raw=True, extras=extras, timeout=timeout, retries=0)
-      finally:
-        logmon.Close()
-
-    if logcat_file.Link():
-      logging.info('Logcat saved to %s', logcat_file.Link())
-
-    duration_ms = time_ms() - start_ms
-
-    with contextlib_ext.Optional(
-        trace_event.trace('ProcessResults'),
-        self._env.trace_output):
-      output = self._test_instance.MaybeDeobfuscateLines(output)
-      # TODO(jbudorick): Make instrumentation tests output a JSON so this
-      # doesn't have to parse the output.
-      result_code, result_bundle, statuses = (
-          self._test_instance.ParseAmInstrumentRawOutput(output))
-      results = self._test_instance.GenerateTestResults(
-          result_code, result_bundle, statuses, start_ms, duration_ms,
-          device.product_cpu_abi, self._test_instance.symbolizer)
-
-    if self._env.trace_output:
-      self._SaveTraceData(trace_device_file, device, test['class'])
-
-    def restore_flags():
-      if flags_to_add:
-        self._flag_changers[str(device)].Restore()
-
-    def restore_timeout_scale():
-      if test_timeout_scale:
-        valgrind_tools.SetChromeTimeoutScale(
-            device, self._test_instance.timeout_scale)
-
-    def handle_coverage_data():
-      if self._test_instance.coverage_directory:
-        device.PullFile(coverage_directory,
-            self._test_instance.coverage_directory)
-        device.RunShellCommand(
-            'rm -f %s' % posixpath.join(coverage_directory, '*'),
-            check_return=True, shell=True)
-
-    def handle_render_test_data():
-      if _IsRenderTest(test):
-        # Render tests do not cause test failure by default. So we have to check
-        # to see if any failure images were generated even if the test does not
-        # fail.
-        try:
-          self._ProcessRenderTestResults(
-              device, render_tests_device_output_dir, results)
-        finally:
-          device.RemovePath(render_tests_device_output_dir,
-                            recursive=True, force=True)
-
-    def pull_ui_screen_captures():
-      screenshots = []
-      for filename in device.ListDirectory(self._ui_capture_dir[device]):
-        if filename.endswith('.json'):
-          screenshots.append(pull_ui_screenshot(filename))
-      if screenshots:
-        json_archive_name = 'ui_capture_%s_%s.json' % (
-            test_name.replace('#', '.'),
-            time.strftime('%Y%m%dT%H%M%S-UTC', time.gmtime()))
-        with self._env.output_manager.ArchivedTempfile(
-            json_archive_name, 'ui_capture', output_manager.Datatype.JSON
-            ) as json_archive:
-          json.dump(screenshots, json_archive)
-        for result in results:
-          result.SetLink('ui screenshot', json_archive.Link())
-
-    def pull_ui_screenshot(filename):
-      source_dir = self._ui_capture_dir[device]
-      json_path = posixpath.join(source_dir, filename)
-      json_data = json.loads(device.ReadFile(json_path))
-      image_file_path = posixpath.join(source_dir, json_data['location'])
+    with ui_capture_dir:
       with self._env.output_manager.ArchivedTempfile(
-          json_data['location'], 'ui_capture', output_manager.Datatype.IMAGE
-          ) as image_archive:
-        device.PullFile(image_file_path, image_archive.name)
-      json_data['image_link'] = image_archive.Link()
-      return json_data
+          stream_name, 'logcat') as logcat_file:
+        try:
+          with logcat_monitor.LogcatMonitor(
+              device.adb,
+              filter_specs=local_device_environment.LOGCAT_FILTERS,
+              output_file=logcat_file.name,
+              transform_func=self._test_instance.MaybeDeobfuscateLines
+              ) as logmon:
+            with _LogTestEndpoints(device, test_name):
+              with contextlib_ext.Optional(
+                  trace_event.trace(test_name),
+                  self._env.trace_output):
+                output = device.StartInstrumentation(
+                    target, raw=True, extras=extras, timeout=timeout, retries=0)
+        finally:
+          logmon.Close()
 
-    # While constructing the TestResult objects, we can parallelize several
-    # steps that involve ADB. These steps should NOT depend on any info in
-    # the results! Things such as whether the test CRASHED have not yet been
-    # determined.
-    post_test_steps = [restore_flags, restore_timeout_scale,
-                       handle_coverage_data, handle_render_test_data,
-                       pull_ui_screen_captures]
-    if self._env.concurrent_adb:
-      post_test_step_thread_group = reraiser_thread.ReraiserThreadGroup(
-          reraiser_thread.ReraiserThread(f) for f in post_test_steps)
-      post_test_step_thread_group.StartAll(will_block=True)
-    else:
-      for step in post_test_steps:
-        step()
+      if logcat_file.Link():
+        logging.info('Logcat saved to %s', logcat_file.Link())
+
+      duration_ms = time_ms() - start_ms
+
+      with contextlib_ext.Optional(
+          trace_event.trace('ProcessResults'),
+          self._env.trace_output):
+        output = self._test_instance.MaybeDeobfuscateLines(output)
+        # TODO(jbudorick): Make instrumentation tests output a JSON so this
+        # doesn't have to parse the output.
+        result_code, result_bundle, statuses = (
+            self._test_instance.ParseAmInstrumentRawOutput(output))
+        results = self._test_instance.GenerateTestResults(
+            result_code, result_bundle, statuses, start_ms, duration_ms,
+            device.product_cpu_abi, self._test_instance.symbolizer)
+
+      if self._env.trace_output:
+        self._SaveTraceData(trace_device_file, device, test['class'])
+
+      def restore_flags():
+        if flags_to_add:
+          self._flag_changers[str(device)].Restore()
+
+      def restore_timeout_scale():
+        if test_timeout_scale:
+          valgrind_tools.SetChromeTimeoutScale(
+              device, self._test_instance.timeout_scale)
+
+      def handle_coverage_data():
+        if self._test_instance.coverage_directory:
+          device.PullFile(coverage_directory,
+              self._test_instance.coverage_directory)
+          device.RunShellCommand(
+              'rm -f %s' % posixpath.join(coverage_directory, '*'),
+              check_return=True, shell=True)
+
+      def handle_render_test_data():
+        if _IsRenderTest(test):
+          # Render tests do not cause test failure by default. So we have to
+          # check to see if any failure images were generated even if the test
+          # does not fail.
+          try:
+            self._ProcessRenderTestResults(
+                device, render_tests_device_output_dir, results)
+          finally:
+            device.RemovePath(render_tests_device_output_dir,
+                              recursive=True, force=True)
+
+      def pull_ui_screen_captures():
+        screenshots = []
+        for filename in device.ListDirectory(ui_capture_dir.name):
+          if filename.endswith('.json'):
+            screenshots.append(pull_ui_screenshot(filename))
+        if screenshots:
+          json_archive_name = 'ui_capture_%s_%s.json' % (
+              test_name.replace('#', '.'),
+              time.strftime('%Y%m%dT%H%M%S-UTC', time.gmtime()))
+          with self._env.output_manager.ArchivedTempfile(
+              json_archive_name, 'ui_capture', output_manager.Datatype.JSON
+              ) as json_archive:
+            json.dump(screenshots, json_archive)
+          for result in results:
+            result.SetLink('ui screenshot', json_archive.Link())
+
+      def pull_ui_screenshot(filename):
+        source_dir = ui_capture_dir.name
+        json_path = posixpath.join(source_dir, filename)
+        json_data = json.loads(device.ReadFile(json_path))
+        image_file_path = posixpath.join(source_dir, json_data['location'])
+        with self._env.output_manager.ArchivedTempfile(
+            json_data['location'], 'ui_capture', output_manager.Datatype.IMAGE
+            ) as image_archive:
+          device.PullFile(image_file_path, image_archive.name)
+        json_data['image_link'] = image_archive.Link()
+        return json_data
+
+      # While constructing the TestResult objects, we can parallelize several
+      # steps that involve ADB. These steps should NOT depend on any info in
+      # the results! Things such as whether the test CRASHED have not yet been
+      # determined.
+      post_test_steps = [restore_flags, restore_timeout_scale,
+                         handle_coverage_data, handle_render_test_data,
+                         pull_ui_screen_captures]
+      if self._env.concurrent_adb:
+        post_test_step_thread_group = reraiser_thread.ReraiserThreadGroup(
+            reraiser_thread.ReraiserThread(f) for f in post_test_steps)
+        post_test_step_thread_group.StartAll(will_block=True)
+      else:
+        for step in post_test_steps:
+          step()
 
     for result in results:
       if logcat_file:
diff --git a/build/android/pylib/results/presentation/test_results_presentation.py b/build/android/pylib/results/presentation/test_results_presentation.py
index 21137fe..e218dac 100755
--- a/build/android/pylib/results/presentation/test_results_presentation.py
+++ b/build/android/pylib/results/presentation/test_results_presentation.py
@@ -6,7 +6,9 @@
 
 import argparse
 import collections
+import contextlib
 import json
+import logging
 import tempfile
 import os
 import sys
@@ -361,6 +363,56 @@
         authenticated_link=True)
 
 
+def ui_screenshot_set(json_path):
+  with open(json_path) as json_file:
+    json_object = json.loads(json_file.read())
+  if not 'per_iteration_data' in json_object:
+    # This will be reported as an error by result_details, no need to duplicate.
+    return None
+  ui_screenshots = []
+  for testsuite_run in json_object['per_iteration_data']:
+    for _, test_runs in testsuite_run.iteritems():
+      for test_run in test_runs:
+        if 'ui screenshot' in test_run['links']:
+          screenshot_link = test_run['links']['ui screenshot']
+          if screenshot_link.startswith('file:'):
+            with contextlib.closing(urllib.urlopen(screenshot_link)) as f:
+              test_screenshots = json.load(f)
+          else:
+            # Assume anything that isn't a file link is a google storage link
+            screenshot_string = google_storage_helper.read_from_link(
+                screenshot_link)
+            if not screenshot_string:
+              logging.error('Bad screenshot link %s', screenshot_link)
+              continue
+            test_screenshots = json.loads(
+                screenshot_string)
+          ui_screenshots.extend(test_screenshots)
+
+  if ui_screenshots:
+    return json.dumps(ui_screenshots)
+  return None
+
+
+def upload_screenshot_set(json_path, test_name, bucket, builder_name,
+                          build_number):
+  screenshot_set = ui_screenshot_set(json_path)
+  if not screenshot_set:
+    return None
+  dest = google_storage_helper.unique_name(
+    'screenshots_%s_%s_%s' % (test_name, builder_name, build_number),
+    suffix='.json')
+  with tempfile.NamedTemporaryFile(suffix='.json') as temp_file:
+    temp_file.write(screenshot_set)
+    temp_file.flush()
+    return google_storage_helper.upload(
+        name=dest,
+        filepath=temp_file.name,
+        bucket='%s/json' % bucket,
+        content_type='application/json',
+        authenticated_link=True)
+
+
 def main():
   parser = argparse.ArgumentParser()
   parser.add_argument('--json-file', help='Path of json file.')
@@ -455,16 +507,28 @@
       'Result details link do not match. The link returned by get_url_link'
       ' should be the same as that returned by upload.')
 
+  ui_screenshot_link = upload_screenshot_set(json_file, args.test_name,
+      args.bucket, builder_name, build_number)
+
+
   if args.output_json:
     with open(json_file) as original_json_file:
       json_object = json.load(original_json_file)
       json_object['links'] = {
           'result_details (logcats, flakiness links)': result_details_link
       }
+
+      if ui_screenshot_link:
+        json_object['links']['ui screenshots'] = ui_screenshot_link
+
       with open(args.output_json, 'w') as f:
         json.dump(json_object, f)
   else:
-    print result_details_link
+    print 'Result Details: %s' % result_details_link
+
+    if ui_screenshot_link:
+      print 'UI Screenshots %s' % ui_screenshot_link
+
 
 if __name__ == '__main__':
   sys.exit(main())
diff --git a/build/android/pylib/utils/google_storage_helper.py b/build/android/pylib/utils/google_storage_helper.py
index 55e4882..3101d71 100644
--- a/build/android/pylib/utils/google_storage_helper.py
+++ b/build/android/pylib/utils/google_storage_helper.py
@@ -13,6 +13,7 @@
 import os
 import sys
 import time
+import urlparse
 
 from pylib.constants import host_paths
 from pylib.utils import decorators
@@ -62,6 +63,15 @@
   return get_url_link(name, bucket, authenticated_link)
 
 
+@decorators.NoRaiseException(default_return_value='')
+def read_from_link(link):
+  # Note that urlparse returns the path with an initial '/', so we only need to
+  # add one more after the 'gs;'
+  gs_path = 'gs:/%s' % urlparse.urlparse(link).path
+  cmd = [_GSUTIL_PATH, '-q', 'cat', gs_path]
+  return cmd_helper.GetCmdOutput(cmd)
+
+
 @decorators.NoRaiseException(default_return_value=False)
 def exists(name, bucket):
   bucket = _format_bucket_name(bucket)
diff --git a/build/android/test_runner.py b/build/android/test_runner.py
index 97c31b8..1a8bf0f 100755
--- a/build/android/test_runner.py
+++ b/build/android/test_runner.py
@@ -937,6 +937,16 @@
         results_detail_file.flush()
       logging.critical('TEST RESULTS: %s', results_detail_file.Link())
 
+      ui_screenshots = test_results_presentation.ui_screenshot_set(
+          json_file.name)
+      if ui_screenshots:
+        with out_manager.ArchivedTempfile(
+            'ui_screenshots.json',
+            'ui_capture',
+            output_manager.Datatype.JSON) as ui_screenshot_file:
+          ui_screenshot_file.write(ui_screenshots)
+        logging.critical('UI Screenshots: %s', ui_screenshot_file.Link())
+
   if args.command == 'perf' and (args.steps or args.single_step):
     return 0
 
diff --git a/build/compiled_action.gni b/build/compiled_action.gni
index c7fb8c65..50f9be6a 100644
--- a/build/compiled_action.gni
+++ b/build/compiled_action.gni
@@ -83,6 +83,7 @@
   action(target_name) {
     forward_variables_from(invoker,
                            [
+                             "data_deps",
                              "deps",
                              "inputs",
                              "outputs",
diff --git a/chrome/android/java/res/layout/signin_view.xml b/chrome/android/java/res/layout/signin_view.xml
new file mode 100644
index 0000000..2aa3da8d
--- /dev/null
+++ b/chrome/android/java/res/layout/signin_view.xml
@@ -0,0 +1,77 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2018 The Chromium Authors. All rights reserved.
+     Use of this source code is governed by a BSD-style license that can be
+     found in the LICENSE file. -->
+<org.chromium.chrome.browser.signin.SigninView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:chrome="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical">
+    <org.chromium.chrome.browser.signin.SigninScrollView
+        android:id="@+id/signin_scroll_view"
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:fadingEdgeLength="48dp"
+        android:layout_weight="1"
+        android:requiresFadingEdge="vertical"
+        android:scrollbars="none">
+        <!-- TODO(https://crbug.com/819142): Add the rest of the layout. -->
+    </org.chromium.chrome.browser.signin.SigninScrollView>
+    <LinearLayout
+        android:id="@+id/button_bar"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal"
+        android:padding="16dp">
+        <!-- TODO(https://crbug.com/819142): Use textAppearance instead of text* attributes. -->
+        <Button
+            android:id="@+id/negative_button"
+            style="@style/ButtonCompatBorderless"
+            android:layout_width="wrap_content"
+            android:layout_height="36dp"
+            android:paddingEnd="@dimen/fre_button_padding"
+            android:paddingStart="@dimen/fre_button_padding"
+            android:textAllCaps="true"
+            android:textColor="@color/light_active_color"
+            android:textSize="14sp"
+            tools:text="@string/no_thanks"/>
+        <View
+            android:layout_width="0dp"
+            android:layout_height="0dp"
+            android:layout_weight="1"
+            android:visibility="invisible"/>
+        <!-- TODO(https://crbug.com/819142): Specify WhiteBody as textAppearance. -->
+        <org.chromium.ui.widget.ButtonCompat
+            android:id="@+id/positive_button"
+            style="@style/WhiteBody"
+            android:layout_width="wrap_content"
+            android:layout_height="36dp"
+            android:paddingEnd="@dimen/fre_button_padding"
+            android:paddingStart="@dimen/fre_button_padding"
+            android:textAllCaps="true"
+            chrome:buttonColor="@color/light_active_color"
+            chrome:buttonRaised="false"
+            tools:text="@string/signin_accept_button"/>
+        <!-- TODO(https://crbug.com/819142): Use textAppearance instead of text* attributes. -->
+        <Button
+            android:id="@+id/more_button"
+            style="@style/ButtonCompatBorderless"
+            android:layout_width="wrap_content"
+            android:layout_height="36dp"
+            android:drawableEnd="@drawable/down_arrow"
+            android:drawablePadding="8dp"
+            android:textAllCaps="true"
+            android:textColor="@color/light_active_color"
+            android:textSize="@dimen/text_size_medium"
+            android:visibility="gone"
+            tools:text="@string/more"/>
+        <View
+            android:id="@+id/positive_button_end_padding"
+            android:layout_width="0dp"
+            android:layout_height="0dp"
+            android:layout_weight="1"
+            android:visibility="gone"/>
+    </LinearLayout>
+</org.chromium.chrome.browser.signin.SigninView>
diff --git a/chrome/android/java/res/values/dimens.xml b/chrome/android/java/res/values/dimens.xml
index 290304a..d377cbf5 100644
--- a/chrome/android/java/res/values/dimens.xml
+++ b/chrome/android/java/res/values/dimens.xml
@@ -489,7 +489,7 @@
     <dimen name="list_item_start_icon_width">36dp</dimen>
     <dimen name="list_item_start_icon_corner_radius">18dp</dimen>
     <dimen name="list_item_end_icon_width">56dp</dimen>
-    <dimen name="list_menu_width">140dp</dimen>
+    <dimen name="list_menu_width">180dp</dimen>
 
     <!-- SelectableListLayout dimensions -->
     <dimen name="selectable_list_layout_row_padding">16dp</dimen>
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeApplication.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeApplication.java
index 22ed2c67..69895c1 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeApplication.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeApplication.java
@@ -60,7 +60,7 @@
         UmaUtils.recordMainEntryPointTime();
         super.attachBaseContext(context);
         checkAppBeingReplaced();
-        if (BuildConfig.isMultidexEnabled()) {
+        if (BuildConfig.IS_MULTIDEX_ENABLED) {
             ChromiumMultiDexInstaller.install(this);
         }
         ContextUtils.initApplicationContext(this);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/browserservices/Origin.java b/chrome/android/java/src/org/chromium/chrome/browser/browserservices/Origin.java
index c871b4e9..bde31687 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/browserservices/Origin.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/browserservices/Origin.java
@@ -6,34 +6,62 @@
 
 import android.net.Uri;
 
-import org.chromium.net.GURLUtils;
-
 /**
- * A class to canonically represent a web origin in Java. It requires the native library to be
- * loaded as it uses {@link GURLUtils#getOrigin}.
+ * A class to canonically represent a web origin in Java. It intends to mirror the behaviour of
+ * GURLUtils.getOrigin, but needs to work without native being loaded.
  */
 public class Origin {
-    private final String mOrigin;
+    private static final int HTTP_DEFAULT_PORT = 80;
+    private static final int HTTPS_DEFAULT_PORT = 443;
+
+    private final Uri mOrigin;
 
     /**
      * Constructs a canonical Origin from a String.
      */
     public Origin(String uri) {
-        mOrigin = GURLUtils.getOrigin(uri);
+        this(Uri.parse(uri));
     }
 
     /**
      * Constructs a canonical Origin from an Uri.
      */
     public Origin(Uri uri) {
-        this(uri.toString());
+        if (uri.getScheme() == null || uri.getAuthority() == null) {
+            mOrigin = Uri.EMPTY;
+            return;
+        }
+
+        // Make explicit ports implicit and remove any user:password.
+        int port = uri.getPort();
+        if (uri.getScheme().equals("http") && port == HTTP_DEFAULT_PORT) port = -1;
+        if (uri.getScheme().equals("https") && port == HTTPS_DEFAULT_PORT) port = -1;
+
+        String authority = uri.getHost();
+        if (port != -1) authority += ":" + port;
+
+        Uri origin;
+        try {
+            origin = uri.normalizeScheme()
+                    .buildUpon()
+                    .opaquePart("")
+                    .fragment("")
+                    .path("/")
+                    .encodedAuthority(authority)
+                    .clearQuery()
+                    .build();
+        } catch (UnsupportedOperationException e) {
+            origin = Uri.EMPTY;
+        }
+
+        mOrigin = origin;
     }
 
     /**
-     * Returns a Uri representing this Origin.
+     * Returns a Uri representing the Origin.
      */
     public Uri uri() {
-        return Uri.parse(mOrigin);
+        return mOrigin;
     }
 
     @Override
@@ -41,9 +69,12 @@
         return mOrigin.hashCode();
     }
 
+    /**
+     * Returns a String representing the Origin.
+     */
     @Override
     public String toString() {
-        return mOrigin;
+        return mOrigin.toString();
     }
 
     @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/phone/StackLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/phone/StackLayout.java
index 94a589a..e2c3edc 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/phone/StackLayout.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/phone/StackLayout.java
@@ -9,13 +9,14 @@
 import org.chromium.chrome.browser.compositor.layouts.LayoutRenderHost;
 import org.chromium.chrome.browser.compositor.layouts.LayoutUpdateHost;
 import org.chromium.chrome.browser.compositor.layouts.content.TabContentManager;
-import org.chromium.chrome.browser.compositor.layouts.phone.stack.Stack;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.tabmodel.TabList;
 import org.chromium.chrome.browser.tabmodel.TabModel;
 import org.chromium.chrome.browser.tabmodel.TabModelSelector;
 import org.chromium.chrome.browser.tabmodel.TabModelUtils;
 
+import java.util.ArrayList;
+
 /**
  * Layout that displays all normal tabs in one stack and all incognito tabs in a second.
  */
@@ -36,22 +37,15 @@
      */
     public StackLayout(Context context, LayoutUpdateHost updateHost, LayoutRenderHost renderHost) {
         super(context, updateHost, renderHost);
-
-        for (int i = 0; i < NUM_STACKS; i++) {
-            mStacks.add(new Stack(context, this));
-        }
     }
 
     @Override
     public void setTabModelSelector(TabModelSelector modelSelector, TabContentManager manager) {
         super.setTabModelSelector(modelSelector, manager);
-        mStacks.get(NORMAL_STACK_INDEX).setTabList(modelSelector.getModel(false));
-        mStacks.get(INCOGNITO_STACK_INDEX).setTabList(modelSelector.getModel(true));
-    }
-
-    @Override
-    protected TabList getTabList(int index) {
-        return mTabModelSelector.getModel(index == INCOGNITO_STACK_INDEX);
+        ArrayList<TabList> tabLists = new ArrayList<TabList>();
+        tabLists.add(modelSelector.getModel(false));
+        tabLists.add(modelSelector.getModel(true));
+        setTabLists(tabLists);
     }
 
     @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/phone/StackLayoutBase.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/phone/StackLayoutBase.java
index 1166d9d..19f08a17 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/phone/StackLayoutBase.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/phone/StackLayoutBase.java
@@ -49,6 +49,7 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Comparator;
+import java.util.List;
 
 /**
  * Base class for layouts that show one or more stacks of tabs.
@@ -96,7 +97,7 @@
      */
     private static final float SWITCH_STACK_FLING_DT = 1.0f / 30.0f;
 
-    /** The array of potentially visible stacks. */
+    /** The list of potentially visible stacks. */
     protected final ArrayList<Stack> mStacks;
 
     /** Rectangles that defines the area where each stack need to be laid out. */
@@ -129,6 +130,10 @@
     private float mLastOnDownY;
     private long mLastOnDownTimeStamp;
 
+    private float mWidth;
+    private float mHeight;
+    private int mOrientation;
+
     // Pre-allocated temporary arrays that store id of visible tabs.
     // They can be used to call populatePriorityVisibilityList.
     // We use StackTab[] instead of ArrayList<StackTab> because the sorting function does
@@ -223,6 +228,7 @@
             } else {
                 final int newStackIndex = getTabStackIndex() + stackIndexDeltaAt;
                 if (newStackIndex < 0 || newStackIndex >= mStacks.size()) return;
+                if (!mStacks.get(newStackIndex).isDisplayable()) return;
                 flingStacks(newStackIndex);
             }
             requestStackUpdate();
@@ -310,6 +316,28 @@
         mSceneLayer = new TabListSceneLayer();
     }
 
+    /**
+     * Updates this layout to show one tab stack for each of the passed-in TabLists. Takes a
+     * reference to the lists param and expects it not to change.
+     * @param lists The list of TabLists to use.
+     */
+    protected void setTabLists(List<TabList> lists) {
+        if (mStacks.size() > lists.size()) {
+            mStacks.subList(lists.size(), lists.size()).clear();
+        }
+        while (mStacks.size() < lists.size()) {
+            Stack stack = new Stack(getContext(), this);
+            stack.notifySizeChanged(mWidth, mHeight, mOrientation);
+            mStacks.add(stack);
+        }
+
+        for (int i = 0; i < lists.size(); i++) {
+            mStacks.get(i).setTabList(lists.get(i));
+        }
+
+        // mStackRects will get updated in updateLayout()
+    }
+
     @Override
     public boolean forceShowBrowserControlsAndroidView() {
         return true;
@@ -352,8 +380,6 @@
         resetScrollData();
     }
 
-    protected abstract TabList getTabList(int index);
-
     /**
      * Get the tab stack at the specified index.
      *
@@ -728,6 +754,9 @@
 
     @Override
     public void notifySizeChanged(float width, float height, int orientation) {
+        mWidth = width;
+        mHeight = height;
+        mOrientation = orientation;
         mCachedLandscapeViewport = null;
         mCachedPortraitViewport = null;
         for (Stack stack : mStacks) {
@@ -1089,7 +1118,8 @@
             final float stackFocus = MathUtils.clamp(1 - scrollDistance, 0, 1);
 
             mStacks.get(i).setStackFocusInfo(stackFocus,
-                    mSortingComparator == mOrderComparator ? getTabList(i).index() : -1);
+                    mSortingComparator == mOrderComparator ? mStacks.get(i).getTabList().index()
+                                                           : -1);
         }
 
         // Compute position and visibility
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/phone/stack/Stack.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/phone/stack/Stack.java
index 7a79709..76b5beb 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/phone/stack/Stack.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/phone/stack/Stack.java
@@ -19,7 +19,7 @@
 import org.chromium.chrome.browser.compositor.layouts.Layout.Orientation;
 import org.chromium.chrome.browser.compositor.layouts.components.LayoutTab;
 import org.chromium.chrome.browser.compositor.layouts.eventfilter.ScrollDirection;
-import org.chromium.chrome.browser.compositor.layouts.phone.StackLayout;
+import org.chromium.chrome.browser.compositor.layouts.phone.StackLayoutBase;
 import org.chromium.chrome.browser.compositor.layouts.phone.stack.StackAnimation.OverviewAnimationType;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.tabmodel.TabList;
@@ -231,7 +231,7 @@
     private Animator mViewAnimations;
 
     // The parent Layout
-    private final StackLayout mLayout;
+    private final StackLayoutBase mLayout;
 
     // Border values
     private float mBorderTransparentTop;
@@ -257,7 +257,7 @@
     /**
      * @param layout The parent layout.
      */
-    public Stack(Context context, StackLayout layout) {
+    public Stack(Context context, StackLayoutBase layout) {
         mLayout = layout;
         contextChanged(context);
     }
@@ -270,6 +270,13 @@
     }
 
     /**
+     * @return The TabList associated with this stack.
+     */
+    public TabList getTabList() {
+        return mTabList;
+    }
+
+    /**
      * @return The {@link StackTab}s currently being rendered by the tab stack.
      * @VisibleForTesting
      */
@@ -2273,7 +2280,7 @@
      */
     public float getMaxTabHeight() {
         if (FeatureUtilities.isChromeHomeEnabled() && mCurrentMode == Orientation.PORTRAIT) {
-            return mLayout.getHeightMinusBrowserControls() - StackLayout.MODERN_TOP_MARGIN_DP;
+            return mLayout.getHeightMinusBrowserControls() - StackLayoutBase.MODERN_TOP_MARGIN_DP;
         }
         return mLayout.getHeightMinusBrowserControls();
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManager.java b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManager.java
index e85c510..9a0953a0 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManager.java
@@ -1586,6 +1586,7 @@
                 // Set up the next batch of Ranker logging.
                 mTapSuppressionRankerLogger.setupLoggingForPage(getBaseWebContents());
                 mSearchPanel.getPanelMetrics().setRankerLogger(mTapSuppressionRankerLogger);
+                ContextualSearchUma.logRankerFeaturesAvailable(false);
                 mInternalStateController.notifyFinishedWorkOn(InternalState.TAP_GESTURE_COMMIT);
             }
 
@@ -1674,6 +1675,7 @@
             public void showContextualSearchTapUi() {
                 mInternalStateController.notifyStartingWorkOn(InternalState.SHOW_FULL_TAP_UI);
                 showContextualSearch(StateChangeReason.TEXT_SELECT_TAP);
+                ContextualSearchUma.logRankerFeaturesAvailable(true);
                 mInternalStateController.notifyFinishedWorkOn(InternalState.SHOW_FULL_TAP_UI);
             }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchUma.java b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchUma.java
index 5d7e8d06..5153513 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchUma.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchUma.java
@@ -1344,6 +1344,17 @@
     }
 
     /**
+     * Logs that features or outcomes are available to record to Ranker.
+     * This data can be used to correlate with #logRecordedToRanker to validate that everything that
+     * should be recorded is actually being recorded.
+     * @param areOutcomes Whether the features available are outcomes.
+     */
+    static void logRankerFeaturesAvailable(boolean areOutcomes) {
+        RecordHistogram.recordBooleanHistogram(
+                "Search.ContextualSearch.Ranker.eaturesAvailable", areOutcomes);
+    }
+
+    /**
      * Gets the state-change code for the given parameters by doing a lookup in the given map.
      * @param state The panel state.
      * @param reason The reason the state changed.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridge.java
index 4b3b83fca..17db3c9 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridge.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridge.java
@@ -523,7 +523,7 @@
      * @param callback A callback that will be called once operation is completed.
      */
     public void deletePagesByClientIdAndOrigin(
-            List<ClientId> clientIds, String origin, Callback<Integer> callback) {
+            List<ClientId> clientIds, OfflinePageOrigin origin, Callback<Integer> callback) {
         String[] namespaces = new String[clientIds.size()];
         String[] ids = new String[clientIds.size()];
 
@@ -533,7 +533,7 @@
         }
 
         nativeDeletePagesByClientIdAndOrigin(
-                mNativeOfflinePageBridge, namespaces, ids, origin, callback);
+                mNativeOfflinePageBridge, namespaces, ids, origin.encodeAsJsonString(), callback);
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageOrigin.java b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageOrigin.java
index 0eaf009..c6f7d1ca 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageOrigin.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageOrigin.java
@@ -141,6 +141,25 @@
         return mAppName;
     }
 
+    @Override
+    public String toString() {
+        return encodeAsJsonString();
+    }
+
+    @Override
+    public boolean equals(Object other) {
+        if (other != null && other instanceof OfflinePageOrigin) {
+            OfflinePageOrigin o = (OfflinePageOrigin) other;
+            return mAppName.equals(o.mAppName) && Arrays.equals(mSignatures, o.mSignatures);
+        }
+        return false;
+    }
+
+    @Override
+    public int hashCode() {
+        return Arrays.deepHashCode(new Object[] {mAppName, mSignatures});
+    }
+
     /**
      * @param context The context to look up signatures.
      * @param appName The name of the application to look up.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/SavePasswordsPreferences.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/SavePasswordsPreferences.java
index c08ebc3..5b6a273 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/SavePasswordsPreferences.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/SavePasswordsPreferences.java
@@ -759,6 +759,9 @@
             if (mSearchQuery == null) {
                 // If not searching, the category needs to be removed again.
                 getPreferenceScreen().removePreference(passwordParent);
+            } else {
+                getView().announceForAccessibility(
+                        getResources().getText(R.string.accessible_find_in_page_no_results));
             }
         }
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/AccountSigninActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/AccountSigninActivity.java
index 0b10502..666e177 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/signin/AccountSigninActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/AccountSigninActivity.java
@@ -70,7 +70,7 @@
 
         final Intent intent;
         if (ChromeFeatureList.isEnabled(ChromeFeatureList.UNIFIED_CONSENT)) {
-            intent = SigninActivity.createIntent(context, accessPoint, false);
+            intent = SigninActivity.createIntent(context, accessPoint);
         } else {
             intent = createIntentForDefaultSigninFlow(context, accessPoint, false);
         }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninActivity.java
index 6649ce8..44cf0b5a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninActivity.java
@@ -4,6 +4,8 @@
 
 package org.chromium.chrome.browser.signin;
 
+import android.app.Fragment;
+import android.app.FragmentManager;
 import android.content.Context;
 import android.content.Intent;
 import android.os.Bundle;
@@ -24,14 +26,11 @@
     /**
      * Creates an {@link Intent} which can be used to start the signin flow.
      * @param accessPoint {@link AccessPoint} for starting signin flow. Used in metrics.
-     * @param isFromPersonalizedPromo Whether the signin activity is started from a personalized
-     *         promo.
      */
-    public static Intent createIntent(Context context,
-            @AccountSigninActivity.AccessPoint int accessPoint, boolean isFromPersonalizedPromo) {
+    public static Intent createIntent(
+            Context context, @AccountSigninActivity.AccessPoint int accessPoint) {
         Intent intent = new Intent(context, SigninActivity.class);
-        // TODO(https://crbug.com/814728): Call SigninFragment.createArguments.
-        Bundle fragmentArguments = new Bundle();
+        Bundle fragmentArguments = SigninFragment.createArguments(accessPoint);
         intent.putExtras(fragmentArguments);
         return intent;
     }
@@ -52,6 +51,12 @@
         super.onCreate(savedInstanceState);
         setContentView(R.layout.signin_activity);
 
-        // TODO(https://crbug.com/814728): Add SigninFragment.
+        FragmentManager fragmentManager = getFragmentManager();
+        Fragment fragment = fragmentManager.findFragmentById(R.id.fragment_container);
+        if (fragment == null) {
+            fragment = new SigninFragment();
+            fragment.setArguments(getIntent().getExtras());
+            fragmentManager.beginTransaction().add(R.id.fragment_container, fragment).commit();
+        }
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninFragment.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninFragment.java
new file mode 100644
index 0000000..a5356b1
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninFragment.java
@@ -0,0 +1,180 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.signin;
+
+import android.content.Intent;
+import android.os.Bundle;
+import android.support.annotation.IntDef;
+import android.support.annotation.Nullable;
+
+import org.chromium.base.metrics.RecordHistogram;
+import org.chromium.base.metrics.RecordUserAction;
+import org.chromium.chrome.browser.preferences.PrefServiceBridge;
+import org.chromium.chrome.browser.preferences.PreferencesLauncher;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/** This fragment implements sign-in screen for {@link SigninActivity}. */
+public class SigninFragment extends SigninFragmentBase {
+    private static final String TAG = "SigninFragment";
+
+    private static final String ARGUMENT_PERSONALIZED_PROMO_ACTION =
+            "SigninFragment.PersonalizedPromoAction";
+
+    @IntDef({PROMO_ACTION_NONE, PROMO_ACTION_WITH_DEFAULT, PROMO_ACTION_NOT_DEFAULT,
+            PROMO_ACTION_NEW_ACCOUNT})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface PromoAction {}
+
+    public static final int PROMO_ACTION_NONE = 0;
+    public static final int PROMO_ACTION_WITH_DEFAULT = 1;
+    public static final int PROMO_ACTION_NOT_DEFAULT = 2;
+    public static final int PROMO_ACTION_NEW_ACCOUNT = 3;
+
+    private @PromoAction int mPromoAction;
+
+    /**
+     * Creates an argument bundle to start signin.
+     * @param accessPoint The access point for starting signin flow.
+     */
+    public static Bundle createArguments(@SigninAccessPoint int accessPoint) {
+        return SigninFragmentBase.createArguments(accessPoint);
+    }
+
+    /**
+     * Creates an argument bundle to start signin from personalized signin promo.
+     * @param accessPoint The access point for starting signin flow.
+     * @param promoAction Promo action that was used to start signin. Used for UMA.
+     */
+    public static Bundle createArgumentsFromPersonalizedPromo(
+            @SigninAccessPoint int accessPoint, @PromoAction int promoAction) {
+        Bundle result = SigninFragmentBase.createArguments(accessPoint);
+        result.putInt(ARGUMENT_PERSONALIZED_PROMO_ACTION, promoAction);
+        return result;
+    }
+
+    // Every fragment must have a public default constructor.
+    public SigninFragment() {}
+
+    @Override
+    public void onCreate(@Nullable Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        mPromoAction =
+                getSigninArguments().getInt(ARGUMENT_PERSONALIZED_PROMO_ACTION, PROMO_ACTION_NONE);
+
+        SigninManager.logSigninStartAccessPoint(getSigninAccessPoint());
+        recordSigninStartedHistogramAccountInfo();
+        recordSigninStartedUserAction();
+    }
+
+    @Override
+    protected Bundle getSigninArguments() {
+        return getArguments();
+    }
+
+    @Override
+    protected void onSigninRefused() {
+        getActivity().finish();
+    }
+
+    @Override
+    protected void onSigninAccepted(
+            String accountName, boolean isDefaultAccount, boolean settingsClicked) {
+        if (PrefServiceBridge.getInstance().getSyncLastAccountName() != null) {
+            AccountSigninActivity.recordSwitchAccountSourceHistogram(
+                    AccountSigninActivity.SwitchAccountSource.SIGNOUT_SIGNIN);
+        }
+
+        SigninManager.get().signIn(accountName, getActivity(), new SigninManager.SignInCallback() {
+            @Override
+            public void onSignInComplete() {
+                if (settingsClicked) {
+                    Intent intent = PreferencesLauncher.createIntentForSettingsPage(
+                            getActivity(), AccountManagementFragment.class.getName());
+                    startActivity(intent);
+                }
+
+                recordSigninCompletedHistogramAccountInfo();
+                getActivity().finish();
+            }
+
+            @Override
+            public void onSignInAborted() {}
+        });
+    }
+
+    private void recordSigninCompletedHistogramAccountInfo() {
+        final String histogram;
+        switch (mPromoAction) {
+            case PROMO_ACTION_NONE:
+                return;
+            case PROMO_ACTION_WITH_DEFAULT:
+                histogram = "Signin.SigninCompletedAccessPoint.WithDefault";
+                break;
+            case PROMO_ACTION_NOT_DEFAULT:
+                histogram = "Signin.SigninCompletedAccessPoint.NotDefault";
+                break;
+            case PROMO_ACTION_NEW_ACCOUNT:
+                histogram = "Signin.SigninCompletedAccessPoint.NewAccount";
+                break;
+            default:
+                assert false : "Unexpected signin flow type!";
+                return;
+        }
+
+        RecordHistogram.recordEnumeratedHistogram(
+                histogram, getSigninAccessPoint(), SigninAccessPoint.MAX);
+    }
+
+    private void recordSigninStartedHistogramAccountInfo() {
+        final String histogram;
+        switch (mPromoAction) {
+            case PROMO_ACTION_NONE:
+                return;
+            case PROMO_ACTION_WITH_DEFAULT:
+                histogram = "Signin.SigninStartedAccessPoint.WithDefault";
+                break;
+            case PROMO_ACTION_NOT_DEFAULT:
+                histogram = "Signin.SigninStartedAccessPoint.NotDefault";
+                break;
+            case PROMO_ACTION_NEW_ACCOUNT:
+                histogram = "Signin.SigninStartedAccessPoint.NewAccount";
+                break;
+            default:
+                assert false : "Unexpected signin flow type!";
+                return;
+        }
+
+        RecordHistogram.recordEnumeratedHistogram(
+                histogram, getSigninAccessPoint(), SigninAccessPoint.MAX);
+    }
+
+    private void recordSigninStartedUserAction() {
+        switch (getSigninAccessPoint()) {
+            case SigninAccessPoint.AUTOFILL_DROPDOWN:
+                RecordUserAction.record("Signin_Signin_FromAutofillDropdown");
+                break;
+            case SigninAccessPoint.BOOKMARK_MANAGER:
+                RecordUserAction.record("Signin_Signin_FromBookmarkManager");
+                break;
+            case SigninAccessPoint.RECENT_TABS:
+                RecordUserAction.record("Signin_Signin_FromRecentTabs");
+                break;
+            case SigninAccessPoint.SETTINGS:
+                RecordUserAction.record("Signin_Signin_FromSettings");
+                break;
+            case SigninAccessPoint.SIGNIN_PROMO:
+                RecordUserAction.record("Signin_Signin_FromSigninPromo");
+                break;
+            case SigninAccessPoint.NTP_CONTENT_SUGGESTIONS:
+                RecordUserAction.record("Signin_Signin_FromNTPContentSuggestions");
+                break;
+            default:
+                assert false : "Invalid access point.";
+        }
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninFragmentBase.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninFragmentBase.java
new file mode 100644
index 0000000..bd7e125
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninFragmentBase.java
@@ -0,0 +1,124 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.signin;
+
+import android.app.Fragment;
+import android.os.Bundle;
+import android.support.annotation.Nullable;
+import android.support.annotation.StringRes;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import org.chromium.base.metrics.RecordUserAction;
+import org.chromium.chrome.R;
+
+/**
+ * This fragment implements sign-in screen with account picker and descriptions of signin-related
+ * features. Configuration for this fragment is provided by overriding {@link #getSigninArguments}
+ * derived classes.
+ */
+public abstract class SigninFragmentBase extends Fragment {
+    private static final String TAG = "SigninFragmentBase";
+
+    private static final String ARGUMENT_ACCESS_POINT = "SigninFragmentBase.AccessPoint";
+
+    private @SigninAccessPoint int mSigninAccessPoint;
+
+    private SigninView mView;
+    private @StringRes int mCancelButtonTextId = R.string.cancel;
+
+    /**
+     * Creates an argument bundle to start AccountSigninView from the account selection page.
+     * @param accessPoint The access point for starting signin flow.
+     */
+    protected static Bundle createArguments(@SigninAccessPoint int accessPoint) {
+        Bundle result = new Bundle();
+        result.putInt(ARGUMENT_ACCESS_POINT, accessPoint);
+        return result;
+    }
+
+    /**
+     * This method should return arguments Bundle that contains arguments created by
+     * {@link #createArguments} and related methods.
+     */
+    protected abstract Bundle getSigninArguments();
+
+    /** The sign-in was refused. */
+    protected abstract void onSigninRefused();
+
+    /**
+     * The sign-in was accepted.
+     * @param accountName The name of the account
+     * @param isDefaultAccount Whether selected account is a default one (first of all accounts)
+     * @param settingsClicked Whether the user requested to see their sync settings
+     */
+    protected abstract void onSigninAccepted(
+            String accountName, boolean isDefaultAccount, boolean settingsClicked);
+
+    /** Returns the access point that initiated the sign-in flow. */
+    protected @SigninAccessPoint int getSigninAccessPoint() {
+        return mSigninAccessPoint;
+    }
+
+    @Override
+    public void onCreate(@Nullable Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        Bundle arguments = getSigninArguments();
+        initAccessPoint(arguments.getInt(ARGUMENT_ACCESS_POINT, -1));
+    }
+
+    private void initAccessPoint(@SigninAccessPoint int accessPoint) {
+        assert accessPoint == SigninAccessPoint.AUTOFILL_DROPDOWN
+                || accessPoint == SigninAccessPoint.BOOKMARK_MANAGER
+                || accessPoint == SigninAccessPoint.NTP_CONTENT_SUGGESTIONS
+                || accessPoint == SigninAccessPoint.RECENT_TABS
+                || accessPoint == SigninAccessPoint.SETTINGS
+                || accessPoint == SigninAccessPoint.SIGNIN_PROMO
+                || accessPoint
+                        == SigninAccessPoint.START_PAGE : "invalid access point: " + accessPoint;
+
+        mSigninAccessPoint = accessPoint;
+        if (accessPoint == SigninAccessPoint.START_PAGE
+                || accessPoint == SigninAccessPoint.SIGNIN_PROMO) {
+            mCancelButtonTextId = R.string.no_thanks;
+        }
+    }
+
+    @Override
+    public View onCreateView(
+            LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+        mView = (SigninView) inflater.inflate(R.layout.signin_view, container, false);
+        mView.getAcceptButton().setVisibility(View.GONE);
+        mView.getMoreButton().setVisibility(View.VISIBLE);
+        mView.getMoreButton().setOnClickListener(view -> {
+            mView.getScrollView().smoothScrollBy(0, mView.getScrollView().getHeight());
+            // TODO(https://crbug.com/821127): Revise this user action.
+            RecordUserAction.record("Signin_MoreButton_Shown");
+        });
+        mView.getScrollView().setScrolledToBottomObserver(this::showAcceptButton);
+
+        mView.getRefuseButton().setOnClickListener(view -> {
+            setButtonsEnabled(false);
+            onSigninRefused();
+        });
+
+        // TODO(https://crbug.com/814728): Set texts for UI elements
+
+        return mView;
+    }
+
+    private void showAcceptButton() {
+        mView.getAcceptButton().setVisibility(View.VISIBLE);
+        mView.getMoreButton().setVisibility(View.GONE);
+        mView.getScrollView().setScrolledToBottomObserver(null);
+    }
+
+    private void setButtonsEnabled(boolean enabled) {
+        mView.getAcceptButton().setEnabled(enabled);
+        mView.getRefuseButton().setEnabled(enabled);
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninScrollView.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninScrollView.java
new file mode 100644
index 0000000..8dd4108
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninScrollView.java
@@ -0,0 +1,70 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.signin;
+
+import android.content.Context;
+import android.support.annotation.Nullable;
+import android.util.AttributeSet;
+import android.view.ViewTreeObserver;
+import android.widget.ScrollView;
+
+/**
+ * ScrollView without the top edge that also sends notification when it is scrolled to the bottom.
+ */
+public class SigninScrollView extends ScrollView {
+    private final ViewTreeObserver.OnGlobalLayoutListener mOnGlobalLayoutListener =
+            this::checkScrolledToBottom;
+    private final ViewTreeObserver.OnScrollChangedListener mOnScrollChangedListener =
+            this::checkScrolledToBottom;
+    private @Nullable Runnable mObserver;
+
+    public SigninScrollView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    @Override
+    protected float getTopFadingEdgeStrength() {
+        // Disable fading out effect at the top of this ScrollView.
+        return 0;
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        removeObserver();
+        super.onDetachedFromWindow();
+    }
+
+    private void checkScrolledToBottom() {
+        if (mObserver == null) return;
+        if (getChildCount() == 0) {
+            // The ScrollView is definitely scrolled to bottom if there are no children.
+            mObserver.run();
+            return;
+        }
+        if ((getHeight() + getScrollY()) < getChildAt(getChildCount() - 1).getBottom()) return;
+        mObserver.run();
+    }
+
+    /**
+     * Sets observer. Regardless of the passed value, notifications for the previous observer will
+     * be canceled.
+     * @param observer The Runnable to receive notification when SigninScrollView is scrolled to
+     *         bottom, or null to clear the observer.
+     */
+    public void setScrolledToBottomObserver(@Nullable Runnable observer) {
+        removeObserver();
+        if (observer == null) return;
+        mObserver = observer;
+        getViewTreeObserver().addOnGlobalLayoutListener(mOnGlobalLayoutListener);
+        getViewTreeObserver().addOnScrollChangedListener(mOnScrollChangedListener);
+    }
+
+    private void removeObserver() {
+        if (mObserver == null) return;
+        mObserver = null;
+        getViewTreeObserver().removeOnGlobalLayoutListener(mOnGlobalLayoutListener);
+        getViewTreeObserver().removeOnScrollChangedListener(mOnScrollChangedListener);
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninView.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninView.java
new file mode 100644
index 0000000..39a2560
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninView.java
@@ -0,0 +1,59 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.signin;
+
+import android.content.Context;
+import android.support.annotation.Nullable;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.Button;
+import android.widget.LinearLayout;
+
+import org.chromium.chrome.R;
+import org.chromium.ui.widget.ButtonCompat;
+
+/** View that wraps signin screen and caches references to UI elements. */
+public class SigninView extends LinearLayout {
+    private SigninScrollView mScrollView;
+    private ButtonCompat mAcceptButton;
+    private Button mRefuseButton;
+    private Button mMoreButton;
+    private View mAcceptButtonEndPadding;
+
+    public SigninView(Context context, @Nullable AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+
+        mScrollView = (SigninScrollView) findViewById(R.id.signin_scroll_view);
+        mAcceptButton = (ButtonCompat) findViewById(R.id.positive_button);
+        mRefuseButton = (Button) findViewById(R.id.negative_button);
+        mMoreButton = (Button) findViewById(R.id.more_button);
+        mAcceptButtonEndPadding = findViewById(R.id.positive_button_end_padding);
+    }
+
+    public SigninScrollView getScrollView() {
+        return mScrollView;
+    }
+
+    public ButtonCompat getAcceptButton() {
+        return mAcceptButton;
+    }
+
+    public Button getRefuseButton() {
+        return mRefuseButton;
+    }
+
+    public Button getMoreButton() {
+        return mMoreButton;
+    }
+
+    public View getAcceptButtonEndPadding() {
+        return mAcceptButtonEndPadding;
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java
index 5173a30..dbd3fa0 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java
@@ -751,10 +751,10 @@
             }
 
             if (mNativeTabAndroid == 0) {
-                // if mNativeTabAndroid is invalid then we are going to crash anyways on the
+                // if mNativeTabAndroid is null then we are going to crash anyways on the
                 // native side. Lets crash on the java side so that we can have a better stack
-                // trace. https://crbug.com/662877
-                throw new RuntimeException("Please post this crash on crbug.com/662877");
+                // trace.
+                throw new RuntimeException("Tab.loadUrl called when no native side exists");
             }
 
             // We load the URL from the tab rather than directly from the ContentView so the tab has
diff --git a/chrome/android/java/strings/android_chrome_strings.grd b/chrome/android/java/strings/android_chrome_strings.grd
index bdfb4f2..e26c75e 100644
--- a/chrome/android/java/strings/android_chrome_strings.grd
+++ b/chrome/android/java/strings/android_chrome_strings.grd
@@ -2296,7 +2296,13 @@
         Waiting for Google Play Services to finish updating
       </message>
 
-      <!-- New Signin Promos Strings -->
+      <!-- Strings for Streamlined Signin and Unified Consent. -->
+      <!-- TODO(https://crbug.com/814728): Make translatable when strings are approved. -->
+      <message name="IDS_SIGNIN_ACCEPT_BUTTON" desc="Text for the confirmation button in the sign-in screen. By clicking this button users signs in and turns on Sync and personalization. [CHAR-LIMIT=20]" translateable="false">
+        Yes, I'm in
+      </message>
+
+      <!-- Personalized Signin Promos Strings -->
       <message name="IDS_SIGNIN_PROMO_DESCRIPTION_BOOKMARKS" desc="Description string for 'Continue as' signin promo shown in Bookmarks screen.">
         To get your bookmarks on all your devices, sign in to Chrome.
       </message>
diff --git a/chrome/android/java_sources.gni b/chrome/android/java_sources.gni
index 65cfd69..95eba2cba 100644
--- a/chrome/android/java_sources.gni
+++ b/chrome/android/java_sources.gni
@@ -1113,11 +1113,15 @@
   "java/src/org/chromium/chrome/browser/signin/ProfileDataCache.java",
   "java/src/org/chromium/chrome/browser/signin/SignOutDialogFragment.java",
   "java/src/org/chromium/chrome/browser/signin/SigninActivity.java",
+  "java/src/org/chromium/chrome/browser/signin/SigninFragment.java",
+  "java/src/org/chromium/chrome/browser/signin/SigninFragmentBase.java",
   "java/src/org/chromium/chrome/browser/signin/SigninHelper.java",
   "java/src/org/chromium/chrome/browser/signin/SigninInvestigator.java",
   "java/src/org/chromium/chrome/browser/signin/SigninManager.java",
   "java/src/org/chromium/chrome/browser/signin/SigninPromoController.java",
   "java/src/org/chromium/chrome/browser/signin/SigninPromoUtil.java",
+  "java/src/org/chromium/chrome/browser/signin/SigninScrollView.java",
+  "java/src/org/chromium/chrome/browser/signin/SigninView.java",
   "java/src/org/chromium/chrome/browser/signin/SyncPromoView.java",
   "java/src/org/chromium/chrome/browser/snackbar/BottomContainer.java",
   "java/src/org/chromium/chrome/browser/snackbar/DataReductionPromoSnackbarController.java",
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/browserservices/OriginTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/browserservices/OriginTest.java
index 6fdaf073..f36ce37 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/browserservices/OriginTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/browserservices/OriginTest.java
@@ -29,11 +29,48 @@
         mNativeLibraryTestRule.loadNativeLibraryNoBrowserProcess();
     }
 
-    /**
-     * The actual conversion from a free form URL to an Origin is done in native and that is
-     * thoroughly tested there. Here we only check that the transformation is performed, not that
-     * it is complete and correct.
-     */
+    @Test
+    @SmallTest
+    public void testTransformation() {
+        Assert.assertEquals(Uri.parse("http://example.com:123/").getPort(), 123);
+
+        // Unlike origin.cc, the returned Uri has a port of -1 if it is the default port for the
+        // scheme.
+        check("http://192.168.9.1/", "http", "192.168.9.1", -1);
+
+        // Test cases for origin.cc that do *not* work with Origin.java:
+
+        // check("http://[2001:db8::1]/", "http", "[2001:db8::1]", 80);
+        // This is because Uri cannot deal with IPv6 URLS, eg:
+        // Uri.parse("http://[2001:db8::1]/").getHost() returns "[2001"
+
+        // check("http://☃.net/", "http", "xn--n3h.net", 80);
+        // check("blob:http://☃.net/", "http", "xn--n3h.net", 80);
+        // We don't perform punycode substitution so the string is unchanged.
+
+        check("http://example.com/", "http", "example.com", -1);
+        check("http://example.com:123/", "http", "example.com", 123);
+        check("https://example.com/", "https", "example.com", -1);
+        check("https://example.com:123/", "https", "example.com", 123);
+        check("http://user:pass@example.com/", "http", "example.com", -1);
+        check("http://example.com:123/?query", "http", "example.com", 123);
+        check("https://example.com/#1234", "https", "example.com", -1);
+        check("https://u:p@example.com:123/?query#1234", "https", "example.com", 123);
+    }
+
+    private static void check(String url, String scheme, String host, int port) {
+        Origin origin = new Origin(url);
+        Assert.assertEquals(scheme, origin.uri().getScheme());
+        Assert.assertEquals(host, origin.uri().getHost());
+        Assert.assertEquals(port, origin.uri().getPort());
+
+        if (port == -1) {
+            Assert.assertEquals(origin.toString(), scheme + "://" + host + "/");
+        } else {
+            Assert.assertEquals(origin.toString(), scheme + "://" + host + ":" + port + "/");
+        }
+    }
+
     @Test
     @SmallTest
     public void testConstruction() {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/test/ScreenShooter.java b/chrome/android/javatests/src/org/chromium/chrome/browser/test/ScreenShooter.java
index 4382b7c..878de8b 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/test/ScreenShooter.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/test/ScreenShooter.java
@@ -10,6 +10,7 @@
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
+import android.annotation.SuppressLint;
 import android.app.Instrumentation;
 import android.content.res.Configuration;
 import android.graphics.Point;
@@ -93,6 +94,7 @@
  * }
  * </pre>
  */
+@SuppressLint("SetWorldReadable")
 public class ScreenShooter extends TestWatcher {
     private static final String SCREENSHOT_DIR =
             "org.chromium.base.test.util.Screenshooter.ScreenshotDir";
@@ -204,6 +206,9 @@
             File shotFile = File.createTempFile(shotName, IMAGE_SUFFIX, new File(mBaseDir));
             assertTrue("Screenshot " + shotName, mDevice.takeScreenshot(shotFile));
             writeImageDescription(shotFile, filters, tags, metadata);
+            // Set as world readable so that the test runner can read it from /data/local/tmp
+            // without having to run as root
+            shotFile.setReadable(true, false);
         } catch (IOException e) {
             fail("Cannot create shot files " + e.toString());
         }
@@ -231,8 +236,12 @@
         String jsonFileName =
                 shotFileName.substring(0, shotFileName.length() - IMAGE_SUFFIX.length())
                 + JSON_SUFFIX;
-        try (FileWriter fileWriter = new FileWriter(new File(mBaseDir, jsonFileName));) {
+        File descriptionFile = new File(mBaseDir, jsonFileName);
+        try (FileWriter fileWriter = new FileWriter(descriptionFile)) {
             fileWriter.write(imageDescription.toString());
         }
+        // Set as world readable so that the test runner can read it from /data/local/tmp without
+        // having to run as root
+        descriptionFile.setReadable(true, false);
     }
 }
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/OfflinePageOriginUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/OfflinePageOriginUnitTest.java
index a80234c..ad4b5ee 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/OfflinePageOriginUnitTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/OfflinePageOriginUnitTest.java
@@ -5,6 +5,8 @@
 package org.chromium.chrome.browser.offlinepages;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -24,4 +26,25 @@
 
         assertEquals("[\"abc.xyz\",[\"deadbeef\",\"00c0ffee\"]]", origin.encodeAsJsonString());
     }
+
+    @Test
+    public void testEquals() {
+        String appName = "abc.xyz";
+        String[] signature1 = new String[] {"deadbeef", "00c0ffee"};
+        String[] signature2 = new String[] {"deadbeef", "fooba499"};
+        OfflinePageOrigin origin1 = new OfflinePageOrigin(appName, signature1);
+        OfflinePageOrigin origin2 = new OfflinePageOrigin(appName, signature2);
+        OfflinePageOrigin origin3 = new OfflinePageOrigin("", signature1);
+        OfflinePageOrigin origin4 = new OfflinePageOrigin(appName, signature1);
+
+        assertFalse("Equivalent to null", origin1.equals(null));
+        assertTrue("Not equivalent to self", origin1.equals(origin1));
+        assertFalse("Equivalent when signatures not equal", origin1.equals(origin2));
+        assertFalse("Equivalent when name not equal", origin1.equals(origin3));
+        assertTrue("Equally created items not equal", origin1.equals(origin4));
+
+        assertEquals("HashCode not equal to self", origin1.hashCode(), origin1.hashCode());
+        assertEquals(
+                "HashCode not equal when items are equal", origin1.hashCode(), origin4.hashCode());
+    }
 }
diff --git a/chrome/app/vector_icons/account_box.icon b/chrome/app/vector_icons/account_box.icon
index 089dccf..e6806d8 100644
--- a/chrome/app/vector_icons/account_box.icon
+++ b/chrome/app/vector_icons/account_box.icon
@@ -24,5 +24,4 @@
 R_V_LINE_TO, 2,
 H_LINE_TO, 12,
 R_V_LINE_TO, -2,
-CLOSE,
-END
+CLOSE
diff --git a/chrome/app/vector_icons/account_child.icon b/chrome/app/vector_icons/account_child.icon
index 0b8e989f..db3f809 100644
--- a/chrome/app/vector_icons/account_child.icon
+++ b/chrome/app/vector_icons/account_child.icon
@@ -21,4 +21,3 @@
 V_LINE_TO, 25.23f,
 CUBIC_TO, 37, 21.12f, 30.16f, 18, 24, 18,
 CLOSE,
-END,
diff --git a/chrome/app/vector_icons/account_child_circle.icon b/chrome/app/vector_icons/account_child_circle.icon
index f4ff64e..4ce7f60 100644
--- a/chrome/app/vector_icons/account_child_circle.icon
+++ b/chrome/app/vector_icons/account_child_circle.icon
@@ -32,5 +32,4 @@
 CUBIC_TO, 7, 11.2f, 9.63f, 10, 12, 10,
 R_CUBIC_TO, 2.37f, 0, 5, 1.2f, 5, 2.78f,
 R_V_LINE_TO, 4.44f,
-CLOSE,
-END
+CLOSE
diff --git a/chrome/app/vector_icons/account_circle.icon b/chrome/app/vector_icons/account_circle.icon
index 2774de46..07bf0c78 100644
--- a/chrome/app/vector_icons/account_circle.icon
+++ b/chrome/app/vector_icons/account_circle.icon
@@ -20,5 +20,4 @@
 R_CUBIC_TO, 0.03f, -1.99f, 4, -3.08f, 6, -3.08f,
 R_CUBIC_TO, 1.99f, 0, 5.97f, 1.09f, 6, 3.08f,
 R_CUBIC_TO, -1.29f, 1.94f, -3.5f, 3.22f, -6, 3.22f,
-CLOSE,
-END
+CLOSE
diff --git a/chrome/app/vector_icons/add.icon b/chrome/app/vector_icons/add.icon
index f2c69854..73829f6 100644
--- a/chrome/app/vector_icons/add.icon
+++ b/chrome/app/vector_icons/add.icon
@@ -8,5 +8,4 @@
 MOVE_TO, 3, 8,
 R_H_LINE_TO, 10,
 MOVE_TO, 8, 3,
-R_V_LINE_TO, 10,
-END
+R_V_LINE_TO, 10
diff --git a/chrome/app/vector_icons/ads.icon b/chrome/app/vector_icons/ads.icon
index 36effc4..8f03cd6 100644
--- a/chrome/app/vector_icons/ads.icon
+++ b/chrome/app/vector_icons/ads.icon
@@ -18,5 +18,4 @@
 V_LINE_TO, 6,
 R_H_LINE_TO, 8,
 R_V_LINE_TO, 6,
-CLOSE,
-END
+CLOSE
diff --git a/chrome/app/vector_icons/apps.icon b/chrome/app/vector_icons/apps.icon
index f70955f..b7cdbe6c 100644
--- a/chrome/app/vector_icons/apps.icon
+++ b/chrome/app/vector_icons/apps.icon
@@ -55,5 +55,4 @@
 R_V_LINE_TO, -8,
 R_H_LINE_TO, -8,
 R_V_LINE_TO, 8,
-CLOSE,
-END
+CLOSE
diff --git a/chrome/app/vector_icons/back_arrow_touch.icon b/chrome/app/vector_icons/back_arrow_touch.icon
index 974a7c83..59a516d 100644
--- a/chrome/app/vector_icons/back_arrow_touch.icon
+++ b/chrome/app/vector_icons/back_arrow_touch.icon
@@ -22,5 +22,4 @@
 R_LINE_TO, 0.09f, -0.09f,
 R_ARC_TO, 1, 1, 0, 0, 0, 1.32f, -1.32f,
 R_V_LINE_TO, 0,
-CLOSE,
-END
\ No newline at end of file
+CLOSE
diff --git a/chrome/app/vector_icons/blocked_badge.icon b/chrome/app/vector_icons/blocked_badge.icon
index 687be0dec..a621f1d 100644
--- a/chrome/app/vector_icons/blocked_badge.icon
+++ b/chrome/app/vector_icons/blocked_badge.icon
@@ -41,5 +41,4 @@
 LINE_TO, 28, 23.2f,
 CUBIC_TO, 28.34f, 22.87f, 28.34f, 22.33f, 28, 22,
 CUBIC_TO, 27.67f, 21.66f, 27.13f, 21.66f, 26.8f, 22,
-CLOSE,
-END
+CLOSE
diff --git a/chrome/app/vector_icons/blocked_redirect.icon b/chrome/app/vector_icons/blocked_redirect.icon
index 6b0e37f..f9e1633 100644
--- a/chrome/app/vector_icons/blocked_redirect.icon
+++ b/chrome/app/vector_icons/blocked_redirect.icon
@@ -28,5 +28,4 @@
 LINE_TO, 2, 9,
 LINE_TO, 5, 9,
 LINE_TO, 5, 11,
-CLOSE,
-END
+CLOSE
diff --git a/chrome/app/vector_icons/bookmarkbar_touch_overflow.icon b/chrome/app/vector_icons/bookmarkbar_touch_overflow.icon
index 254ad43..f493ed8 100644
--- a/chrome/app/vector_icons/bookmarkbar_touch_overflow.icon
+++ b/chrome/app/vector_icons/bookmarkbar_touch_overflow.icon
@@ -9,5 +9,4 @@
 LINE_TO, 9.52f, 6,
 LINE_TO, 16, 12,
 LINE_TO, 9.52f, 18,
-CLOSE,
-END
+CLOSE
diff --git a/chrome/app/vector_icons/browser_tools.1x.icon b/chrome/app/vector_icons/browser_tools.1x.icon
index ff2750374..7115751 100644
--- a/chrome/app/vector_icons/browser_tools.1x.icon
+++ b/chrome/app/vector_icons/browser_tools.1x.icon
@@ -20,5 +20,4 @@
 CUBIC_TO, 9.33f, 12, 10, 12.67f, 10, 13.5f,
 CUBIC_TO, 10, 14.33f, 9.33f, 15, 8.5f, 15,
 CUBIC_TO, 7.67f, 15, 7, 14.33f, 7, 13.5f,
-CLOSE,
-END
+CLOSE
diff --git a/chrome/app/vector_icons/browser_tools.icon b/chrome/app/vector_icons/browser_tools.icon
index fcda251..6fd494e 100644
--- a/chrome/app/vector_icons/browser_tools.icon
+++ b/chrome/app/vector_icons/browser_tools.icon
@@ -20,5 +20,4 @@
 CUBIC_TO, 19, 24.34f, 17.66f, 23, 16, 23,
 CUBIC_TO, 14.34f, 23, 13, 24.34f, 13, 26,
 CUBIC_TO, 13, 27.66f, 14.34f, 29, 16, 29,
-CLOSE,
-END
+CLOSE
diff --git a/chrome/app/vector_icons/browser_tools_animated.1x.icon b/chrome/app/vector_icons/browser_tools_animated.1x.icon
index 01566f2..5897c1c 100644
--- a/chrome/app/vector_icons/browser_tools_animated.1x.icon
+++ b/chrome/app/vector_icons/browser_tools_animated.1x.icon
@@ -103,5 +103,4 @@
 CUBIC_TO, 7.67f, 15, 7, 14.33f, 7, 13.5f,
 TRANSITION_END, 283, 400, gfx::Tween::FAST_OUT_SLOW_IN,
 
-CLOSE,
-END
+CLOSE
diff --git a/chrome/app/vector_icons/browser_tools_animated.icon b/chrome/app/vector_icons/browser_tools_animated.icon
index ba7adb98..89af1169 100644
--- a/chrome/app/vector_icons/browser_tools_animated.icon
+++ b/chrome/app/vector_icons/browser_tools_animated.icon
@@ -95,4 +95,3 @@
 TRANSITION_END, 283, 400, gfx::Tween::FAST_OUT_SLOW_IN,
 
 CLOSE,
-END,
diff --git a/chrome/app/vector_icons/browser_tools_error.icon b/chrome/app/vector_icons/browser_tools_error.icon
index 8c04ff10..c1c66a5 100644
--- a/chrome/app/vector_icons/browser_tools_error.icon
+++ b/chrome/app/vector_icons/browser_tools_error.icon
@@ -18,5 +18,4 @@
 R_V_LINE_TO, -2,
 R_H_LINE_TO, 2,
 R_V_LINE_TO, 2,
-CLOSE,
-END
\ No newline at end of file
+CLOSE
diff --git a/chrome/app/vector_icons/browser_tools_error_touch.icon b/chrome/app/vector_icons/browser_tools_error_touch.icon
index 2ae9ce0c..2283d82a 100644
--- a/chrome/app/vector_icons/browser_tools_error_touch.icon
+++ b/chrome/app/vector_icons/browser_tools_error_touch.icon
@@ -25,5 +25,4 @@
 R_H_LINE_TO, 24,
 R_V_LINE_TO, 24,
 H_LINE_TO, 0,
-CLOSE,
-END
\ No newline at end of file
+CLOSE
diff --git a/chrome/app/vector_icons/browser_tools_touch.icon b/chrome/app/vector_icons/browser_tools_touch.icon
index 8e92a38..4d28e31 100644
--- a/chrome/app/vector_icons/browser_tools_touch.icon
+++ b/chrome/app/vector_icons/browser_tools_touch.icon
@@ -14,5 +14,4 @@
 R_MOVE_TO, 0, 6,
 R_ARC_TO, 2, 2, 0, 1, 0, 0, 4,
 R_ARC_TO, 2, 2, 0, 0, 0, 0, -4,
-CLOSE,
-END
\ No newline at end of file
+CLOSE
diff --git a/chrome/app/vector_icons/browser_tools_update.icon b/chrome/app/vector_icons/browser_tools_update.icon
index 9747c147..c93b4d8d 100644
--- a/chrome/app/vector_icons/browser_tools_update.icon
+++ b/chrome/app/vector_icons/browser_tools_update.icon
@@ -15,5 +15,4 @@
 LINE_TO, 4, 9,
 R_H_LINE_TO, 2,
 R_V_LINE_TO, 3,
-CLOSE,
-END
\ No newline at end of file
+CLOSE
diff --git a/chrome/app/vector_icons/browser_tools_update_touch.icon b/chrome/app/vector_icons/browser_tools_update_touch.icon
index b3a8b9c..65640d0 100644
--- a/chrome/app/vector_icons/browser_tools_update_touch.icon
+++ b/chrome/app/vector_icons/browser_tools_update_touch.icon
@@ -22,5 +22,4 @@
 R_H_LINE_TO, 24,
 R_V_LINE_TO, 24,
 H_LINE_TO, 0,
-CLOSE,
-END
\ No newline at end of file
+CLOSE
diff --git a/chrome/app/vector_icons/caret_down.1x.icon b/chrome/app/vector_icons/caret_down.1x.icon
index f0d172f..1359d50 100644
--- a/chrome/app/vector_icons/caret_down.1x.icon
+++ b/chrome/app/vector_icons/caret_down.1x.icon
@@ -9,4 +9,3 @@
 MOVE_TO, 4, 6,
 R_LINE_TO, 4, 4,
 R_LINE_TO, 4, -4,
-END,
diff --git a/chrome/app/vector_icons/caret_down.icon b/chrome/app/vector_icons/caret_down.icon
index 7a5452d..b4a1696f 100644
--- a/chrome/app/vector_icons/caret_down.icon
+++ b/chrome/app/vector_icons/caret_down.icon
@@ -10,4 +10,3 @@
 R_LINE_TO, 7.5f, -8,
 // Hard clip at path points +- half the stroke.
 CLIP, 7, 11, 18, 11,
-END,
diff --git a/chrome/app/vector_icons/caret_up.1x.icon b/chrome/app/vector_icons/caret_up.1x.icon
index 863b01c3..5bd4153 100644
--- a/chrome/app/vector_icons/caret_up.1x.icon
+++ b/chrome/app/vector_icons/caret_up.1x.icon
@@ -9,4 +9,3 @@
 MOVE_TO, 4, 10,
 R_LINE_TO, 4, -4,
 R_LINE_TO, 4, 4,
-END,
diff --git a/chrome/app/vector_icons/caret_up.icon b/chrome/app/vector_icons/caret_up.icon
index 67f18cba..09b08e0 100644
--- a/chrome/app/vector_icons/caret_up.icon
+++ b/chrome/app/vector_icons/caret_up.icon
@@ -10,4 +10,3 @@
 MOVE_TO, 8.5f, 19.5f,
 R_LINE_TO, 7.5f, -8,
 R_LINE_TO, 7.5f, 8,
-END,
diff --git a/chrome/app/vector_icons/certificate.icon b/chrome/app/vector_icons/certificate.icon
index d2ffd58f..fa2cc23a 100644
--- a/chrome/app/vector_icons/certificate.icon
+++ b/chrome/app/vector_icons/certificate.icon
@@ -45,5 +45,4 @@
 R_H_LINE_TO, 24,
 R_V_LINE_TO, -3,
 H_LINE_TO, 12,
-CLOSE,
-END
+CLOSE
diff --git a/chrome/app/vector_icons/chromium/product.icon b/chrome/app/vector_icons/chromium/product.icon
index b7cc06d..63ece93 100644
--- a/chrome/app/vector_icons/chromium/product.icon
+++ b/chrome/app/vector_icons/chromium/product.icon
@@ -27,5 +27,4 @@
 R_H_LINE_TO, -6.6f,
 R_CUBIC_TO, 1, 0.8f, 1.7f, 2.1f, 1.7f, 3.5f,
 CLOSE,
-CIRCLE, 12, 12, 3.5,
-END
+CIRCLE, 12, 12, 3.5
diff --git a/chrome/app/vector_icons/close_all.icon b/chrome/app/vector_icons/close_all.icon
index abe83644..fdf8061 100644
--- a/chrome/app/vector_icons/close_all.icon
+++ b/chrome/app/vector_icons/close_all.icon
@@ -35,5 +35,4 @@
 LINE_TO, 15.41f, 10,
 R_LINE_TO, 2.83f, 2.83f,
 R_LINE_TO, -1.41f, 1.41f,
-CLOSE,
-END
+CLOSE
diff --git a/chrome/app/vector_icons/code.icon b/chrome/app/vector_icons/code.icon
index 8492f13..d634082 100644
--- a/chrome/app/vector_icons/code.icon
+++ b/chrome/app/vector_icons/code.icon
@@ -17,5 +17,4 @@
 R_LINE_TO, 12, 12,
 R_LINE_TO, -12, 12,
 R_LINE_TO, -2.8f, -2.8f,
-CLOSE,
-END
+CLOSE
diff --git a/chrome/app/vector_icons/content_paste.icon b/chrome/app/vector_icons/content_paste.icon
index 194ed6d..4997de7 100644
--- a/chrome/app/vector_icons/content_paste.icon
+++ b/chrome/app/vector_icons/content_paste.icon
@@ -33,5 +33,4 @@
 V_LINE_TO, 4,
 R_H_LINE_TO, 2,
 R_V_LINE_TO, 16,
-CLOSE,
-END
\ No newline at end of file
+CLOSE
diff --git a/chrome/app/vector_icons/cookie.icon b/chrome/app/vector_icons/cookie.icon
index a4e6887a..ab47da7a 100644
--- a/chrome/app/vector_icons/cookie.icon
+++ b/chrome/app/vector_icons/cookie.icon
@@ -55,5 +55,4 @@
 CUBIC_TO, 34.66f, 26, 36, 27.34f, 36, 29,
 CUBIC_TO, 36, 30.66f, 34.66f, 32, 33, 32,
 LINE_TO, 33, 32,
-CLOSE,
-END
+CLOSE
diff --git a/chrome/app/vector_icons/crashed_tab.icon b/chrome/app/vector_icons/crashed_tab.icon
index fa3e662..50576843 100644
--- a/chrome/app/vector_icons/crashed_tab.icon
+++ b/chrome/app/vector_icons/crashed_tab.icon
@@ -48,5 +48,4 @@
 R_MOVE_TO, 0, -4,
 R_LINE_TO, 0, 0,
 R_MOVE_TO, -2, 2,
-R_LINE_TO, 0, 0,
-END
+R_LINE_TO, 0, 0
diff --git a/chrome/app/vector_icons/credit_card.1x.icon b/chrome/app/vector_icons/credit_card.1x.icon
index 2608251..b3e5a647 100644
--- a/chrome/app/vector_icons/credit_card.1x.icon
+++ b/chrome/app/vector_icons/credit_card.1x.icon
@@ -24,5 +24,4 @@
 H_LINE_TO, 3.01f,
 CUBIC_TO, 1.9f, 14, 1, 13.1f, 1, 12.01f,
 V_LINE_TO, 4.99f,
-CLOSE,
-END
+CLOSE
diff --git a/chrome/app/vector_icons/credit_card.icon b/chrome/app/vector_icons/credit_card.icon
index c48afc5..b0b43cb7 100644
--- a/chrome/app/vector_icons/credit_card.icon
+++ b/chrome/app/vector_icons/credit_card.icon
@@ -24,5 +24,4 @@
 V_LINE_TO, 8,
 R_H_LINE_TO, 22,
 R_V_LINE_TO, 3,
-CLOSE,
-END
+CLOSE
diff --git a/chrome/app/vector_icons/default_favicon.icon b/chrome/app/vector_icons/default_favicon.icon
index c66dc6b..3639719dd7 100644
--- a/chrome/app/vector_icons/default_favicon.icon
+++ b/chrome/app/vector_icons/default_favicon.icon
@@ -18,5 +18,4 @@
 R_V_LINE_TO, 8,
 R_H_LINE_TO, 8,
 R_V_LINE_TO, 16,
-CLOSE,
-END
\ No newline at end of file
+CLOSE
diff --git a/chrome/app/vector_icons/default_touch_favicon.icon b/chrome/app/vector_icons/default_touch_favicon.icon
index ecc13ead..84bbf3e 100644
--- a/chrome/app/vector_icons/default_touch_favicon.icon
+++ b/chrome/app/vector_icons/default_touch_favicon.icon
@@ -17,5 +17,4 @@
 MOVE_TO, 10, 9,
 LINE_TO, 7, 6,
 LINE_TO, 7, 9,
-CLOSE,
-END
+CLOSE
diff --git a/chrome/app/vector_icons/default_touch_favicon_mask.icon b/chrome/app/vector_icons/default_touch_favicon_mask.icon
index ba64377..3158281b 100644
--- a/chrome/app/vector_icons/default_touch_favicon_mask.icon
+++ b/chrome/app/vector_icons/default_touch_favicon_mask.icon
@@ -4,5 +4,4 @@
 
 CANVAS_DIMENSIONS, 16,
 CIRCLE, 8, 8, 6,
-CLOSE,
-END
+CLOSE
diff --git a/chrome/app/vector_icons/eol.icon b/chrome/app/vector_icons/eol.icon
index 1fa2a35..1d929fc 100644
--- a/chrome/app/vector_icons/eol.icon
+++ b/chrome/app/vector_icons/eol.icon
@@ -55,5 +55,4 @@
 LINE_TO, 34.26f, 38.6f,
 LINE_TO, 45.21f, 49.76f,
 LINE_TO, 45.21f, 50.42f,
-CLOSE,
-END
+CLOSE
diff --git a/chrome/app/vector_icons/extension.icon b/chrome/app/vector_icons/extension.icon
index 75fe2c8..b8174deb 100644
--- a/chrome/app/vector_icons/extension.icon
+++ b/chrome/app/vector_icons/extension.icon
@@ -31,5 +31,4 @@
 R_H_LINE_TO, 3,
 R_CUBIC_TO, 2.76f, 0, 5, -2.24f, 5, -5,
 R_CUBIC_TO, 0, -2.76f, -2.24f, -5, -5, -5,
-CLOSE,
-END
+CLOSE
diff --git a/chrome/app/vector_icons/extension_crashed.icon b/chrome/app/vector_icons/extension_crashed.icon
index 6a88cb6..2229d7397 100644
--- a/chrome/app/vector_icons/extension_crashed.icon
+++ b/chrome/app/vector_icons/extension_crashed.icon
@@ -32,5 +32,4 @@
 LINE_TO, 16, 31.5f,
 LINE_TO, 37, 17.5f,
 LINE_TO, 37, 23,
-CLOSE,
-END
+CLOSE
diff --git a/chrome/app/vector_icons/file_download.icon b/chrome/app/vector_icons/file_download.icon
index e7067c0..b2f7de0 100644
--- a/chrome/app/vector_icons/file_download.icon
+++ b/chrome/app/vector_icons/file_download.icon
@@ -16,5 +16,4 @@
 R_H_LINE_TO, 28,
 R_V_LINE_TO, -4,
 H_LINE_TO, 10,
-CLOSE,
-END
+CLOSE
diff --git a/chrome/app/vector_icons/file_download_shelf.icon b/chrome/app/vector_icons/file_download_shelf.icon
index a77e54099..f35a93d 100644
--- a/chrome/app/vector_icons/file_download_shelf.icon
+++ b/chrome/app/vector_icons/file_download_shelf.icon
@@ -21,5 +21,4 @@
 R_H_LINE_TO, 32,
 R_V_LINE_TO, 4,
 R_H_LINE_TO, -32,
-CLOSE,
-END
+CLOSE
diff --git a/chrome/app/vector_icons/folder.icon b/chrome/app/vector_icons/folder.icon
index 412e6e4..28f38f3 100644
--- a/chrome/app/vector_icons/folder.icon
+++ b/chrome/app/vector_icons/folder.icon
@@ -14,5 +14,4 @@
 R_CUBIC_TO, 0, -1.1f, -0.9f, -2, -2, -2,
 R_H_LINE_TO, -8,
 R_LINE_TO, -2, -2,
-CLOSE,
-END
+CLOSE
diff --git a/chrome/app/vector_icons/folder_supervised.1x.icon b/chrome/app/vector_icons/folder_supervised.1x.icon
index eee32eb..2245267 100644
--- a/chrome/app/vector_icons/folder_supervised.1x.icon
+++ b/chrome/app/vector_icons/folder_supervised.1x.icon
@@ -43,5 +43,4 @@
 CUBIC_TO, 8.75f, 5.56f, 8.19f, 5, 7.5f, 5,
 CUBIC_TO, 6.81f, 5, 6.25f, 5.56f, 6.25f, 6.25f,
 CUBIC_TO, 6.25f, 6.94f, 6.81f, 7.5f, 7.5f, 7.5f,
-CLOSE,
-END
+CLOSE
diff --git a/chrome/app/vector_icons/folder_supervised.icon b/chrome/app/vector_icons/folder_supervised.icon
index 17da033..da6f86f1d 100644
--- a/chrome/app/vector_icons/folder_supervised.icon
+++ b/chrome/app/vector_icons/folder_supervised.icon
@@ -43,5 +43,4 @@
 CUBIC_TO, 17.5f, 18.67f, 16.83f, 18, 16, 18,
 CUBIC_TO, 15.17f, 18, 14.5f, 18.67f, 14.5f, 19.5f,
 CUBIC_TO, 14.5f, 20.33f, 15.17f, 21, 16, 21,
-CLOSE,
-END
+CLOSE
diff --git a/chrome/app/vector_icons/forward_arrow_touch.icon b/chrome/app/vector_icons/forward_arrow_touch.icon
index b7bb8ce..06bb39f 100644
--- a/chrome/app/vector_icons/forward_arrow_touch.icon
+++ b/chrome/app/vector_icons/forward_arrow_touch.icon
@@ -22,5 +22,4 @@
 R_LINE_TO, -0.09f, -0.09f,
 R_ARC_TO, 1, 1, 0, 0, 1, -1.32f, -1.32f,
 R_V_LINE_TO, 0,
-CLOSE,
-END
\ No newline at end of file
+CLOSE
diff --git a/chrome/app/vector_icons/globe.icon b/chrome/app/vector_icons/globe.icon
index 858c2f3..08b0b926 100644
--- a/chrome/app/vector_icons/globe.icon
+++ b/chrome/app/vector_icons/globe.icon
@@ -45,5 +45,4 @@
 CUBIC_TO, 38.14f, 28.44f, 38.29f, 28.42f, 38.44f, 28.4f,
 CUBIC_TO, 37.45f, 31.83f, 35.33f, 34.76f, 32.51f, 36.76f,
 LINE_TO, 32.51f, 36.76f,
-CLOSE,
-END
+CLOSE
diff --git a/chrome/app/vector_icons/google_chrome/product.icon b/chrome/app/vector_icons/google_chrome/product.icon
index ec96ab98..8f98f16 100644
--- a/chrome/app/vector_icons/google_chrome/product.icon
+++ b/chrome/app/vector_icons/google_chrome/product.icon
@@ -39,5 +39,4 @@
 NEW_PATH,
 // Blue
 PATH_COLOR_ARGB, 0xFF, 0x42, 0x85, 0xF4,
-CIRCLE, 12, 12, 3.5,
-END
+CIRCLE, 12, 12, 3.5
diff --git a/chrome/app/vector_icons/google_g_logo.icon b/chrome/app/vector_icons/google_g_logo.icon
index d8ee51b..ba12830 100644
--- a/chrome/app/vector_icons/google_g_logo.icon
+++ b/chrome/app/vector_icons/google_g_logo.icon
@@ -45,5 +45,4 @@
 CUBIC_TO, 9.96f, 0, 4.46f, 3.6f, 1.78f, 8.8f,
 R_LINE_TO, 5.43f, 4.16f,
 R_CUBIC_TO, 1.27f, -3.78f, 4.85f, -6.6f, 9.1f, -6.6f,
-CLOSE,
-END
+CLOSE
diff --git a/chrome/app/vector_icons/google_pay_logo_with_vertical_separator.icon b/chrome/app/vector_icons/google_pay_logo_with_vertical_separator.icon
index b9968af..f3f5e160 100644
--- a/chrome/app/vector_icons/google_pay_logo_with_vertical_separator.icon
+++ b/chrome/app/vector_icons/google_pay_logo_with_vertical_separator.icon
@@ -110,6 +110,5 @@
 R_H_LINE_TO, 1,
 R_V_LINE_TO, 14,
 R_H_LINE_TO, -1,
-CLOSE,
-END
+CLOSE
 
diff --git a/chrome/app/vector_icons/horizontal_menu.1x.icon b/chrome/app/vector_icons/horizontal_menu.1x.icon
index 90c90c64..5b82051 100644
--- a/chrome/app/vector_icons/horizontal_menu.1x.icon
+++ b/chrome/app/vector_icons/horizontal_menu.1x.icon
@@ -20,5 +20,4 @@
 CUBIC_TO, 11.5f, 8.83f, 12.17f, 9.5f, 13, 9.5f,
 CUBIC_TO, 13.83f, 9.5f, 14.5f, 8.83f, 14.5f, 8,
 CUBIC_TO, 14.5f, 7.17f, 13.83f, 6.5f, 13, 6.5f,
-CLOSE,
-END
+CLOSE
diff --git a/chrome/app/vector_icons/horizontal_menu.icon b/chrome/app/vector_icons/horizontal_menu.icon
index 95eedd9..33b5698 100644
--- a/chrome/app/vector_icons/horizontal_menu.icon
+++ b/chrome/app/vector_icons/horizontal_menu.icon
@@ -20,5 +20,4 @@
 CUBIC_TO, 22.34f, 19, 21, 17.66f, 21, 16,
 CUBIC_TO, 21, 14.34f, 22.34f, 13, 24, 13,
 CUBIC_TO, 25.66f, 13, 27, 14.34f, 27, 16,
-CLOSE,
-END
+CLOSE
diff --git a/chrome/app/vector_icons/image.icon b/chrome/app/vector_icons/image.icon
index 89eee8a..bcd00bb 100644
--- a/chrome/app/vector_icons/image.icon
+++ b/chrome/app/vector_icons/image.icon
@@ -18,5 +18,4 @@
 R_LINE_TO, 9, 12,
 H_LINE_TO, 10,
 R_LINE_TO, 7, -9,
-CLOSE,
-END
+CLOSE
diff --git a/chrome/app/vector_icons/inactive_toast_arrow.icon b/chrome/app/vector_icons/inactive_toast_arrow.icon
index 195ea064..a1ffcf1 100644
--- a/chrome/app/vector_icons/inactive_toast_arrow.icon
+++ b/chrome/app/vector_icons/inactive_toast_arrow.icon
@@ -16,5 +16,4 @@
 LINE_TO, 12.0f, 12.0f,
 LINE_TO, 25.0f, -1.29452005e-13f,
 LINE_TO, -1.0f, -1.26121336e-13f,
-CLOSE,
-END
+CLOSE
diff --git a/chrome/app/vector_icons/inactive_toast_close.icon b/chrome/app/vector_icons/inactive_toast_close.icon
index 57ff3c6..f9aadfb 100644
--- a/chrome/app/vector_icons/inactive_toast_close.icon
+++ b/chrome/app/vector_icons/inactive_toast_close.icon
@@ -16,5 +16,4 @@
 R_LINE_TO, 3.89f, 3.89f,
 R_LINE_TO, 0.71f, -0.71f,
 R_LINE_TO, -3.89f, -3.89f,
-CLOSE,
-END
+CLOSE
diff --git a/chrome/app/vector_icons/inactive_toast_logo.icon b/chrome/app/vector_icons/inactive_toast_logo.icon
index 8af149c..3ed5614 100644
--- a/chrome/app/vector_icons/inactive_toast_logo.icon
+++ b/chrome/app/vector_icons/inactive_toast_logo.icon
@@ -27,5 +27,4 @@
 R_H_LINE_TO, -6.6f,
 R_CUBIC_TO, 1, 0.8f, 1.7f, 2.1f, 1.7f, 3.5f,
 CLOSE,
-CIRCLE, 12, 12, 3.5,
-END
+CIRCLE, 12, 12, 3.5
diff --git a/chrome/app/vector_icons/incognito.1x.icon b/chrome/app/vector_icons/incognito.1x.icon
index 4f9d36d..420a90e 100644
--- a/chrome/app/vector_icons/incognito.1x.icon
+++ b/chrome/app/vector_icons/incognito.1x.icon
@@ -48,5 +48,4 @@
 R_H_LINE_TO, 18,
 R_LINE_TO, -3.8f, -2,
 H_LINE_TO, 6.93f,
-CLOSE,
-END
+CLOSE
diff --git a/chrome/app/vector_icons/incognito.icon b/chrome/app/vector_icons/incognito.icon
index 0798668..5ebf9d94 100644
--- a/chrome/app/vector_icons/incognito.icon
+++ b/chrome/app/vector_icons/incognito.icon
@@ -49,5 +49,4 @@
 LINE_TO, 18.46f, 9.23f,
 LINE_TO, 16.26f, 16,
 R_H_LINE_TO, 15.64f,
-CLOSE,
-END
+CLOSE
diff --git a/chrome/app/vector_icons/key.icon b/chrome/app/vector_icons/key.icon
index c529eb8..f8a919c 100644
--- a/chrome/app/vector_icons/key.icon
+++ b/chrome/app/vector_icons/key.icon
@@ -21,5 +21,4 @@
 R_CUBIC_TO, 0, -1.66f, -1.34f, -3, -3, -3,
 R_CUBIC_TO, -1.66f, 0, -3, 1.34f, -3, 3,
 R_CUBIC_TO, 0, 1.66f, 1.34f, 3, 3, 3,
-CLOSE,
-END
\ No newline at end of file
+CLOSE
diff --git a/chrome/app/vector_icons/laptop.icon b/chrome/app/vector_icons/laptop.icon
index 4ca2f98..8b2e9e41 100644
--- a/chrome/app/vector_icons/laptop.icon
+++ b/chrome/app/vector_icons/laptop.icon
@@ -21,5 +21,4 @@
 R_V_LINE_TO, 20,
 H_LINE_TO, 8,
 V_LINE_TO, 12,
-CLOSE,
-END
+CLOSE
diff --git a/chrome/app/vector_icons/launch.icon b/chrome/app/vector_icons/launch.icon
index 22223d6..b03c0aa 100644
--- a/chrome/app/vector_icons/launch.icon
+++ b/chrome/app/vector_icons/launch.icon
@@ -26,5 +26,4 @@
 V_LINE_TO, 8,
 H_LINE_TO, 15,
 V_LINE_TO, 3,
-CLOSE,
-END
+CLOSE
diff --git a/chrome/app/vector_icons/mixed_content.icon b/chrome/app/vector_icons/mixed_content.icon
index a3303bbe..1c62044a 100644
--- a/chrome/app/vector_icons/mixed_content.icon
+++ b/chrome/app/vector_icons/mixed_content.icon
@@ -16,5 +16,4 @@
 LINE_TO, 39, 22.11f,
 CUBIC_TO, 39, 29.93f, 33.34f, 38.22f, 26, 40,
 LINE_TO, 26, 8,
-CLOSE,
-END
+CLOSE
diff --git a/chrome/app/vector_icons/my_location.icon b/chrome/app/vector_icons/my_location.icon
index fcbf685..c3d8647 100644
--- a/chrome/app/vector_icons/my_location.icon
+++ b/chrome/app/vector_icons/my_location.icon
@@ -31,5 +31,4 @@
 R_CUBIC_TO, 0, -7.73f, 6.27f, -14, 14, -14,
 R_CUBIC_TO, 7.73f, 0, 14, 6.27f, 14, 14,
 R_CUBIC_TO, 0, 7.73f, -6.27f, 14, -14, 14,
-CLOSE,
-END
+CLOSE
diff --git a/chrome/app/vector_icons/navigate_home.1x.icon b/chrome/app/vector_icons/navigate_home.1x.icon
index 1312e01..d140ec70 100644
--- a/chrome/app/vector_icons/navigate_home.1x.icon
+++ b/chrome/app/vector_icons/navigate_home.1x.icon
@@ -28,5 +28,4 @@
 CUBIC_TO, 2.5f, 16, 2, 15.5f, 2, 14.5f,
 LINE_TO, 2, 8.3f,
 LINE_TO, 2, 8.3f,
-CLOSE,
-END
+CLOSE
diff --git a/chrome/app/vector_icons/navigate_home.icon b/chrome/app/vector_icons/navigate_home.icon
index 2a6f8d1..42aa6e0f 100644
--- a/chrome/app/vector_icons/navigate_home.icon
+++ b/chrome/app/vector_icons/navigate_home.icon
@@ -33,5 +33,4 @@
 CUBIC_TO, 6.9f, 29, 6, 28.1f, 6, 27,
 LINE_TO, 6, 17.39f,
 LINE_TO, 6, 17.39f,
-CLOSE,
-END
+CLOSE
diff --git a/chrome/app/vector_icons/navigate_home_touch.icon b/chrome/app/vector_icons/navigate_home_touch.icon
index d266a1e..a2c6762a 100644
--- a/chrome/app/vector_icons/navigate_home_touch.icon
+++ b/chrome/app/vector_icons/navigate_home_touch.icon
@@ -28,5 +28,4 @@
 R_LINE_TO, 5, 5.15f,
 V_LINE_TO, 19,
 H_LINE_TO, 7,
-CLOSE,
-END
\ No newline at end of file
+CLOSE
diff --git a/chrome/app/vector_icons/navigate_stop.1x.icon b/chrome/app/vector_icons/navigate_stop.1x.icon
index bb69c8099..7e86af5 100644
--- a/chrome/app/vector_icons/navigate_stop.1x.icon
+++ b/chrome/app/vector_icons/navigate_stop.1x.icon
@@ -19,5 +19,4 @@
 LINE_TO, 13.75f, 12.57f,
 CUBIC_TO, 14.08f, 12.9f, 14.08f, 13.43f, 13.75f, 13.75f,
 CUBIC_TO, 13.43f, 14.08f, 12.9f, 14.08f, 12.57f, 13.75f,
-CLOSE,
-END
+CLOSE
diff --git a/chrome/app/vector_icons/navigate_stop.icon b/chrome/app/vector_icons/navigate_stop.icon
index 5885cfcc..a8bcead 100644
--- a/chrome/app/vector_icons/navigate_stop.icon
+++ b/chrome/app/vector_icons/navigate_stop.icon
@@ -19,5 +19,4 @@
 LINE_TO, 27.51f, 25.14f,
 CUBIC_TO, 28.16f, 25.79f, 28.16f, 26.85f, 27.51f, 27.51f,
 CUBIC_TO, 26.85f, 28.16f, 25.79f, 28.16f, 25.14f, 27.51f,
-CLOSE,
-END
+CLOSE
diff --git a/chrome/app/vector_icons/navigate_stop_touch.icon b/chrome/app/vector_icons/navigate_stop_touch.icon
index 1ef5b4f..60cfd8ad 100644
--- a/chrome/app/vector_icons/navigate_stop_touch.icon
+++ b/chrome/app/vector_icons/navigate_stop_touch.icon
@@ -28,5 +28,4 @@
 LINE_TO, 6.5f, 5,
 LINE_TO, 12, 10.51f,
 LINE_TO, 17.51f, 5,
-CLOSE,
-END
\ No newline at end of file
+CLOSE
diff --git a/chrome/app/vector_icons/new_tab_button_incognito.icon b/chrome/app/vector_icons/new_tab_button_incognito.icon
index d73efbd..b487335f 100644
--- a/chrome/app/vector_icons/new_tab_button_incognito.icon
+++ b/chrome/app/vector_icons/new_tab_button_incognito.icon
@@ -41,5 +41,4 @@
 R_CUBIC_TO, 0, -0.56f, -0.45f, -1, -1, -1,
 R_CUBIC_TO, -0.55f, 0, -1, 0.45f, -1, 1,
 R_CUBIC_TO, 0, 0.56f, 0.45f, 1, 1, 1,
-CLOSE,
-END
\ No newline at end of file
+CLOSE
diff --git a/chrome/app/vector_icons/new_tab_button_plus.icon b/chrome/app/vector_icons/new_tab_button_plus.icon
index e23da8e0..69484e674 100644
--- a/chrome/app/vector_icons/new_tab_button_plus.icon
+++ b/chrome/app/vector_icons/new_tab_button_plus.icon
@@ -15,5 +15,4 @@
 R_H_LINE_TO, 5,
 V_LINE_TO, 0,
 R_H_LINE_TO, 2,
-CLOSE,
-END
\ No newline at end of file
+CLOSE
diff --git a/chrome/app/vector_icons/new_tab_mac_touchbar.icon b/chrome/app/vector_icons/new_tab_mac_touchbar.icon
index 807837f..43265a7 100644
--- a/chrome/app/vector_icons/new_tab_mac_touchbar.icon
+++ b/chrome/app/vector_icons/new_tab_mac_touchbar.icon
@@ -22,5 +22,4 @@
 R_V_LINE_TO, 12,
 R_H_LINE_TO, 12,
 R_V_LINE_TO, 6,
-CLOSE,
-END
\ No newline at end of file
+CLOSE
diff --git a/chrome/app/vector_icons/open_in_phone.icon b/chrome/app/vector_icons/open_in_phone.icon
index 3ec5522b..a990614 100644
--- a/chrome/app/vector_icons/open_in_phone.icon
+++ b/chrome/app/vector_icons/open_in_phone.icon
@@ -28,5 +28,4 @@
 R_CUBIC_TO, 1.1f, 0, 2, -0.9f, 2, -2,
 V_LINE_TO, 3,
 R_CUBIC_TO, 0, -1.1f, -0.9f, -1.99f, -2, -1.99f,
-CLOSE,
-END
+CLOSE
diff --git a/chrome/app/vector_icons/overflow_chevron.1x.icon b/chrome/app/vector_icons/overflow_chevron.1x.icon
index 073f07c..a0b8ef1 100644
--- a/chrome/app/vector_icons/overflow_chevron.1x.icon
+++ b/chrome/app/vector_icons/overflow_chevron.1x.icon
@@ -24,5 +24,4 @@
 LINE_TO, 7.76f, 4.55f,
 CUBIC_TO, 8.08f, 4.25f, 8.08f, 3.75f, 7.76f, 3.45f,
 LINE_TO, 5.41f, 1.23f,
-CLOSE,
-END
+CLOSE
diff --git a/chrome/app/vector_icons/overflow_chevron.icon b/chrome/app/vector_icons/overflow_chevron.icon
index 874c5b6..542ec32 100644
--- a/chrome/app/vector_icons/overflow_chevron.icon
+++ b/chrome/app/vector_icons/overflow_chevron.icon
@@ -24,5 +24,4 @@
 LINE_TO, 13.64f, 8.52f,
 CUBIC_TO, 14.12f, 7.95f, 14.12f, 7.05f, 13.64f, 6.48f,
 LINE_TO, 10.12f, 2.42f,
-CLOSE,
-END
+CLOSE
diff --git a/chrome/app/vector_icons/page_info_content_paste.icon b/chrome/app/vector_icons/page_info_content_paste.icon
index e884297..091253ce 100644
--- a/chrome/app/vector_icons/page_info_content_paste.icon
+++ b/chrome/app/vector_icons/page_info_content_paste.icon
@@ -28,5 +28,4 @@
 H_LINE_TO, 7,
 R_ARC_TO, 1, 1, 0, 0, 1, -1, -1,
 R_V_LINE_TO, -1.5f,
-CLOSE,
-END
+CLOSE
diff --git a/chrome/app/vector_icons/paintbrush.icon b/chrome/app/vector_icons/paintbrush.icon
index 9b7b2a6..dd55dee1 100644
--- a/chrome/app/vector_icons/paintbrush.icon
+++ b/chrome/app/vector_icons/paintbrush.icon
@@ -35,5 +35,4 @@
 LINE_TO, 5.6f, 27.6f,
 LINE_TO, 13.8f, 35.83f,
 LINE_TO, 13.8f, 35.83f,
-CLOSE,
-END
+CLOSE
diff --git a/chrome/app/vector_icons/photo.icon b/chrome/app/vector_icons/photo.icon
index 4b1e7a6..5bfe351 100644
--- a/chrome/app/vector_icons/photo.icon
+++ b/chrome/app/vector_icons/photo.icon
@@ -18,5 +18,4 @@
 LINE_TO, 10.67f, 9,
 R_LINE_TO, 3, 4,
 H_LINE_TO, 4.33f,
-CLOSE,
-END
+CLOSE
diff --git a/chrome/app/vector_icons/photo_camera.icon b/chrome/app/vector_icons/photo_camera.icon
index 3667b98..fd72bbd 100644
--- a/chrome/app/vector_icons/photo_camera.icon
+++ b/chrome/app/vector_icons/photo_camera.icon
@@ -17,5 +17,4 @@
 LINE_TO, 30, 4,
 H_LINE_TO, 18,
 CLOSE,
-CIRCLE, 24, 24, 10,
-END
+CIRCLE, 24, 24, 10
diff --git a/chrome/app/vector_icons/profile_switcher_outline.icon b/chrome/app/vector_icons/profile_switcher_outline.icon
index 11b0d52b..e9c12ce 100644
--- a/chrome/app/vector_icons/profile_switcher_outline.icon
+++ b/chrome/app/vector_icons/profile_switcher_outline.icon
@@ -45,5 +45,4 @@
 R_CUBIC_TO, 0.05f, -3.97f, 8.01f, -6.16f, 12, -6.16f,
 R_CUBIC_TO, 3.99f, 0, 11.94f, 2.19f, 12, 6.16f,
 R_CUBIC_TO, -2.59f, 3.88f, -6.99f, 6.44f, -12, 6.44f,
-CLOSE,
-END
+CLOSE
diff --git a/chrome/app/vector_icons/reload_touch.icon b/chrome/app/vector_icons/reload_touch.icon
index 0e3d14b..aac2d29 100644
--- a/chrome/app/vector_icons/reload_touch.icon
+++ b/chrome/app/vector_icons/reload_touch.icon
@@ -21,5 +21,4 @@
 CUBIC_TO, 7.6f, 20, 4, 16.42f, 4, 12,
 R_CUBIC_TO, 0, -4.42f, 3.6f, -8, 8.04f, -8,
 R_CUBIC_TO, 2.2f, 0, 4.2f, 0.88f, 5.65f, 2.32f,
-CLOSE,
-END
\ No newline at end of file
+CLOSE
diff --git a/chrome/app/vector_icons/remove.icon b/chrome/app/vector_icons/remove.icon
index 31af5d4..e2ca0dda 100644
--- a/chrome/app/vector_icons/remove.icon
+++ b/chrome/app/vector_icons/remove.icon
@@ -6,5 +6,4 @@
 STROKE, 2.f,
 CAP_SQUARE,
 MOVE_TO, 3, 8,
-R_H_LINE_TO, 10,
-END
+R_H_LINE_TO, 10
diff --git a/chrome/app/vector_icons/remove_box.icon b/chrome/app/vector_icons/remove_box.icon
index 6374ad7..c17ba2f2 100644
--- a/chrome/app/vector_icons/remove_box.icon
+++ b/chrome/app/vector_icons/remove_box.icon
@@ -18,5 +18,4 @@
 R_V_LINE_TO, -2,
 R_H_LINE_TO, 10,
 R_V_LINE_TO, 2,
-CLOSE,
-END
+CLOSE
diff --git a/chrome/app/vector_icons/sad_tab.icon b/chrome/app/vector_icons/sad_tab.icon
index 6876aca..dfcaf99c 100644
--- a/chrome/app/vector_icons/sad_tab.icon
+++ b/chrome/app/vector_icons/sad_tab.icon
@@ -44,5 +44,4 @@
 LINE_TO, 28, 23,
 LINE_TO, 28, 18,
 LINE_TO, 28, 18,
-CLOSE,
-END
+CLOSE
diff --git a/chrome/app/vector_icons/security.icon b/chrome/app/vector_icons/security.icon
index c949e291..561c15e 100644
--- a/chrome/app/vector_icons/security.icon
+++ b/chrome/app/vector_icons/security.icon
@@ -19,5 +19,4 @@
 V_LINE_TO, 12.6f,
 R_LINE_TO, 14, -6.22f,
 R_V_LINE_TO, 17.6f,
-CLOSE,
-END
+CLOSE
diff --git a/chrome/app/vector_icons/sensors.icon b/chrome/app/vector_icons/sensors.icon
index 75c785a3..4d6bb3a 100644
--- a/chrome/app/vector_icons/sensors.icon
+++ b/chrome/app/vector_icons/sensors.icon
@@ -40,5 +40,4 @@
 R_CUBIC_TO, 2.2f, -1.3f, 3.8f, -3.8f, 3.8f, -6.6f,
 R_CUBIC_TO, 0, -2.8f, -1.5f, -5.2f, -3.7f, -6.6f,
 LINE_TO, 12, 3.7f,
-CLOSE,
-END
+CLOSE
diff --git a/chrome/app/vector_icons/settings.icon b/chrome/app/vector_icons/settings.icon
index 8150a91..6286b5e 100644
--- a/chrome/app/vector_icons/settings.icon
+++ b/chrome/app/vector_icons/settings.icon
@@ -47,5 +47,4 @@
 R_CUBIC_TO, 0, -3.87f, 3.13f, -7, 7, -7,
 R_CUBIC_TO, 3.87f, 0, 7, 3.13f, 7, 7,
 R_CUBIC_TO, 0, 3.87f, -3.13f, 7, -7, 7,
-CLOSE,
-END
+CLOSE
diff --git a/chrome/app/vector_icons/signin_button_drop_down_arrow.icon b/chrome/app/vector_icons/signin_button_drop_down_arrow.icon
index 04734a7d..baeef57 100644
--- a/chrome/app/vector_icons/signin_button_drop_down_arrow.icon
+++ b/chrome/app/vector_icons/signin_button_drop_down_arrow.icon
@@ -6,5 +6,4 @@
 MOVE_TO, 5, 8,
 R_H_LINE_TO, 14,
 R_LINE_TO, -7, 11,
-CLOSE,
-END
+CLOSE
diff --git a/chrome/app/vector_icons/smartphone.icon b/chrome/app/vector_icons/smartphone.icon
index 278ef4d..27851c96 100644
--- a/chrome/app/vector_icons/smartphone.icon
+++ b/chrome/app/vector_icons/smartphone.icon
@@ -17,5 +17,4 @@
 V_LINE_TO, 10,
 R_H_LINE_TO, 20,
 R_V_LINE_TO, 28,
-CLOSE,
-END
+CLOSE
diff --git a/chrome/app/vector_icons/supervisor_account.icon b/chrome/app/vector_icons/supervisor_account.icon
index 4b317121..fc4d1d17 100644
--- a/chrome/app/vector_icons/supervisor_account.icon
+++ b/chrome/app/vector_icons/supervisor_account.icon
@@ -18,4 +18,3 @@
 R_V_LINE_TO, -4.5f,
 R_CUBIC_TO, 0, -1.7f, .67f, -4.67f, 4.74f, -6.94f,
 CUBIC_TO, 21, 26.19f, 19.31f, 26, 18, 26,
-END,
diff --git a/chrome/app/vector_icons/supervisor_account_circle.icon b/chrome/app/vector_icons/supervisor_account_circle.icon
index e0478bf..03b962fc 100644
--- a/chrome/app/vector_icons/supervisor_account_circle.icon
+++ b/chrome/app/vector_icons/supervisor_account_circle.icon
@@ -34,5 +34,4 @@
 R_CUBIC_TO, 0, -1.42f, 2.94f, -2.13f, 4.4f, -2.13f,
 R_CUBIC_TO, 1.07f, 0, 2.92f, 0.39f, 3.84f, 1.15f,
 R_CUBIC_TO, -1.17f, 2.97f, -4.06f, 5.09f, -7.45f, 5.09f,
-CLOSE,
-END
+CLOSE
diff --git a/chrome/app/vector_icons/sync.icon b/chrome/app/vector_icons/sync.icon
index c2727bb..34964fc 100644
--- a/chrome/app/vector_icons/sync.icon
+++ b/chrome/app/vector_icons/sync.icon
@@ -24,5 +24,4 @@
 R_LINE_TO, 2.5f, -2.36f,
 LINE_TO, 8, 9.77f,
 R_V_LINE_TO, 1.77f,
-CLOSE,
-END
+CLOSE
diff --git a/chrome/app/vector_icons/sync_circle.icon b/chrome/app/vector_icons/sync_circle.icon
index 6276c0b..1d9002c9 100644
--- a/chrome/app/vector_icons/sync_circle.icon
+++ b/chrome/app/vector_icons/sync_circle.icon
@@ -25,5 +25,4 @@
 R_LINE_TO, 0.73f, 0.73f,
 R_CUBIC_TO, 0.39f, -0.61f, 0.62f, -1.34f, 0.62f, -2.13f,
 R_CUBIC_TO, 0, -2.21f, -1.79f, -4, -4, -4,
-CLOSE,
-END
+CLOSE
diff --git a/chrome/app/vector_icons/sync_error_circle.icon b/chrome/app/vector_icons/sync_error_circle.icon
index 62a4afa4..19160e76 100644
--- a/chrome/app/vector_icons/sync_error_circle.icon
+++ b/chrome/app/vector_icons/sync_error_circle.icon
@@ -37,5 +37,4 @@
 R_V_LINE_TO, -3,
 R_H_LINE_TO, -1,
 R_V_LINE_TO, 3,
-CLOSE,
-END
+CLOSE
diff --git a/chrome/app/vector_icons/sync_problem.icon b/chrome/app/vector_icons/sync_problem.icon
index 590cea7b..e512d9f 100644
--- a/chrome/app/vector_icons/sync_problem.icon
+++ b/chrome/app/vector_icons/sync_problem.icon
@@ -35,5 +35,4 @@
 V_LINE_TO, 14,
 R_H_LINE_TO, -4,
 R_V_LINE_TO, 12,
-CLOSE,
-END
+CLOSE
diff --git a/chrome/app/vector_icons/sync_switch_account.icon b/chrome/app/vector_icons/sync_switch_account.icon
index 71e863a..88eaf6d 100644
--- a/chrome/app/vector_icons/sync_switch_account.icon
+++ b/chrome/app/vector_icons/sync_switch_account.icon
@@ -20,5 +20,4 @@
 R_H_LINE_TO, 4.55f,
 R_V_LINE_TO, 1.94f,
 LINE_TO, 14, 5.58f,
-CLOSE,
-END
+CLOSE
diff --git a/chrome/app/vector_icons/tab.icon b/chrome/app/vector_icons/tab.icon
index aaaf6cc2..debaf86 100644
--- a/chrome/app/vector_icons/tab.icon
+++ b/chrome/app/vector_icons/tab.icon
@@ -19,5 +19,4 @@
 R_V_LINE_TO, 8,
 R_H_LINE_TO, 16,
 R_V_LINE_TO, 20,
-CLOSE,
-END
+CLOSE
diff --git a/chrome/app/vector_icons/tab_audio.1x.icon b/chrome/app/vector_icons/tab_audio.1x.icon
index 19d3e2c..f2689701 100644
--- a/chrome/app/vector_icons/tab_audio.1x.icon
+++ b/chrome/app/vector_icons/tab_audio.1x.icon
@@ -16,5 +16,4 @@
 MOVE_TO, 10.5f, 6,
 R_V_LINE_TO, 3,
 MOVE_TO, 12.5f, 5,
-R_V_LINE_TO, 5,
-END
+R_V_LINE_TO, 5
diff --git a/chrome/app/vector_icons/tab_audio.icon b/chrome/app/vector_icons/tab_audio.icon
index 5aa896d..1ed5205e 100644
--- a/chrome/app/vector_icons/tab_audio.icon
+++ b/chrome/app/vector_icons/tab_audio.icon
@@ -19,5 +19,4 @@
 R_V_LINE_TO, 10,
 R_H_LINE_TO, 2,
 R_V_LINE_TO, -10,
-CLOSE,
-END
+CLOSE
diff --git a/chrome/app/vector_icons/tab_audio_muting.1x.icon b/chrome/app/vector_icons/tab_audio_muting.1x.icon
index 719f492..b81d3044 100644
--- a/chrome/app/vector_icons/tab_audio_muting.1x.icon
+++ b/chrome/app/vector_icons/tab_audio_muting.1x.icon
@@ -22,5 +22,4 @@
 MOVE_TO, 10.5f, 6,
 R_V_LINE_TO, 1.5f,
 MOVE_TO, 12.5f, 5,
-R_V_LINE_TO, 4.5f,
-END
+R_V_LINE_TO, 4.5f
diff --git a/chrome/app/vector_icons/tab_audio_muting.icon b/chrome/app/vector_icons/tab_audio_muting.icon
index 69a6cbc..166a98b 100644
--- a/chrome/app/vector_icons/tab_audio_muting.icon
+++ b/chrome/app/vector_icons/tab_audio_muting.icon
@@ -28,5 +28,4 @@
 R_LINE_TO, 2, 2,
 R_V_LINE_TO, -9,
 R_H_LINE_TO, -2,
-CLOSE,
-END
+CLOSE
diff --git a/chrome/app/vector_icons/tab_audio_muting_rounded.icon b/chrome/app/vector_icons/tab_audio_muting_rounded.icon
index 5894536..24ee2e3 100644
--- a/chrome/app/vector_icons/tab_audio_muting_rounded.icon
+++ b/chrome/app/vector_icons/tab_audio_muting_rounded.icon
@@ -38,5 +38,4 @@
 LINE_TO, 4.84f, 2.72f,
 LINE_TO, 6, 3.88f,
 LINE_TO, 6, 1.56f,
-CLOSE,
-END
+CLOSE
diff --git a/chrome/app/vector_icons/tab_audio_rounded.icon b/chrome/app/vector_icons/tab_audio_rounded.icon
index 5dc3f0e1..6462ea0 100644
--- a/chrome/app/vector_icons/tab_audio_rounded.icon
+++ b/chrome/app/vector_icons/tab_audio_rounded.icon
@@ -23,5 +23,4 @@
 LINE_TO, 7.11f, 11,
 CUBIC_TO, 9.34f, 10.48f, 11, 8.44f, 11, 6,
 CUBIC_TO, 11, 3.56f, 9.34f, 1.52f, 7.11f, 1,
-CLOSE,
-END
+CLOSE
diff --git a/chrome/app/vector_icons/tab_bluetooth_connected.icon b/chrome/app/vector_icons/tab_bluetooth_connected.icon
index 9ed1125..3d75601 100644
--- a/chrome/app/vector_icons/tab_bluetooth_connected.icon
+++ b/chrome/app/vector_icons/tab_bluetooth_connected.icon
@@ -30,5 +30,4 @@
 R_V_LINE_TO, -6,
 R_LINE_TO, 2.83f, 3.01f,
 H_LINE_TO, 21,
-CLOSE,
-END
\ No newline at end of file
+CLOSE
diff --git a/chrome/app/vector_icons/tab_close_button_touch.icon b/chrome/app/vector_icons/tab_close_button_touch.icon
index 8911437..661ec4e 100644
--- a/chrome/app/vector_icons/tab_close_button_touch.icon
+++ b/chrome/app/vector_icons/tab_close_button_touch.icon
@@ -18,5 +18,4 @@
 LINE_TO, 15.65f, 16.83f,
 LINE_TO, 16.83f, 15.65f,
 LINE_TO, 13.18f, 12,
-CLOSE,
-END
+CLOSE
diff --git a/chrome/app/vector_icons/tab_close_button_touch_incognito.icon b/chrome/app/vector_icons/tab_close_button_touch_incognito.icon
index a6d85b8..7e9299c 100644
--- a/chrome/app/vector_icons/tab_close_button_touch_incognito.icon
+++ b/chrome/app/vector_icons/tab_close_button_touch_incognito.icon
@@ -18,5 +18,4 @@
 LINE_TO, 15.65f, 16.83f,
 LINE_TO, 16.83f, 15.65f,
 LINE_TO, 13.18f, 12,
-CLOSE,
-END
+CLOSE
diff --git a/chrome/app/vector_icons/tab_close_button_touch_incognito_hovered_pressed.icon b/chrome/app/vector_icons/tab_close_button_touch_incognito_hovered_pressed.icon
index 47c8817b..d9cb4ac7 100644
--- a/chrome/app/vector_icons/tab_close_button_touch_incognito_hovered_pressed.icon
+++ b/chrome/app/vector_icons/tab_close_button_touch_incognito_hovered_pressed.icon
@@ -18,5 +18,4 @@
 LINE_TO, 15.65f, 16.83f,
 LINE_TO, 16.83f, 15.65f,
 LINE_TO, 13.18f, 12,
-CLOSE,
-END
+CLOSE
diff --git a/chrome/app/vector_icons/tab_close_hovered_pressed.1x.icon b/chrome/app/vector_icons/tab_close_hovered_pressed.1x.icon
index facef29..1673116 100644
--- a/chrome/app/vector_icons/tab_close_hovered_pressed.1x.icon
+++ b/chrome/app/vector_icons/tab_close_hovered_pressed.1x.icon
@@ -12,5 +12,4 @@
 MOVE_TO, 4.75f, 4.75f,
 R_LINE_TO, 6.5f, 6.5f,
 MOVE_TO, 4.75f, 11.25f,
-R_LINE_TO, 6.5f, -6.5f,
-END
\ No newline at end of file
+R_LINE_TO, 6.5f, -6.5f
diff --git a/chrome/app/vector_icons/tab_close_hovered_pressed.icon b/chrome/app/vector_icons/tab_close_hovered_pressed.icon
index 8b6696af..f8b979e2 100644
--- a/chrome/app/vector_icons/tab_close_hovered_pressed.icon
+++ b/chrome/app/vector_icons/tab_close_hovered_pressed.icon
@@ -11,5 +11,4 @@
 MOVE_TO, 10.25f, 10.25f,
 R_LINE_TO, 11.5f, 11.5f,
 MOVE_TO, 10.25f, 21.75f,
-R_LINE_TO, 11.5f, -11.5f,
-END
\ No newline at end of file
+R_LINE_TO, 11.5f, -11.5f
diff --git a/chrome/app/vector_icons/tab_close_normal.1x.icon b/chrome/app/vector_icons/tab_close_normal.1x.icon
index 22108de..9df4bd8 100644
--- a/chrome/app/vector_icons/tab_close_normal.1x.icon
+++ b/chrome/app/vector_icons/tab_close_normal.1x.icon
@@ -9,5 +9,4 @@
 MOVE_TO, 4.75f, 4.75f,
 R_LINE_TO, 6.5f, 6.5f,
 MOVE_TO, 4.75f, 11.25f,
-R_LINE_TO, 6.5f, -6.5f,
-END
\ No newline at end of file
+R_LINE_TO, 6.5f, -6.5f
diff --git a/chrome/app/vector_icons/tab_close_normal.icon b/chrome/app/vector_icons/tab_close_normal.icon
index 1597b26..fe6a968 100644
--- a/chrome/app/vector_icons/tab_close_normal.icon
+++ b/chrome/app/vector_icons/tab_close_normal.icon
@@ -8,5 +8,4 @@
 MOVE_TO, 10.25f, 10.25f,
 R_LINE_TO, 11.5f, 11.5f,
 MOVE_TO, 10.25f, 21.75f,
-R_LINE_TO, 11.5f, -11.5f,
-END
\ No newline at end of file
+R_LINE_TO, 11.5f, -11.5f
diff --git a/chrome/app/vector_icons/tab_media_capturing.icon b/chrome/app/vector_icons/tab_media_capturing.icon
index ed94532..517784b3 100644
--- a/chrome/app/vector_icons/tab_media_capturing.icon
+++ b/chrome/app/vector_icons/tab_media_capturing.icon
@@ -21,5 +21,4 @@
 R_V_LINE_TO, 16,
 H_LINE_TO, 4,
 V_LINE_TO, 8,
-CLOSE,
-END
+CLOSE
diff --git a/chrome/app/vector_icons/tab_media_capturing_with_arrow.icon b/chrome/app/vector_icons/tab_media_capturing_with_arrow.icon
index 7184673..0c37cc7 100644
--- a/chrome/app/vector_icons/tab_media_capturing_with_arrow.icon
+++ b/chrome/app/vector_icons/tab_media_capturing_with_arrow.icon
@@ -28,5 +28,4 @@
 LINE_TO, 7.92f, 7,
 CUBIC_TO, 5.14f, 7, 4.38f, 9, 4, 11,
 CUBIC_TO, 4.93f, 9.6f, 5.88f, 8.96f, 7.92f, 9,
-CLOSE,
-END
+CLOSE
diff --git a/chrome/app/vector_icons/tab_media_recording.icon b/chrome/app/vector_icons/tab_media_recording.icon
index b97009d..ee2bab57 100644
--- a/chrome/app/vector_icons/tab_media_recording.icon
+++ b/chrome/app/vector_icons/tab_media_recording.icon
@@ -20,5 +20,4 @@
 R_CUBIC_TO, 0, -4.42f, -3.58f, -8, -8, -8,
 R_CUBIC_TO, -4.42f, 0, -8, 3.58f, -8, 8,
 R_CUBIC_TO, 0, 4.42f, 3.58f, 8, 8, 8,
-CLOSE,
-END
+CLOSE
diff --git a/chrome/app/vector_icons/tab_usb_connected.1x.icon b/chrome/app/vector_icons/tab_usb_connected.1x.icon
index 00cc795..dcf4c40 100644
--- a/chrome/app/vector_icons/tab_usb_connected.1x.icon
+++ b/chrome/app/vector_icons/tab_usb_connected.1x.icon
@@ -34,5 +34,4 @@
 V_LINE_TO, 6,
 R_H_LINE_TO, -2,
 R_V_LINE_TO, 2,
-CLOSE,
-END
+CLOSE
diff --git a/chrome/app/vector_icons/tab_usb_connected.icon b/chrome/app/vector_icons/tab_usb_connected.icon
index 2884fdf..19978a3 100644
--- a/chrome/app/vector_icons/tab_usb_connected.icon
+++ b/chrome/app/vector_icons/tab_usb_connected.icon
@@ -35,5 +35,4 @@
 R_V_LINE_TO, -4,
 R_H_LINE_TO, -4,
 R_V_LINE_TO, 4,
-CLOSE,
-END
+CLOSE
diff --git a/chrome/app/vector_icons/tablet.icon b/chrome/app/vector_icons/tablet.icon
index 121bfd49..23f3eae 100644
--- a/chrome/app/vector_icons/tablet.icon
+++ b/chrome/app/vector_icons/tablet.icon
@@ -17,5 +17,4 @@
 V_LINE_TO, 12,
 R_H_LINE_TO, 28,
 R_V_LINE_TO, 24,
-CLOSE,
-END
+CLOSE
diff --git a/chrome/app/vector_icons/translate.icon b/chrome/app/vector_icons/translate.icon
index d553c9ba..6c06119 100644
--- a/chrome/app/vector_icons/translate.icon
+++ b/chrome/app/vector_icons/translate.icon
@@ -71,5 +71,4 @@
 CUBIC_TO, 11.26f, 7.36f, 11.02f, 8.27f, 10.17f, 9.27f,
 CUBIC_TO, 9.81f, 8.84f, 9.55f, 8.41f, 9.38f, 8.08f,
 LINE_TO, 8.69f, 8.08f,
-CLOSE,
-END
+CLOSE
diff --git a/chrome/app/vector_icons/trash_can.icon b/chrome/app/vector_icons/trash_can.icon
index 70d9408..1ac9ed1 100644
--- a/chrome/app/vector_icons/trash_can.icon
+++ b/chrome/app/vector_icons/trash_can.icon
@@ -18,5 +18,4 @@
 H_LINE_TO, 3.33f,

 V_LINE_TO, 4,

 R_H_LINE_TO, 9.33f,

-CLOSE,

-END

+CLOSE

diff --git a/chrome/app/vector_icons/usb_security_key.icon b/chrome/app/vector_icons/usb_security_key.icon
index c8110ea3..35d37b0a 100644
--- a/chrome/app/vector_icons/usb_security_key.icon
+++ b/chrome/app/vector_icons/usb_security_key.icon
@@ -27,5 +27,4 @@
 R_H_LINE_TO, 1.32f,
 R_V_LINE_TO, 0.4f,
 H_LINE_TO, 1.85f,
-CLOSE,
-END
+CLOSE
diff --git a/chrome/app/vector_icons/user_account_avatar.icon b/chrome/app/vector_icons/user_account_avatar.icon
index 7a614704..006dec9a 100644
--- a/chrome/app/vector_icons/user_account_avatar.icon
+++ b/chrome/app/vector_icons/user_account_avatar.icon
@@ -20,5 +20,4 @@
 R_CUBIC_TO, 0.05f, -3.37f, 6.87f, -5.15f, 10.3f, -5.15f,
 R_CUBIC_TO, 3.42f, 0, 10.25f, 1.78f, 10.3f, 5.15f,
 R_CUBIC_TO, -2.21f, 3.06f, -6.01f, 5.15f, -10.3f, 5.15f,
-CLOSE,
-END
+CLOSE
diff --git a/chrome/app/vector_icons/user_menu_guest.icon b/chrome/app/vector_icons/user_menu_guest.icon
index e0ece26..fe0fb3f 100644
--- a/chrome/app/vector_icons/user_menu_guest.icon
+++ b/chrome/app/vector_icons/user_menu_guest.icon
@@ -34,5 +34,4 @@
 R_CUBIC_TO, -1.33f, 0, -4, 0.73f, -4, 2.07f,
 V_LINE_TO, 13,
 R_H_LINE_TO, 8,
-CLOSE,
-END
+CLOSE
diff --git a/chrome/app/vector_icons/user_menu_right_arrow.icon b/chrome/app/vector_icons/user_menu_right_arrow.icon
index be4f0d7..7ecf47a 100644
--- a/chrome/app/vector_icons/user_menu_right_arrow.icon
+++ b/chrome/app/vector_icons/user_menu_right_arrow.icon
@@ -6,6 +6,5 @@
 MOVE_TO, 8, 5,
 R_V_LINE_TO, 14,
 R_LINE_TO, 11, -7,
-CLOSE,
-END
+CLOSE
 
diff --git a/chrome/app/vector_icons/volume_up.icon b/chrome/app/vector_icons/volume_up.icon
index 89774393..8f526ba 100644
--- a/chrome/app/vector_icons/volume_up.icon
+++ b/chrome/app/vector_icons/volume_up.icon
@@ -23,5 +23,4 @@
 V_LINE_TO, 14,
 CUBIC_TO, 12.01f, 13.38f, 14, 10.93f, 14, 8,
 R_CUBIC_TO, 0, -2.93f, -1.99f, -5.38f, -4.67f, -6,
-CLOSE,
-END
+CLOSE
diff --git a/chrome/app/vector_icons/warning_badge.icon b/chrome/app/vector_icons/warning_badge.icon
index 4e4f34a..ab1cf11 100644
--- a/chrome/app/vector_icons/warning_badge.icon
+++ b/chrome/app/vector_icons/warning_badge.icon
@@ -33,5 +33,4 @@
 LINE_TO, 26, 27,
 LINE_TO, 26, 29,
 LINE_TO, 24, 29,
-CLOSE,
-END
+CLOSE
diff --git a/chrome/app/vector_icons/warning_badge_circle.1x.icon b/chrome/app/vector_icons/warning_badge_circle.1x.icon
index f1a8abc..ae8b2b3 100644
--- a/chrome/app/vector_icons/warning_badge_circle.1x.icon
+++ b/chrome/app/vector_icons/warning_badge_circle.1x.icon
@@ -19,5 +19,4 @@
 H_LINE_TO, 32,
 V_LINE_TO, 30,
 R_H_LINE_TO, 1.5f,
-CLOSE,
-END
+CLOSE
diff --git a/chrome/app/vector_icons/warning_badge_circle.icon b/chrome/app/vector_icons/warning_badge_circle.icon
index e7418ee10..c1d9f7e 100644
--- a/chrome/app/vector_icons/warning_badge_circle.icon
+++ b/chrome/app/vector_icons/warning_badge_circle.icon
@@ -19,5 +19,4 @@
 R_H_LINE_TO, -3,
 R_V_LINE_TO, -7,
 R_H_LINE_TO, 3,
-CLOSE,
-END
+CLOSE
diff --git a/chrome/app/vector_icons/web.icon b/chrome/app/vector_icons/web.icon
index 78d9b5f..497c50c 100644
--- a/chrome/app/vector_icons/web.icon
+++ b/chrome/app/vector_icons/web.icon
@@ -29,5 +29,4 @@
 V_LINE_TO, 18,
 R_H_LINE_TO, 8,
 R_V_LINE_TO, 18,
-CLOSE,
-END
+CLOSE
diff --git a/chrome/app/vector_icons/zoom_minus.icon b/chrome/app/vector_icons/zoom_minus.icon
index 04b5dd9..ce0d1ff1 100644
--- a/chrome/app/vector_icons/zoom_minus.icon
+++ b/chrome/app/vector_icons/zoom_minus.icon
@@ -28,5 +28,4 @@
 LINE_TO, 27, 18.6f,
 LINE_TO, 27, 21.4f,
 LINE_TO, 13, 21.4f,
-CLOSE,
-END
+CLOSE
diff --git a/chrome/app/vector_icons/zoom_plus.icon b/chrome/app/vector_icons/zoom_plus.icon
index 69007a3..0ee36e0 100644
--- a/chrome/app/vector_icons/zoom_plus.icon
+++ b/chrome/app/vector_icons/zoom_plus.icon
@@ -38,5 +38,4 @@
 LINE_TO, 27, 18.6f,
 LINE_TO, 27, 21.4f,
 LINE_TO, 27, 21.4f,
-CLOSE,
-END
+CLOSE
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index aeb7fc93..84750b5 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -2735,6 +2735,11 @@
      flag_descriptions::kServiceWorkerPaymentAppsDescription,
      kOsAndroid | kOsDesktop,
      FEATURE_VALUE_TYPE(features::kServiceWorkerPaymentApps)},
+    {"enable-web-payments-single-app-ui-skip",
+     flag_descriptions::kEnableWebPaymentsSingleAppUiSkipName,
+     flag_descriptions::kEnableWebPaymentsSingleAppUiSkipDescription,
+     kOsAndroid | kOsDesktop,
+     FEATURE_VALUE_TYPE(payments::features::kWebPaymentsSingleAppUiSkip)},
 #if defined(OS_ANDROID)
     {"enable-android-pay-integration-v1",
      flag_descriptions::kEnableAndroidPayIntegrationV1Name,
@@ -2749,11 +2754,6 @@
      flag_descriptions::kEnableWebPaymentsMethodSectionOrderV2Description,
      kOsAndroid,
      FEATURE_VALUE_TYPE(payments::features::kWebPaymentsMethodSectionOrderV2)},
-    {"enable-web-payments-single-app-ui-skip",
-     flag_descriptions::kEnableWebPaymentsSingleAppUiSkipName,
-     flag_descriptions::kEnableWebPaymentsSingleAppUiSkipDescription,
-     kOsAndroid,
-     FEATURE_VALUE_TYPE(chrome::android::kWebPaymentsSingleAppUiSkip)},
     {"android-payment-apps", flag_descriptions::kAndroidPaymentAppsName,
      flag_descriptions::kAndroidPaymentAppsDescription, kOsAndroid,
      FEATURE_VALUE_TYPE(chrome::android::kAndroidPaymentApps)},
diff --git a/chrome/browser/android/chrome_feature_list.cc b/chrome/browser/android/chrome_feature_list.cc
index b73969f8..6d38c98 100644
--- a/chrome/browser/android/chrome_feature_list.cc
+++ b/chrome/browser/android/chrome_feature_list.cc
@@ -130,7 +130,7 @@
     &kVrIconInDaydreamHome,
     &payments::features::kWebPaymentsMethodSectionOrderV2,
     &payments::features::kWebPaymentsModifiers,
-    &kWebPaymentsSingleAppUiSkip,
+    &payments::features::kWebPaymentsSingleAppUiSkip,
     &kWebVrAutopresentFromIntent,
     &kWebVrCardboardSupport,
     &ntp_snippets::kArticleSuggestionsExpandableHeader,
@@ -387,9 +387,6 @@
 const base::Feature kVrIconInDaydreamHome{"VrIconInDaydreamHome",
                                           base::FEATURE_ENABLED_BY_DEFAULT};
 
-const base::Feature kWebPaymentsSingleAppUiSkip{
-    "WebPaymentsSingleAppUiSkip", base::FEATURE_ENABLED_BY_DEFAULT};
-
 const base::Feature kWebVrAutopresentFromIntent{
     "WebVrAutopresentFromIntent", base::FEATURE_ENABLED_BY_DEFAULT};
 
diff --git a/chrome/browser/android/chrome_feature_list.h b/chrome/browser/android/chrome_feature_list.h
index 9f9b7f3..b877cb49 100644
--- a/chrome/browser/android/chrome_feature_list.h
+++ b/chrome/browser/android/chrome_feature_list.h
@@ -85,7 +85,6 @@
 extern const base::Feature kVrBrowsingInCustomTab;
 extern const base::Feature kVrBrowsingNativeAndroidUi;
 extern const base::Feature kVrIconInDaydreamHome;
-extern const base::Feature kWebPaymentsSingleAppUiSkip;
 extern const base::Feature kWebVrAutopresentFromIntent;
 extern const base::Feature kWebVrCardboardSupport;
 
diff --git a/chrome/browser/app_controller_mac_browsertest.mm b/chrome/browser/app_controller_mac_browsertest.mm
index 02823f79..e799df1 100644
--- a/chrome/browser/app_controller_mac_browsertest.mm
+++ b/chrome/browser/app_controller_mac_browsertest.mm
@@ -176,7 +176,10 @@
 // open then a reopen event does nothing.
 IN_PROC_BROWSER_TEST_F(AppControllerPlatformAppBrowserTest,
                        PlatformAppReopenWithWindows) {
-  base::scoped_nsobject<AppController> ac([[AppController alloc] init]);
+  AppController* ac = base::mac::ObjCCast<AppController>(
+      [[NSApplication sharedApplication] delegate]);
+  ASSERT_TRUE(ac);
+
   NSUInteger old_window_count = [[NSApp windows] count];
   EXPECT_EQ(1u, active_browser_list_->size());
   [ac applicationShouldHandleReopen:NSApp hasVisibleWindows:YES];
@@ -190,8 +193,9 @@
 
 IN_PROC_BROWSER_TEST_F(AppControllerPlatformAppBrowserTest,
                        ActivationFocusesBrowserWindow) {
-  base::scoped_nsobject<AppController> app_controller(
-      [[AppController alloc] init]);
+  AppController* app_controller = base::mac::ObjCCast<AppController>(
+      [[NSApplication sharedApplication] delegate]);
+  ASSERT_TRUE(app_controller);
 
   ExtensionTestMessageListener listener("Launched", false);
   const extensions::Extension* app =
@@ -233,7 +237,10 @@
 // Test that in web app mode a reopen event opens the app URL.
 IN_PROC_BROWSER_TEST_F(AppControllerWebAppBrowserTest,
                        WebAppReopenWithNoWindows) {
-  base::scoped_nsobject<AppController> ac([[AppController alloc] init]);
+  AppController* ac = base::mac::ObjCCast<AppController>(
+      [[NSApplication sharedApplication] delegate]);
+  ASSERT_TRUE(ac);
+
   EXPECT_EQ(1u, active_browser_list_->size());
   BOOL result = [ac applicationShouldHandleReopen:NSApp hasVisibleWindows:NO];
 
@@ -284,7 +291,10 @@
 // Test that for a regular last profile, a reopen event opens a browser.
 IN_PROC_BROWSER_TEST_F(AppControllerNewProfileManagementBrowserTest,
                        RegularProfileReopenWithNoWindows) {
-  base::scoped_nsobject<AppController> ac([[AppController alloc] init]);
+  AppController* ac = base::mac::ObjCCast<AppController>(
+      [[NSApplication sharedApplication] delegate]);
+  ASSERT_TRUE(ac);
+
   EXPECT_EQ(1u, active_browser_list_->size());
   BOOL result = [ac applicationShouldHandleReopen:NSApp hasVisibleWindows:NO];
 
@@ -300,7 +310,9 @@
   // minimize flakiness due to the scheduling/descheduling of tasks on the
   // different threads, pre-initialize the guest profile before it is needed.
   CreateAndWaitForSystemProfile();
-  base::scoped_nsobject<AppController> ac([[AppController alloc] init]);
+  AppController* ac = base::mac::ObjCCast<AppController>(
+      [[NSApplication sharedApplication] delegate]);
+  ASSERT_TRUE(ac);
 
   // Lock the active profile.
   base::ScopedAllowBlockingForTesting allow_blocking;
@@ -322,6 +334,46 @@
   UserManager::Hide();
 }
 
+// Test that for a guest last profile, commandDispatch should open UserManager
+// if guest mode is disabled. Note that this test might be flaky under ASAN
+// due to https://crbug.com/674475. Please disable this test under ASAN
+// as the tests below if that happened.
+IN_PROC_BROWSER_TEST_F(AppControllerNewProfileManagementBrowserTest,
+                       OpenGuestProfileOnlyIfGuestModeIsEnabled) {
+  CreateAndWaitForSystemProfile();
+  PrefService* local_state = g_browser_process->local_state();
+  local_state->SetString(prefs::kProfileLastUsed, chrome::kGuestProfileDir);
+  local_state->SetBoolean(prefs::kBrowserGuestModeEnabled, false);
+
+  AppController* ac = base::mac::ObjCCast<AppController>(
+      [[NSApplication sharedApplication] delegate]);
+  ASSERT_TRUE(ac);
+
+  base::ScopedAllowBlockingForTesting allow_blocking;
+  Profile* profile = [ac lastProfile];
+  EXPECT_TRUE(profile->IsGuestSession());
+
+  NSMenu* menu = [ac applicationDockMenu:NSApp];
+  ASSERT_TRUE(menu);
+  NSMenuItem* item = [menu itemWithTag:IDC_NEW_WINDOW];
+  ASSERT_TRUE(item);
+  EXPECT_EQ(1u, active_browser_list_->size());
+
+  [ac commandDispatch:item];
+
+  base::RunLoop().RunUntilIdle();
+
+  EXPECT_EQ(1u, active_browser_list_->size());
+  EXPECT_TRUE(UserManager::IsShowing());
+  UserManager::Hide();
+
+  local_state->SetBoolean(prefs::kBrowserGuestModeEnabled, true);
+  [ac commandDispatch:item];
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(2u, active_browser_list_->size());
+  EXPECT_FALSE(UserManager::IsShowing());
+}
+
 #if defined(ADDRESS_SANITIZER)
 // Flaky under ASAN. See https://crbug.com/674475.
 #define MAYBE_GuestProfileReopenWithNoWindows DISABLED_GuestProfileReopenWithNoWindows
@@ -337,7 +389,9 @@
   PrefService* local_state = g_browser_process->local_state();
   local_state->SetString(prefs::kProfileLastUsed, chrome::kGuestProfileDir);
 
-  base::scoped_nsobject<AppController> ac([[AppController alloc] init]);
+  AppController* ac = base::mac::ObjCCast<AppController>(
+      [[NSApplication sharedApplication] delegate]);
+  ASSERT_TRUE(ac);
 
   base::ScopedAllowBlockingForTesting allow_blocking;
   Profile* profile = [ac lastProfile];
@@ -363,7 +417,9 @@
 #endif
 IN_PROC_BROWSER_TEST_F(AppControllerNewProfileManagementBrowserTest,
                        MAYBE_AboutChromeForcesUserManager) {
-  base::scoped_nsobject<AppController> ac([[AppController alloc] init]);
+  AppController* ac = base::mac::ObjCCast<AppController>(
+      [[NSApplication sharedApplication] delegate]);
+  ASSERT_TRUE(ac);
 
   // Create the guest profile, and set it as the last used profile so the
   // app controller can use it on init.
@@ -577,7 +633,10 @@
 IN_PROC_BROWSER_TEST_F(AppControllerMainMenuBrowserTest,
     BookmarksMenuIsRestoredAfterProfileSwitch) {
   ProfileManager* profile_manager = g_browser_process->profile_manager();
-  base::scoped_nsobject<AppController> ac([[AppController alloc] init]);
+  AppController* ac = base::mac::ObjCCast<AppController>(
+      [[NSApplication sharedApplication] delegate]);
+  ASSERT_TRUE(ac);
+
   [ac awakeFromNib];
 
   // Constants for bookmarks that we will create later.
diff --git a/chrome/browser/background_fetch/background_fetch_browsertest.cc b/chrome/browser/background_fetch/background_fetch_browsertest.cc
index 4b22559..bfc2efb4 100644
--- a/chrome/browser/background_fetch/background_fetch_browsertest.cc
+++ b/chrome/browser/background_fetch/background_fetch_browsertest.cc
@@ -273,7 +273,9 @@
   DISALLOW_COPY_AND_ASSIGN(BackgroundFetchBrowserTest);
 };
 
-IN_PROC_BROWSER_TEST_F(BackgroundFetchBrowserTest, DownloadService_Acceptance) {
+// Flaky. See https://crbug.com/822276
+IN_PROC_BROWSER_TEST_F(BackgroundFetchBrowserTest,
+                       DISABLED_DownloadService_Acceptance) {
   // Starts a Background Fetch for a single to-be-downloaded file and waits for
   // that request to be scheduled with the Download Service.
 
@@ -321,8 +323,9 @@
   EXPECT_FALSE(offline_item.is_resumable);
 }
 
+// Flaky. See https://crbug.com/822276
 IN_PROC_BROWSER_TEST_F(BackgroundFetchBrowserTest,
-                       OfflineItemCollection_VerifyIconReceived) {
+                       DISABLED_OfflineItemCollection_VerifyIconReceived) {
   // Starts a Background Fetch for a single to-be-downloaded file and waits for
   // the fetch to be registered with the offline items collection. We then
   // verify that the expected icon is associated with the newly added offline
diff --git a/chrome/browser/background_fetch/background_fetch_download_client.cc b/chrome/browser/background_fetch/background_fetch_download_client.cc
index cf21948..f80b659 100644
--- a/chrome/browser/background_fetch/background_fetch_download_client.cc
+++ b/chrome/browser/background_fetch/background_fetch_download_client.cc
@@ -7,12 +7,14 @@
 #include <memory>
 #include <utility>
 
+#include "base/threading/sequenced_task_runner_handle.h"
 #include "chrome/browser/background_fetch/background_fetch_delegate_impl.h"
 #include "chrome/browser/download/download_service_factory.h"
 #include "components/download/public/background_service/download_metadata.h"
 #include "components/download/public/background_service/download_service.h"
 #include "content/public/browser/background_fetch_response.h"
 #include "content/public/browser/browser_context.h"
+#include "services/network/public/cpp/resource_request_body.h"
 #include "url/origin.h"
 
 BackgroundFetchDownloadClient::BackgroundFetchDownloadClient(
@@ -93,3 +95,10 @@
   // TODO(delphick): Return false if the background fetch hasn't finished yet
   return true;
 }
+
+void BackgroundFetchDownloadClient::GetUploadData(
+    const std::string& guid,
+    download::GetUploadDataCallback callback) {
+  base::SequencedTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::BindOnce(std::move(callback), nullptr));
+}
diff --git a/chrome/browser/background_fetch/background_fetch_download_client.h b/chrome/browser/background_fetch/background_fetch_download_client.h
index e7aaf09..edcfae01 100644
--- a/chrome/browser/background_fetch/background_fetch_download_client.h
+++ b/chrome/browser/background_fetch/background_fetch_download_client.h
@@ -43,6 +43,8 @@
                            const download::CompletionInfo& info) override;
   bool CanServiceRemoveDownloadedFile(const std::string& guid,
                                       bool force_delete) override;
+  void GetUploadData(const std::string& guid,
+                     download::GetUploadDataCallback callback) override;
 
   content::BrowserContext* browser_context_;
   base::WeakPtr<BackgroundFetchDelegateImpl> delegate_;
diff --git a/chrome/browser/devtools/devtools_window.cc b/chrome/browser/devtools/devtools_window.cc
index 53c6d3d..4f6c33a 100644
--- a/chrome/browser/devtools/devtools_window.cc
+++ b/chrome/browser/devtools/devtools_window.cc
@@ -22,6 +22,7 @@
 #include "chrome/browser/file_select_helper.h"
 #include "chrome/browser/infobars/infobar_service.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/sessions/session_tab_helper.h"
 #include "chrome/browser/task_manager/web_contents_tags.h"
 #include "chrome/browser/ui/browser.h"
@@ -988,6 +989,14 @@
       base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kKioskMode))
     return nullptr;
 
+#if defined(OS_CHROMEOS)
+  // Do not create DevTools if it's disabled for primary profile.
+  const Profile* primary_profile = ProfileManager::GetPrimaryUserProfile();
+  if (primary_profile &&
+      primary_profile->GetPrefs()->GetBoolean(prefs::kDevToolsDisabled))
+    return nullptr;
+#endif
+
   if (inspected_web_contents) {
     // Check for a place to dock.
     Browser* browser = nullptr;
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index a89423f..2a23cdc 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -272,6 +272,12 @@
     R"*(Validate Asm.js when "use asm" is present and then convert to )*"
     R"*(WebAssembly.)*";
 
+const char kEnableWebPaymentsSingleAppUiSkipName[] =
+    "Enable Web Payments single app UI skip";
+const char kEnableWebPaymentsSingleAppUiSkipDescription[] =
+    "Enable Web Payments to skip showing its UI if the developer specifies a "
+    "single app.";
+
 const char kEnableAutofillCreditCardAblationExperimentDisplayName[] =
     "Credit card autofill ablation experiment.";
 const char kEnableAutofillCreditCardAblationExperimentDescription[] =
@@ -2041,12 +2047,6 @@
     "Enable this option to display payment method section above address "
     "section instead of below it.";
 
-const char kEnableWebPaymentsSingleAppUiSkipName[] =
-    "Enable Web Payments single app UI skip";
-const char kEnableWebPaymentsSingleAppUiSkipDescription[] =
-    "Enable Web Payments to skip showing its UI if the developer specifies a "
-    "single app.";
-
 const char kGrantNotificationsToDSEName[] =
     "Grant notifications to the Default Search Engine";
 const char kGrantNotificationsToDSENameDescription[] =
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index d0f4663..850bc8a 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -394,6 +394,9 @@
 extern const char kEnableWasmName[];
 extern const char kEnableWasmDescription[];
 
+extern const char kEnableWebPaymentsSingleAppUiSkipName[];
+extern const char kEnableWebPaymentsSingleAppUiSkipDescription[];
+
 extern const char kEnableWebUsbName[];
 extern const char kEnableWebUsbDescription[];
 
@@ -1239,9 +1242,6 @@
 extern const char kEnableWebPaymentsMethodSectionOrderV2Name[];
 extern const char kEnableWebPaymentsMethodSectionOrderV2Description[];
 
-extern const char kEnableWebPaymentsSingleAppUiSkipName[];
-extern const char kEnableWebPaymentsSingleAppUiSkipDescription[];
-
 extern const char kGrantNotificationsToDSEName[];
 extern const char kGrantNotificationsToDSENameDescription[];
 
diff --git a/chrome/browser/media/router/discovery/mdns/cast_media_sink_service_impl.cc b/chrome/browser/media/router/discovery/mdns/cast_media_sink_service_impl.cc
index 6507292..48f85bc 100644
--- a/chrome/browser/media/router/discovery/mdns/cast_media_sink_service_impl.cc
+++ b/chrome/browser/media/router/discovery/mdns/cast_media_sink_service_impl.cc
@@ -350,6 +350,16 @@
         base::BindOnce(&CastMediaSinkServiceImpl::OpenChannel, GetWeakPtr(),
                        ip_endpoint, cast_sink_it->second, nullptr,
                        SinkSource::kConnectionRetry));
+    // We erase the sink here so that OpenChannel would not find an existing
+    // sink.
+    // Note: a better longer term solution is to introduce a state field to the
+    // sink. We would set it to ERROR here. In OpenChannel(), we would check
+    // create a socket only if the state is not already CONNECTED.
+    if (observer_)
+      observer_->OnSinkRemoved(cast_sink_it->second);
+
+    current_sinks_map_.erase(cast_sink_it);
+    MediaSinkServiceBase::RestartTimer();
     return;
   }
 
@@ -382,6 +392,9 @@
     }
     sink_cache_[last_network_id] = std::move(current_sinks);
   }
+
+  // TODO(imcheng): Maybe this should clear |current_sinks_map_| and call
+  // |RestartTimer()| so it is more responsive?
   if (IsNetworkIdUnknownOrDisconnected(network_id))
     return;
 
@@ -511,7 +524,7 @@
              << ip_endpoint.ToString() << " [error_state]: "
              << cast_channel::ChannelErrorToString(error_state);
 
-    OnChannelOpenFailed(ip_endpoint);
+    OnChannelOpenFailed(ip_endpoint, cast_sink);
     CastAnalytics::RecordCastChannelConnectResult(
         MediaRouterChannelConnectResults::FAILURE);
     return;
@@ -572,6 +585,18 @@
     sink_it->second = cast_sink;
   }
 
+  // If the sink was under a different IP address previously, remove it from
+  // |current_sinks_map_|.
+  auto old_sink_it = std::find_if(
+      current_sinks_map_.begin(), current_sinks_map_.end(),
+      [&cast_sink, &ip_endpoint](
+          const std::pair<net::IPEndPoint, MediaSinkInternal>& entry) {
+        return !(entry.first == ip_endpoint) &&
+               entry.second.sink().id() == cast_sink.sink().id();
+      });
+  if (old_sink_it != current_sinks_map_.end())
+    current_sinks_map_.erase(old_sink_it);
+
   if (observer_)
     observer_->OnSinkAddedOrUpdated(cast_sink, socket);
 
@@ -580,9 +605,14 @@
 }
 
 void CastMediaSinkServiceImpl::OnChannelOpenFailed(
-    const net::IPEndPoint& ip_endpoint) {
+    const net::IPEndPoint& ip_endpoint,
+    const MediaSinkInternal& sink) {
+  // It is possible that the old sink in |current_sinks_map_| is replaced with
+  // a new sink if a network change happened. Check the sink ID to make sure
+  // this is the sink we want to erase.
   auto it = current_sinks_map_.find(ip_endpoint);
-  if (it == current_sinks_map_.end())
+  if (it == current_sinks_map_.end() ||
+      it->second.sink().id() != sink.sink().id())
     return;
 
   if (observer_)
diff --git a/chrome/browser/media/router/discovery/mdns/cast_media_sink_service_impl.h b/chrome/browser/media/router/discovery/mdns/cast_media_sink_service_impl.h
index adb0a09..253db30 100644
--- a/chrome/browser/media/router/discovery/mdns/cast_media_sink_service_impl.h
+++ b/chrome/browser/media/router/discovery/mdns/cast_media_sink_service_impl.h
@@ -169,6 +169,10 @@
                            TestInitRetryParametersWithDefaultValue);
   FRIEND_TEST_ALL_PREFIXES(CastMediaSinkServiceImplTest,
                            TestOnDialSinkAddedSkipsIfNonCastDevice);
+  FRIEND_TEST_ALL_PREFIXES(CastMediaSinkServiceImplTest,
+                           TestOnChannelErrorRetry);
+  FRIEND_TEST_ALL_PREFIXES(CastMediaSinkServiceImplTest,
+                           OpenChannelNewIPSameSink);
 
   // Holds Finch field trial parameters controlling Cast channel retry strategy.
   struct RetryParams {
@@ -276,7 +280,7 @@
                               cast_channel::ChannelError error_state,
                               SinkSource sink_source);
 
-  // Invoked when opening cast channel on IO thread succeeds.
+  // Invoked when opening cast channel succeeds.
   // |cast_sink|: Cast sink created from mDNS service description or DIAL sink.
   // |socket|: raw pointer of newly created cast channel. Does not take
   // ownership of |socket|.
@@ -284,11 +288,12 @@
                               cast_channel::CastSocket* socket,
                               SinkSource sink_source);
 
-  // Invoked when opening cast channel on IO thread fails after all retry
+  // Invoked when opening cast channel fails after all retry
   // attempts.
   // |ip_endpoint|: ip endpoint of cast channel failing to connect to.
-  // |sink_source|: Method of sink discovery.
-  void OnChannelOpenFailed(const net::IPEndPoint& ip_endpoint);
+  // |sink|: The sink for which channel open failed.
+  void OnChannelOpenFailed(const net::IPEndPoint& ip_endpoint,
+                           const MediaSinkInternal& sink);
 
   // Returns whether the given DIAL-discovered |sink| is probably a non-Cast
   // device. This is heuristically determined by two things: |sink| has been
diff --git a/chrome/browser/media/router/discovery/mdns/cast_media_sink_service_impl_unittest.cc b/chrome/browser/media/router/discovery/mdns/cast_media_sink_service_impl_unittest.cc
index 5970f77..62bd0fc 100644
--- a/chrome/browser/media/router/discovery/mdns/cast_media_sink_service_impl_unittest.cc
+++ b/chrome/browser/media/router/discovery/mdns/cast_media_sink_service_impl_unittest.cc
@@ -403,11 +403,66 @@
   media_sink_service_impl_.OnDiscoveryComplete();
 }
 
+TEST_F(CastMediaSinkServiceImplTest, OpenChannelNewIPSameSink) {
+  MediaSinkInternal cast_sink1 = CreateCastSink(1);
+  net::IPEndPoint ip_endpoint1 = cast_sink1.cast_data().ip_endpoint;
+
+  cast_channel::MockCastSocket socket;
+  socket.set_id(1);
+
+  base::SimpleTestClock clock;
+  base::Time start_time = base::Time::Now();
+  clock.SetNow(start_time);
+  media_sink_service_impl_.SetClockForTest(&clock);
+
+  EXPECT_CALL(*mock_cast_socket_service_,
+              OpenSocketInternal(ip_endpoint1, _, _))
+      .WillRepeatedly(
+          Invoke([&](const auto& ip_endpoint1, auto* net_log, auto open_cb) {
+            std::move(open_cb).Run(&socket);
+          }));
+  std::vector<MediaSinkInternal> sinks1 = {cast_sink1};
+  media_sink_service_impl_.OpenChannels(
+      sinks1, CastMediaSinkServiceImpl::SinkSource::kMdns);
+
+  mock_time_task_runner_->FastForwardUntilNoTasksRemain();
+  EXPECT_EQ(1u, media_sink_service_impl_.current_sinks_map_.size());
+
+  // |cast_sink1| changed IP address and is discovered by mdns before it is
+  // removed from |media_sink_service_impl_| first.
+  net::IPEndPoint ip_endpoint2 = CreateIPEndPoint(2);
+  CastSinkExtraData extra_data = cast_sink1.cast_data();
+  extra_data.ip_endpoint = ip_endpoint2;
+  cast_sink1.set_cast_data(extra_data);
+
+  EXPECT_CALL(*mock_cast_socket_service_,
+              OpenSocketInternal(ip_endpoint2, _, _))
+      .WillRepeatedly(
+          Invoke([&](const auto& ip_endpoint1, auto* net_log, auto open_cb) {
+            std::move(open_cb).Run(&socket);
+          }));
+
+  std::vector<MediaSinkInternal> updated_sinks1 = {cast_sink1};
+  media_sink_service_impl_.OpenChannels(
+      updated_sinks1, CastMediaSinkServiceImpl::SinkSource::kMdns);
+
+  // The entry under old IPEndPoint is removed and replaced with new IPEndPoint.
+  mock_time_task_runner_->FastForwardUntilNoTasksRemain();
+  const auto& current_sinks_map = media_sink_service_impl_.current_sinks_map_;
+  EXPECT_EQ(1u, current_sinks_map.size());
+  auto sink_it = current_sinks_map.find(ip_endpoint2);
+  ASSERT_TRUE(sink_it != current_sinks_map.end());
+  EXPECT_EQ(cast_sink1, sink_it->second);
+}
+
 TEST_F(CastMediaSinkServiceImplTest, TestOnChannelOpenFailed) {
   auto cast_sink = CreateCastSink(1);
   net::IPEndPoint ip_endpoint1 = CreateIPEndPoint(1);
   cast_channel::MockCastSocket socket;
   socket.set_id(1);
+  socket.SetIPEndpoint(ip_endpoint1);
+
+  auto cast_sink2 = CreateCastSink(2);
 
   EXPECT_CALL(observer_, OnSinkAddedOrUpdated(cast_sink, &socket));
   media_sink_service_impl_.OnChannelOpenSucceeded(
@@ -415,12 +470,49 @@
 
   EXPECT_EQ(1u, media_sink_service_impl_.current_sinks_map_.size());
 
-  socket.SetIPEndpoint(ip_endpoint1);
+  // OnChannelOpenFailed called with mismatched sink: no-op.
+  EXPECT_CALL(observer_, OnSinkRemoved(_)).Times(0);
+  media_sink_service_impl_.OnChannelOpenFailed(ip_endpoint1, cast_sink2);
+  EXPECT_FALSE(media_sink_service_impl_.current_sinks_map_.empty());
+
   EXPECT_CALL(observer_, OnSinkRemoved(cast_sink));
-  media_sink_service_impl_.OnChannelOpenFailed(ip_endpoint1);
+  media_sink_service_impl_.OnChannelOpenFailed(ip_endpoint1, cast_sink);
   EXPECT_TRUE(media_sink_service_impl_.current_sinks_map_.empty());
 }
 
+TEST_F(CastMediaSinkServiceImplTest, TestOnChannelErrorRetry) {
+  auto cast_sink = CreateCastSink(1);
+  net::IPEndPoint ip_endpoint1 = CreateIPEndPoint(1);
+  cast_channel::MockCastSocket socket;
+  socket.set_id(1);
+  socket.SetIPEndpoint(ip_endpoint1);
+  EXPECT_CALL(socket, ready_state())
+      .WillOnce(Return(cast_channel::ReadyState::OPEN));
+
+  EXPECT_CALL(observer_, OnSinkAddedOrUpdated(cast_sink, &socket));
+  media_sink_service_impl_.OnChannelOpenSucceeded(
+      cast_sink, &socket, CastMediaSinkServiceImpl::SinkSource::kMdns);
+
+  // Sink is removed on |OnError|, but we will retry.
+  EXPECT_CALL(observer_, OnSinkRemoved(cast_sink));
+  EXPECT_CALL(*mock_cast_socket_service_,
+              OpenSocketInternal(ip_endpoint1, _, _))
+      .WillRepeatedly(
+          Invoke([&](const auto& ip_endpoint1, auto* net_log, auto open_cb) {
+            std::move(open_cb).Run(&socket);
+          }));
+  media_sink_service_impl_.OnError(socket,
+                                   cast_channel::ChannelError::PING_TIMEOUT);
+
+  EXPECT_TRUE(media_sink_service_impl_.current_sinks_map_.empty());
+
+  // Retry succeeds and sink is added back.
+  EXPECT_CALL(observer_, OnSinkAddedOrUpdated(cast_sink, &socket));
+  mock_time_task_runner_->FastForwardUntilNoTasksRemain();
+
+  EXPECT_EQ(1u, media_sink_service_impl_.current_sinks_map_.size());
+}
+
 TEST_F(CastMediaSinkServiceImplTest,
        TestOnChannelErrorMayRetryForConnectingChannel) {
   net::IPEndPoint ip_endpoint1 = CreateIPEndPoint(1);
@@ -666,8 +758,8 @@
       net::NetworkChangeNotifier::CONNECTION_WIFI);
   content::RunAllTasksUntilIdle();
   mock_time_task_runner_->FastForwardUntilNoTasksRemain();
-  media_sink_service_impl_.OnChannelOpenFailed(ip_endpoint1);
-  media_sink_service_impl_.OnChannelOpenFailed(ip_endpoint2);
+  media_sink_service_impl_.OnChannelOpenFailed(ip_endpoint1, sink1);
+  media_sink_service_impl_.OnChannelOpenFailed(ip_endpoint2, sink2);
 
   MediaSinkInternal sink3 = CreateCastSink(3);
   net::IPEndPoint ip_endpoint3 = CreateIPEndPoint(3);
@@ -738,7 +830,7 @@
       net::NetworkChangeNotifier::CONNECTION_WIFI);
   content::RunAllTasksUntilIdle();
   mock_time_task_runner_->FastForwardUntilNoTasksRemain();
-  media_sink_service_impl_.OnChannelOpenFailed(ip_endpoint1);
+  media_sink_service_impl_.OnChannelOpenFailed(ip_endpoint1, sink1);
 
   MediaSinkInternal sink3 = CreateCastSink(3);
   net::IPEndPoint ip_endpoint3 = CreateIPEndPoint(3);
@@ -791,7 +883,7 @@
   ExpectOpenSocketInternal(&socket1);
   media_sink_service_impl_.OpenChannels(
       sink_list1, CastMediaSinkServiceImpl::SinkSource::kMdns);
-  media_sink_service_impl_.OnChannelOpenFailed(ip_endpoint1);
+  media_sink_service_impl_.OnChannelOpenFailed(ip_endpoint1, sink1);
 
   // Connect to a new network with different sinks.
   fake_network_info_.clear();
@@ -872,8 +964,8 @@
       net::NetworkChangeNotifier::CONNECTION_NONE);
   content::RunAllTasksUntilIdle();
   mock_time_task_runner_->FastForwardUntilNoTasksRemain();
-  media_sink_service_impl_.OnChannelOpenFailed(ip_endpoint1);
-  media_sink_service_impl_.OnChannelOpenFailed(ip_endpoint2);
+  media_sink_service_impl_.OnChannelOpenFailed(ip_endpoint1, sink1);
+  media_sink_service_impl_.OnChannelOpenFailed(ip_endpoint2, sink2);
 
   MediaSinkInternal sink3 = CreateCastSink(3);
   net::IPEndPoint ip_endpoint3 = CreateIPEndPoint(3);
@@ -941,8 +1033,8 @@
       net::NetworkChangeNotifier::CONNECTION_WIFI);
   content::RunAllTasksUntilIdle();
   mock_time_task_runner_->FastForwardUntilNoTasksRemain();
-  media_sink_service_impl_.OnChannelOpenFailed(ip_endpoint1);
-  media_sink_service_impl_.OnChannelOpenFailed(ip_endpoint2);
+  media_sink_service_impl_.OnChannelOpenFailed(ip_endpoint1, sink1);
+  media_sink_service_impl_.OnChannelOpenFailed(ip_endpoint2, sink2);
 
   MediaSinkInternal sink3 = CreateCastSink(3);
   net::IPEndPoint ip_endpoint3 = CreateIPEndPoint(3);
@@ -963,7 +1055,7 @@
   content::RunAllTasksUntilIdle();
   mock_time_task_runner_->FastForwardUntilNoTasksRemain();
 
-  media_sink_service_impl_.OnChannelOpenFailed(ip_endpoint3);
+  media_sink_service_impl_.OnChannelOpenFailed(ip_endpoint3, sink3);
 
   // Resolution will fail for cached sinks.
   socket1.SetErrorState(cast_channel::ChannelError::CONNECT_ERROR);
@@ -994,7 +1086,7 @@
       net::NetworkChangeNotifier::CONNECTION_NONE);
   content::RunAllTasksUntilIdle();
   mock_time_task_runner_->FastForwardUntilNoTasksRemain();
-  media_sink_service_impl_.OnChannelOpenFailed(ip_endpoint4);
+  media_sink_service_impl_.OnChannelOpenFailed(ip_endpoint4, sink4);
 
   // Reconnect and expect only |sink4| to be cached.
   EXPECT_CALL(*mock_cast_socket_service_,
@@ -1034,6 +1126,12 @@
       sink_list1, CastMediaSinkServiceImpl::SinkSource::kMdns);
   media_sink_service_impl_.OnDialSinkAdded(sink2_dial);
 
+  // CastMediaSinkServiceImpl generates a Cast sink based on |sink2_dial|.
+  auto sink2_it =
+      media_sink_service_impl_.current_sinks_map_.find(ip_endpoint2);
+  ASSERT_TRUE(sink2_it != media_sink_service_impl_.current_sinks_map_.end());
+  MediaSinkInternal sink2_cast_from_dial = sink2_it->second;
+
   // Connect to a new network with different sinks.
   fake_network_info_.clear();
   net::NetworkChangeNotifier::NotifyObserversOfNetworkChangeForTests(
@@ -1046,8 +1144,9 @@
       net::NetworkChangeNotifier::CONNECTION_WIFI);
   content::RunAllTasksUntilIdle();
   mock_time_task_runner_->FastForwardUntilNoTasksRemain();
-  media_sink_service_impl_.OnChannelOpenFailed(ip_endpoint1);
-  media_sink_service_impl_.OnChannelOpenFailed(ip_endpoint2);
+  media_sink_service_impl_.OnChannelOpenFailed(ip_endpoint1, sink1_cast);
+  media_sink_service_impl_.OnChannelOpenFailed(ip_endpoint2,
+                                               sink2_cast_from_dial);
 
   MediaSinkInternal sink3_cast = CreateCastSink(3);
   MediaSinkInternal sink4_dial = CreateDialSink(4);
@@ -1134,8 +1233,8 @@
       net::NetworkChangeNotifier::CONNECTION_WIFI);
   content::RunAllTasksUntilIdle();
   mock_time_task_runner_->FastForwardUntilNoTasksRemain();
-  media_sink_service_impl_.OnChannelOpenFailed(ip_endpoint1_cast);
-  media_sink_service_impl_.OnChannelOpenFailed(ip_endpoint1_dial);
+  media_sink_service_impl_.OnChannelOpenFailed(ip_endpoint1_cast, sink1_cast);
+  media_sink_service_impl_.OnChannelOpenFailed(ip_endpoint1_dial, sink1_dial);
 
   MediaSinkInternal sink2_cast = CreateCastSink(2);
   net::IPEndPoint ip_endpoint2 = CreateIPEndPoint(2);
@@ -1197,8 +1296,8 @@
       net::NetworkChangeNotifier::CONNECTION_WIFI);
   content::RunAllTasksUntilIdle();
   mock_time_task_runner_->FastForwardUntilNoTasksRemain();
-  media_sink_service_impl_.OnChannelOpenFailed(ip_endpoint1);
-  media_sink_service_impl_.OnChannelOpenFailed(ip_endpoint2);
+  media_sink_service_impl_.OnChannelOpenFailed(ip_endpoint1, sink1);
+  media_sink_service_impl_.OnChannelOpenFailed(ip_endpoint2, sink2);
 
   MediaSinkInternal sink3 = CreateCastSink(3);
   net::IPEndPoint ip_endpoint3 = CreateIPEndPoint(3);
diff --git a/chrome/browser/media/webrtc/webrtc_event_log_manager.cc b/chrome/browser/media/webrtc/webrtc_event_log_manager.cc
index 7bf732cd..0b86f7c 100644
--- a/chrome/browser/media/webrtc/webrtc_event_log_manager.cc
+++ b/chrome/browser/media/webrtc/webrtc_event_log_manager.cc
@@ -96,6 +96,7 @@
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   if (base::FeatureList::IsEnabled(::features::kWebRtcRemoteEventLog)) {
+    VLOG(1) << "WebRTC remote-bound event logging enabled.";
     remote_logs_manager_ = std::make_unique<WebRtcRemoteEventLogManager>(this);
   }
 
diff --git a/chrome/browser/media/webrtc/webrtc_event_log_manager_remote.cc b/chrome/browser/media/webrtc/webrtc_event_log_manager_remote.cc
index 8cdf17e..c5bfce3 100644
--- a/chrome/browser/media/webrtc/webrtc_event_log_manager_remote.cc
+++ b/chrome/browser/media/webrtc/webrtc_event_log_manager_remote.cc
@@ -20,14 +20,15 @@
 #include "base/threading/sequenced_task_runner_handle.h"
 #include "content/public/browser/browser_thread.h"
 
-// TODO(eladalon): Block remote-bound logging on mobile devices.
-// https://crbug.com/775415
+// TODO(crbug.com/775415): Block remote-bound logging on mobile devices.
 
 const size_t kMaxRemoteLogFileMetadataSizeBytes = 0xffffu;  // 65535
 static_assert(kMaxRemoteLogFileMetadataSizeBytes <= 0xFFFFFFu,
               "Only 24 bits available for encoding the metadata's length.");
 
-const size_t kMaxRemoteLogFileSizeBytes = (1u << 29);  // ~500MBs
+// TODO(crbug.com/775415): Change back to (1u << 29) after resolving the issue
+// where we read the entire file into memory.
+const size_t kMaxRemoteLogFileSizeBytes = 50000000u;
 
 namespace {
 const base::FilePath::CharType kRemoteBoundLogSubDirectory[] =
@@ -95,9 +96,9 @@
 
 WebRtcRemoteEventLogManager::~WebRtcRemoteEventLogManager() {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  // TODO(eladalon): Purge from disk files which were being uploaded  while
-  // destruction took place, thereby avoiding endless attempts to upload
-  // the same file. https://crbug.com/775415
+  // TODO(crbug.com/775415): Purge from disk files which were being uploaded
+  // while destruction took place, thereby avoiding endless attempts to upload
+  // the same file.
 }
 
 void WebRtcRemoteEventLogManager::EnableForBrowserContext(
@@ -119,7 +120,7 @@
   enabled_browser_contexts_.insert(browser_context_id);
 }
 
-// TODO(eladalon): Add unit tests. https://crbug.com/775415
+// TODO(crbug.com/775415): Add unit tests.
 void WebRtcRemoteEventLogManager::DisableForBrowserContext(
     BrowserContextId browser_context_id) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(io_task_sequence_checker_);
@@ -282,9 +283,6 @@
       base::BindOnce(
           &WebRtcRemoteEventLogManager::OnWebRtcEventLogUploadCompleteInternal,
           base::Unretained(this)));
-
-  // TODO(eladalon): Send indication of success/failure back to JS.
-  // https://crbug.com/775415
 }
 
 void WebRtcRemoteEventLogManager::SetWebRtcEventLogUploaderFactoryForTesting(
@@ -344,7 +342,7 @@
     return false;
   }
 
-  // TODO(eladalon): Test for appropriate permissions. https://crbug.com/775415
+  // TODO(crbug.com/775415): Test for appropriate permissions.
 
   return true;
 }
@@ -389,7 +387,7 @@
   // Randomize a new filename. In the highly unlikely event that this filename
   // is already taken, it will be treated the same way as any other failure
   // to start the log file.
-  // TODO(eladalon): Add a unit test for above comment. https://crbug.com/775415
+  // TODO(crbug.com/775415): Add a unit test for above comment.
   const std::string unique_filename =
       "event_log_" + std::to_string(base::RandUint64());
   const base::FilePath base_path = GetLogsDirectoryPath(browser_context_dir);
@@ -531,11 +529,13 @@
 
   // The uploader takes ownership of the file; it's no longer considered to be
   // pending. (If the upload fails, the log will be deleted.)
-  // TODO(eladalon): Add more refined retry behavior, so that we would not
-  // delete the log permanently if the network is just down, on the one hand,
-  // but also would not be uploading unlimited data on endless retries on the
-  // other hand. https://crbug.com/775415
-  // TODO(eladalon): Delay the upload's start. https://crbug.com/814362
+  // TODO(crbug.com/775415): Add more refined retry behavior, so that we would
+  // not delete the log permanently if the network is just down, on the one
+  // hand, but also would not be uploading unlimited data on endless retries on
+  // the other hand.
+  // TODO(crbug.com/814362): Delay the upload's start.
+  // TODO(crbug.com/775415): Rename the file before uploading, so that we would
+  // not retry the upload after restarting Chrome, if the upload is interrupted.
   uploader_ = uploader_factory_->Create(pending_logs_.begin()->path, this);
   pending_logs_.erase(pending_logs_.begin());
 }
diff --git a/chrome/browser/media/webrtc/webrtc_event_log_uploader.cc b/chrome/browser/media/webrtc/webrtc_event_log_uploader.cc
index 8d5ea19..8d7f0bd 100644
--- a/chrome/browser/media/webrtc/webrtc_event_log_uploader.cc
+++ b/chrome/browser/media/webrtc/webrtc_event_log_uploader.cc
@@ -4,36 +4,280 @@
 
 #include "chrome/browser/media/webrtc/webrtc_event_log_uploader.h"
 
+#include "base/bind.h"
 #include "base/files/file_util.h"
 #include "base/logging.h"
+#include "base/threading/sequenced_task_runner_handle.h"
+#include "build/build_config.h"
+#include "chrome/browser/browser_process.h"
+#include "components/version_info/version_info.h"
+#include "content/public/browser/browser_thread.h"
+#include "net/base/load_flags.h"
+#include "net/base/mime_util.h"
+#include "net/http/http_status_code.h"
 
-WebRtcEventLogUploaderImpl::WebRtcEventLogUploaderImpl(
-    const base::FilePath& path,
-    WebRtcEventLogUploaderObserver* observer) {
-  DCHECK(observer);
+// Explanation about the life cycle of a WebRtcEventLogUploaderImpl object, and
+// about why its use of base::Unretained is safe:
+// * WebRtcEventLogUploaderImpl objects are owned (indirectly) by
+//   WebRtcEventLogManager, which is a singleton object that is not destroyed
+//   during Chrome shutdown, but rather, is allowed to leak.
+// * Therefore, objects of type WebRtcEventLogUploaderImpl will only be
+//   destroyed when their owner explicitly decides to do so.
+// * The direct owner, WebRtcRemoteEventLogManager, only deletes a
+//   WebRtcEventLogUploaderImpl after it receives a notification
+//   of type OnWebRtcEventLogUploadComplete.
+// * OnWebRtcEventLogUploadComplete() is only ever called as the last step,
+//   there are no tasks pending which have a reference to this object.
+// * The previous point follows from OnURLFetchComplete being guaranteed to
+//   be the last callback called on a URLFetcherDelegate.
 
-  // TODO(eladalon): Provide an actual implementation; really upload the file.
-  // https://crbug.com/775415
+namespace {
+// TODO(crbug.com/817495): Eliminate the duplication with other uploaders.
+const char kUploadContentType[] = "multipart/form-data";
+const char kBoundary[] = "----**--yradnuoBgoLtrapitluMklaTelgooG--**----";
 
-  // If the upload was successful, the file is no longer needed.
-  // If the upload failed, we don't want to retry, because we run the risk of
-  // uploading significant amounts of data once again, only for the upload to
-  // fail again after (as an example) wasting 50MBs of upload bandwidth.
-  const bool deletion_successful = base::DeleteFile(path, /*recursive=*/false);
-  if (!deletion_successful) {
-    // This is a somewhat serious (though unlikely) error, because now we'll try
-    // to upload this file again next time Chrome launches.
-    LOG(ERROR) << "Could not delete pending log file.";
-  }
+const char kLogFilename[] = "webrtc_event_log";
+const char kLogExtension[] = "log";
 
-  // TODO(eladalon): Provide actual success/failure of upload.
-  // https://crbug.com/775415
-  observer->OnWebRtcEventLogUploadComplete(path, true);
+constexpr size_t kExpectedMimeOverheadBytes = 1000;  // Intentional overshot.
+
+// TODO(crbug.com/817495): Eliminate the duplication with other uploaders.
+#if defined(OS_WIN)
+const char kProduct[] = "Chrome";
+#elif defined(OS_MACOSX)
+const char kProduct[] = "Chrome_Mac";
+#elif defined(OS_LINUX)
+const char kProduct[] = "Chrome_Linux";
+#elif defined(OS_ANDROID)
+const char kProduct[] = "Chrome_Android";
+#elif defined(OS_CHROMEOS)
+const char kProduct[] = "Chrome_ChromeOS";
+#else
+#error Platform not supported.
+#endif
+
+// TODO(crbug.com/775415): Update comment to reflect new policy when discarding
+// the command line flag.
+constexpr net::NetworkTrafficAnnotationTag kTrafficAnnotation =
+    net::DefineNetworkTrafficAnnotation("webrtc_event_log_uploader", R"(
+      semantics {
+        sender: "WebRTC Event Log uploader module"
+        description:
+          "Uploads a WebRTC event log to a server called Crash. These logs "
+          "will not contain private information. They will be used to "
+          "improve WebRTC (fix bugs, tune performance, etc.)."
+        trigger:
+          "A privileged JS application (Hangouts/Meet) has requested a peer "
+          "connection to be logged, and the resulting event log to be "
+          "uploaded at a time deemed to cause the least interference to the "
+          "user (i.e., when the user is not busy making other VoIP calls)."
+        data:
+          "WebRTC events such as the timing of audio playout (but not the "
+          "content), timing and size of RTP packets sent/received, etc."
+        destination: GOOGLE_OWNED_SERVICE
+      }
+      policy {
+        cookies_allowed: NO
+        setting: "This feature is only enabled if the user launches Chrome "
+                 "with a specific command line flag: "
+                 "--enable-features=WebRtcRemoteEventLog"
+        policy_exception_justification:
+          "Not applicable."
+      })");
+
+void AddFileContents(const std::string& file_contents,
+                     const std::string& content_type,
+                     std::string* post_data) {
+  // net::AddMultipartValueForUpload does almost what we want to do here, except
+  // that it does not add the "filename" attribute. We hack it to force it to.
+  std::string mime_value_name = base::StringPrintf(
+      "%s\"; filename=\"%s.%s\"", kLogFilename, kLogFilename, kLogExtension);
+  net::AddMultipartValueForUpload(mime_value_name, file_contents, kBoundary,
+                                  content_type, post_data);
 }
 
+std::string MimeContentType() {
+  const char kBoundaryKeywordAndMisc[] = "; boundary=";
+
+  std::string content_type;
+  content_type.reserve(sizeof(content_type) + sizeof(kBoundaryKeywordAndMisc) +
+                       sizeof(kBoundary));
+
+  content_type.append(kUploadContentType);
+  content_type.append(kBoundaryKeywordAndMisc);
+  content_type.append(kBoundary);
+
+  return content_type;
+}
+}  // namespace
+
+const char WebRtcEventLogUploaderImpl::kUploadURL[] =
+    "https://clients2.google.com/cr/report";
+
 std::unique_ptr<WebRtcEventLogUploader>
 WebRtcEventLogUploaderImpl::Factory::Create(
     const base::FilePath& log_file,
     WebRtcEventLogUploaderObserver* observer) {
-  return std::make_unique<WebRtcEventLogUploaderImpl>(log_file, observer);
+  DCHECK(observer);
+  return std::make_unique<WebRtcEventLogUploaderImpl>(
+      log_file, observer, kMaxRemoteLogFileSizeBytes);
+}
+
+std::unique_ptr<WebRtcEventLogUploader>
+WebRtcEventLogUploaderImpl::Factory::CreateWithCurstomMaxSizeForTesting(
+    const base::FilePath& log_file,
+    WebRtcEventLogUploaderObserver* observer,
+    size_t max_log_file_size_bytes) {
+  DCHECK(observer);
+  return std::make_unique<WebRtcEventLogUploaderImpl>(log_file, observer,
+                                                      max_log_file_size_bytes);
+}
+
+WebRtcEventLogUploaderImpl::Delegate::Delegate(
+    WebRtcEventLogUploaderImpl* owner)
+    : owner_(owner) {}
+
+void WebRtcEventLogUploaderImpl::Delegate::OnURLFetchComplete(
+    const net::URLFetcher* source) {
+  owner_->OnURLFetchComplete(source);
+}
+
+WebRtcEventLogUploaderImpl::WebRtcEventLogUploaderImpl(
+    const base::FilePath& log_file,
+    WebRtcEventLogUploaderObserver* observer,
+    size_t max_log_file_size_bytes)
+    : delegate_(this),
+      log_file_(log_file),
+      observer_(observer),
+      max_log_file_size_bytes_(max_log_file_size_bytes),
+      request_context_getter_(nullptr),
+      io_task_runner_(base::SequencedTaskRunnerHandle::Get()) {
+  DCHECK(observer);
+
+  if (!PrepareUploadData()) {
+    ReportResult(false);
+    return;
+  }
+
+  // See the comment at the beginning of this file for an explanation about why
+  // base::Unretained is safe to use here.
+  content::BrowserThread::PostTask(
+      content::BrowserThread::UI, FROM_HERE,
+      base::BindOnce(&WebRtcEventLogUploaderImpl::PrepareRequestContext,
+                     base::Unretained(this)));
+}
+
+WebRtcEventLogUploaderImpl::~WebRtcEventLogUploaderImpl() {
+  DCHECK(io_task_runner_->RunsTasksInCurrentSequence());
+  // WebRtcEventLogUploaderImpl objects only deleted if either:
+  // 1. The upload was never started, meaning |url_fetcher_| was never set.
+  // 2. Upload started and finished.
+  // Therefore, we can be sure that when we destroy this object, there are no
+  // tasks pending that still hold a base::Unretained() reference to it.
+  DCHECK(!url_fetcher_);
+}
+
+bool WebRtcEventLogUploaderImpl::PrepareUploadData() {
+  DCHECK(io_task_runner_->RunsTasksInCurrentSequence());
+
+  // TODO(crbug.com/775415): Avoid reading the entire file into memory.
+  std::string log_file_contents;
+  if (!base::ReadFileToStringWithMaxSize(log_file_, &log_file_contents,
+                                         max_log_file_size_bytes_)) {
+    LOG(WARNING) << "Couldn't read event log file, or max file size exceeded.";
+    return false;
+  }
+
+  DCHECK(post_data_.empty());
+  post_data_.reserve(log_file_contents.size() + kExpectedMimeOverheadBytes);
+  net::AddMultipartValueForUpload("prod", kProduct, kBoundary, "", &post_data_);
+  net::AddMultipartValueForUpload("ver",
+                                  version_info::GetVersionNumber() + "-webrtc",
+                                  kBoundary, "", &post_data_);
+  net::AddMultipartValueForUpload("guid", "0", kBoundary, "", &post_data_);
+  net::AddMultipartValueForUpload("type", kLogFilename, kBoundary, "",
+                                  &post_data_);
+  AddFileContents(log_file_contents, "application/log", &post_data_);
+  net::AddMultipartFinalDelimiterForUpload(kBoundary, &post_data_);
+
+  return true;
+}
+
+void WebRtcEventLogUploaderImpl::PrepareRequestContext() {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+  // system_request_context() can only be gotten on the UI thread, but can
+  // then be used by any thread.
+  DCHECK(!request_context_getter_);
+  request_context_getter_ = g_browser_process->system_request_context();
+  // In unit tests, request_context_getter_ will remain null.
+
+  // See the comment at the beginning of this file for an explanation about why
+  // base::Unretained is safe to use here.
+  io_task_runner_->PostTask(
+      FROM_HERE, base::BindOnce(&WebRtcEventLogUploaderImpl::StartUpload,
+                                base::Unretained(this)));
+}
+
+void WebRtcEventLogUploaderImpl::StartUpload() {
+  DCHECK(io_task_runner_->RunsTasksInCurrentSequence());
+
+  url_fetcher_ = net::URLFetcher::Create(
+      GURL(kUploadURL), net::URLFetcher::POST, &delegate_, kTrafficAnnotation);
+  url_fetcher_->SetRequestContext(request_context_getter_);
+  url_fetcher_->SetLoadFlags(net::LOAD_DO_NOT_SAVE_COOKIES |
+                             net::LOAD_DO_NOT_SEND_COOKIES);
+  url_fetcher_->SetUploadData(MimeContentType(), post_data_);
+  url_fetcher_->Start();  // Delegat::OnURLFetchComplete called when finished.
+}
+
+void WebRtcEventLogUploaderImpl::OnURLFetchComplete(
+    const net::URLFetcher* source) {
+  DCHECK(io_task_runner_->RunsTasksInCurrentSequence());
+  DCHECK_EQ(source, url_fetcher_.get());
+
+  const bool upload_successful =
+      (source->GetStatus().status() == net::URLRequestStatus::SUCCESS &&
+       source->GetResponseCode() == net::HTTP_OK);
+
+  if (upload_successful) {
+    // TODO(crbug.com/775415): Update chrome://webrtc-logs.
+    std::string report_id;
+    if (!url_fetcher_->GetResponseAsString(&report_id)) {
+      LOG(WARNING) << "WebRTC event log completed, but report ID unknown.";
+    } else {
+      // TODO(crbug.com/775415): Remove this when chrome://webrtc-logs updated.
+      VLOG(1) << "WebRTC event log successfully uploaded: " << report_id;
+    }
+  } else {
+    LOG(WARNING) << "WebRTC event log upload failed.";
+  }
+
+  ReportResult(upload_successful);
+
+  url_fetcher_.reset();  // Explicitly maintain determinant.
+}
+
+void WebRtcEventLogUploaderImpl::ReportResult(bool result) {
+  DCHECK(io_task_runner_->RunsTasksInCurrentSequence());
+
+  // If the upload was successful, the file is no longer needed.
+  // If the upload failed, we don't want to retry, because we run the risk of
+  // uploading significant amounts of data once again, only for the upload to
+  // fail again after (as an example) wasting 50MBs of upload bandwidth.
+  // TODO(crbug.com/775415): Provide refined retrial behavior.
+  DeleteLogFile();
+
+  observer_->OnWebRtcEventLogUploadComplete(log_file_, result);
+}
+
+void WebRtcEventLogUploaderImpl::DeleteLogFile() {
+  DCHECK(io_task_runner_->RunsTasksInCurrentSequence());
+  const bool deletion_successful =
+      base::DeleteFile(log_file_, /*recursive=*/false);
+  if (!deletion_successful) {
+    // This is a somewhat serious (though unlikely) error, because now we'll
+    // try to upload this file again next time Chrome launches.
+    LOG(ERROR) << "Could not delete pending WebRTC event log file.";
+  }
 }
diff --git a/chrome/browser/media/webrtc/webrtc_event_log_uploader.h b/chrome/browser/media/webrtc/webrtc_event_log_uploader.h
index 0fbc946..5fe67041 100644
--- a/chrome/browser/media/webrtc/webrtc_event_log_uploader.h
+++ b/chrome/browser/media/webrtc/webrtc_event_log_uploader.h
@@ -6,14 +6,23 @@
 #define CHROME_BROWSER_MEDIA_WEBRTC_WEBRTC_EVENT_LOG_UPLOADER_H_
 
 #include <memory>
+#include <string>
 
 #include "base/files/file_path.h"
+#include "base/sequenced_task_runner.h"
+#include "chrome/browser/media/webrtc/webrtc_event_log_manager_common.h"
+#include "net/url_request/url_fetcher.h"
+#include "net/url_request/url_fetcher_delegate.h"
+
+namespace net {
+class URLRequestContextGetter;
+}  // namespace net
 
 // A class implementing this interace can register for notification of an
 // upload's eventual result (success/failure).
 class WebRtcEventLogUploaderObserver {
  public:
-  virtual void OnWebRtcEventLogUploadComplete(const base::FilePath& file_path,
+  virtual void OnWebRtcEventLogUploadComplete(const base::FilePath& log_file,
                                               bool upload_successful) = 0;
 
  protected:
@@ -27,8 +36,6 @@
 // of the upload.
 class WebRtcEventLogUploader {
  public:
-  virtual ~WebRtcEventLogUploader() = default;
-
   // Since we'll need more than one instance of the abstract
   // WebRtcEventLogUploader, we'll need an abstract factory for it.
   class Factory {
@@ -39,18 +46,20 @@
     // rather than be memorized by the factory's constructor, because factories
     // created by unit tests have no visibility into the real implementation's
     // observer (WebRtcRemoteEventLogManager).
+    // This takes ownership of the file. The caller must not attempt to access
+    // the file after invoking Create().
     virtual std::unique_ptr<WebRtcEventLogUploader> Create(
         const base::FilePath& log_file,
         WebRtcEventLogUploaderObserver* observer) = 0;
   };
+
+  virtual ~WebRtcEventLogUploader() = default;
 };
 
+// Primary implementation of WebRtcEventLogUploader. Uploads log files to crash.
+// Deletes log files whether they were successfully uploaded or not.
 class WebRtcEventLogUploaderImpl : public WebRtcEventLogUploader {
  public:
-  WebRtcEventLogUploaderImpl(const base::FilePath& path,
-                             WebRtcEventLogUploaderObserver* observer);
-  ~WebRtcEventLogUploaderImpl() override = default;
-
   class Factory : public WebRtcEventLogUploader::Factory {
    public:
     ~Factory() override = default;
@@ -58,7 +67,90 @@
     std::unique_ptr<WebRtcEventLogUploader> Create(
         const base::FilePath& log_file,
         WebRtcEventLogUploaderObserver* observer) override;
+
+   protected:
+    friend class WebRtcEventLogUploaderImplTest;
+
+    std::unique_ptr<WebRtcEventLogUploader> CreateWithCurstomMaxSizeForTesting(
+        const base::FilePath& log_file,
+        WebRtcEventLogUploaderObserver* observer,
+        size_t max_remote_log_file_size_bytes);
   };
+
+  WebRtcEventLogUploaderImpl(const base::FilePath& log_file,
+                             WebRtcEventLogUploaderObserver* observer,
+                             size_t max_remote_log_file_size_bytes);
+  ~WebRtcEventLogUploaderImpl() override;
+
+ protected:
+  friend class WebRtcEventLogUploaderImplTest;
+
+  // Prepare the data that will be uploaded. Runs on io_task_runner_.
+  bool PrepareUploadData();
+
+  // Prepares the URLRequestContextGetter. This has to run on the UI thread,
+  // but once complete, the URLRequestContextGetter it produces, which is
+  // stored in request_context_getter_, may be used on any task context.
+  void PrepareRequestContext();
+
+  // Initiates the upload. Runs on io_task_runner_, so that the callback will
+  // also be called on io_task_runner_.
+  void StartUpload();
+
+  // Called on io_task_runner_.  Before this is called, other methods of the
+  // URLFetcherDelegate API may be called, but this is guaranteed to be the
+  // last call, so deleting |this| is permissible afterwards.
+  void OnURLFetchComplete(const net::URLFetcher* source);
+
+  // Cleanup and reporting to |observer_|.
+  void ReportResult(bool result);
+
+  // Remove the log file which is owned by |this|.
+  void DeleteLogFile();
+
+  // Allows testing the behavior for excessively large files.
+  void SetMaxRemoteLogFileSizeBytesForTesting(size_t max_size_bytes);
+
+  // The URL used for uploading the logs.
+  static const char kUploadURL[];
+
+ private:
+  class Delegate : public net::URLFetcherDelegate {
+   public:
+    explicit Delegate(WebRtcEventLogUploaderImpl* owner);
+    ~Delegate() override = default;
+
+    // net::URLFetcherDelegate implementation.
+    void OnURLFetchComplete(const net::URLFetcher* source) override;
+
+   private:
+    WebRtcEventLogUploaderImpl* const owner_;
+  } delegate_;
+
+  // The path to the WebRTC event log file that this uploader is in charge of.
+  const base::FilePath log_file_;
+
+  // The observer to be notified when this upload succeeds or fails.
+  WebRtcEventLogUploaderObserver* const observer_;
+
+  // Maximum allowed file size. In production code, this is a hard-coded,
+  // but unit tests may set other values.
+  const size_t max_log_file_size_bytes_;
+
+  // This is written to on the UI thread, but used on the IO thread. It allows
+  // the creation of URLFetcher objects.
+  net::URLRequestContextGetter* request_context_getter_;
+
+  // This object is in charge of the actual upload.
+  std::unique_ptr<net::URLFetcher> url_fetcher_;
+
+  // To avoid an unnecessary hop to the UI thread when something is amiss with
+  // the data we wish to upload, PrepareUploadData() is called first, and saves
+  // the data here. When back from the UI thread, StartUpload will read this.
+  std::string post_data_;
+
+  // The object lives on this IO-capable task runner.
+  scoped_refptr<base::SequencedTaskRunner> io_task_runner_;
 };
 
 #endif  // CHROME_BROWSER_MEDIA_WEBRTC_WEBRTC_EVENT_LOG_UPLOADER_H_
diff --git a/chrome/browser/media/webrtc/webrtc_event_log_uploader_impl_unittest.cc b/chrome/browser/media/webrtc/webrtc_event_log_uploader_impl_unittest.cc
new file mode 100644
index 0000000..4351f56
--- /dev/null
+++ b/chrome/browser/media/webrtc/webrtc_event_log_uploader_impl_unittest.cc
@@ -0,0 +1,236 @@
+// Copyright (c) 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/media/webrtc/webrtc_event_log_uploader.h"
+
+#include <memory>
+#include <string>
+
+#include "base/callback_forward.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/run_loop.h"
+#include "base/sequenced_task_runner.h"
+#include "base/task_scheduler/post_task.h"
+#include "build/build_config.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "net/http/http_status_code.h"
+#include "net/url_request/test_url_fetcher_factory.h"
+#include "net/url_request/url_request_status.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using ::testing::StrictMock;
+
+namespace {
+class MockWebRtcEventLogUploaderObserver
+    : public WebRtcEventLogUploaderObserver {
+ public:
+  explicit MockWebRtcEventLogUploaderObserver(
+      base::OnceClosure completion_closure)
+      : completion_closure_(std::move(completion_closure)) {}
+
+  ~MockWebRtcEventLogUploaderObserver() override = default;
+
+  // Combines the mock functionality via a helper (CompletionCallback), as well
+  // as calls the completion closure.
+  void OnWebRtcEventLogUploadComplete(const base::FilePath& log_file,
+                                      bool upload_successful) {
+    CompletionCallback(log_file, upload_successful);
+    std::move(completion_closure_).Run();
+  }
+
+  MOCK_METHOD2(CompletionCallback, void(const base::FilePath&, bool));
+
+ private:
+  base::OnceClosure completion_closure_;
+};
+
+#if defined(OS_POSIX) && !defined(OS_FUCHSIA)
+void RemovePermissions(const base::FilePath& path, int removed_permissions) {
+  int permissions;
+  ASSERT_TRUE(base::GetPosixFilePermissions(path, &permissions));
+  permissions &= ~removed_permissions;
+  ASSERT_TRUE(base::SetPosixFilePermissions(path, permissions));
+}
+
+void RemoveReadPermissions(const base::FilePath& path) {
+  constexpr int read_permissions = base::FILE_PERMISSION_READ_BY_USER |
+                                   base::FILE_PERMISSION_READ_BY_GROUP |
+                                   base::FILE_PERMISSION_READ_BY_OTHERS;
+  RemovePermissions(path, read_permissions);
+}
+
+void RemoveWritePermissions(const base::FilePath& path) {
+  constexpr int write_permissions = base::FILE_PERMISSION_WRITE_BY_USER |
+                                    base::FILE_PERMISSION_WRITE_BY_GROUP |
+                                    base::FILE_PERMISSION_WRITE_BY_OTHERS;
+  RemovePermissions(path, write_permissions);
+}
+#endif  // defined(OS_POSIX) && !defined(OS_FUCHSIA)
+}  // namespace
+
+class WebRtcEventLogUploaderImplTest : public ::testing::Test {
+ public:
+  WebRtcEventLogUploaderImplTest()
+      : observer_run_loop_(),
+        url_fetcher_factory_(nullptr),
+        observer_(observer_run_loop_.QuitWhenIdleClosure()),
+        task_runner_(base::CreateSequencedTaskRunnerWithTraits(
+            {base::MayBlock(), base::TaskPriority::BACKGROUND,
+             base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN})) {}
+  ~WebRtcEventLogUploaderImplTest() override = default;
+
+  void SetUp() override {
+    ASSERT_TRUE(log_dir_.CreateUniqueTempDir());
+    ASSERT_TRUE(base::CreateTemporaryFileInDir(log_dir_.GetPath(), &log_file_));
+    constexpr size_t kLogFileSizeBytes = 100u;
+    const std::string file_contents(kLogFileSizeBytes, 'A');
+    ASSERT_EQ(
+        base::WriteFile(log_file_, file_contents.c_str(), file_contents.size()),
+        static_cast<int>(file_contents.size()));
+  }
+
+  void TearDown() override {
+    base::RunLoop tear_down_run_loop;
+    task_runner_->PostTask(
+        FROM_HERE,
+        base::BindOnce(
+            [](WebRtcEventLogUploaderImplTest* test,
+               base::OnceClosure quit_closure) {
+              test->uploader_.reset();
+              std::move(quit_closure).Run();
+            },
+            base::Unretained(this), tear_down_run_loop.QuitWhenIdleClosure()));
+    tear_down_run_loop.Run();
+  }
+
+  void SetUrlFetcherResponse(net::HttpStatusCode http_code,
+                             net::URLRequestStatus::Status request_status) {
+    const std::string kResponseId = "ec1ed029734b8f7e";  // Arbitrary.
+    url_fetcher_factory_.SetFakeResponse(
+        GURL(WebRtcEventLogUploaderImpl::kUploadURL), kResponseId, http_code,
+        request_status);
+  }
+
+  void StartAndWaitForUpload() {
+    task_runner_->PostTask(
+        FROM_HERE, base::BindOnce(
+                       [](WebRtcEventLogUploaderImplTest* test) {
+                         test->uploader_ = test->uploader_factory_.Create(
+                             test->log_file_, &test->observer_);
+                       },
+                       base::Unretained(this)));
+    observer_run_loop_.Run();  // Observer was given quit-closure by ctor.
+  }
+
+  void StartAndWaitForUploadWithCustomMaxSize(size_t max_log_size_bytes) {
+    task_runner_->PostTask(
+        FROM_HERE,
+        base::BindOnce(
+            [](WebRtcEventLogUploaderImplTest* test,
+               size_t max_log_size_bytes) {
+              test->uploader_ =
+                  test->uploader_factory_.CreateWithCurstomMaxSizeForTesting(
+                      test->log_file_, &test->observer_, max_log_size_bytes);
+            },
+            base::Unretained(this), max_log_size_bytes));
+    observer_run_loop_.Run();  // Observer was given quit-closure by ctor.
+  }
+
+  content::TestBrowserThreadBundle test_browser_thread_bundle_;
+  base::RunLoop observer_run_loop_;
+
+  base::ScopedTempDir log_dir_;
+  base::FilePath log_file_;
+
+  net::FakeURLFetcherFactory url_fetcher_factory_;
+
+  StrictMock<MockWebRtcEventLogUploaderObserver> observer_;
+
+  // These (uploader-factory and uploader) are the units under test.
+  WebRtcEventLogUploaderImpl::Factory uploader_factory_;
+  std::unique_ptr<WebRtcEventLogUploader> uploader_;
+
+  scoped_refptr<base::SequencedTaskRunner> task_runner_;
+};
+
+TEST_F(WebRtcEventLogUploaderImplTest, SuccessfulUploadReportedToObserver) {
+  // Main test.
+  SetUrlFetcherResponse(net::HTTP_OK, net::URLRequestStatus::SUCCESS);
+  EXPECT_CALL(observer_, CompletionCallback(log_file_, true)).Times(1);
+  StartAndWaitForUpload();
+  EXPECT_FALSE(base::PathExists(log_file_));
+}
+
+// Version #1 - request reported as successful, but got an error (404) as the
+// HTTP return code.
+// Due to the simplicitly of both tests, this also tests the scenario
+// FileDeletedAfterUnsuccessfulUpload, rather than giving each its own test.
+TEST_F(WebRtcEventLogUploaderImplTest, UnsuccessfulUploadReportedToObserver1) {
+  SetUrlFetcherResponse(net::HTTP_NOT_FOUND, net::URLRequestStatus::SUCCESS);
+  EXPECT_CALL(observer_, CompletionCallback(log_file_, false)).Times(1);
+  StartAndWaitForUpload();
+  EXPECT_FALSE(base::PathExists(log_file_));
+}
+
+// Version #2 - request reported as failed; HTTP return code ignored, even
+// if it's a purported success.
+TEST_F(WebRtcEventLogUploaderImplTest, UnsuccessfulUploadReportedToObserver2) {
+  SetUrlFetcherResponse(net::HTTP_OK, net::URLRequestStatus::FAILED);
+  EXPECT_CALL(observer_, CompletionCallback(log_file_, false)).Times(1);
+  StartAndWaitForUpload();
+  EXPECT_FALSE(base::PathExists(log_file_));
+}
+
+#if defined(OS_POSIX) && !defined(OS_FUCHSIA)
+TEST_F(WebRtcEventLogUploaderImplTest, FailureToReadFileReportedToObserver) {
+  // Show the failure was independent of the URLFetcher's primed return value.
+  SetUrlFetcherResponse(net::HTTP_OK, net::URLRequestStatus::SUCCESS);
+
+  RemoveReadPermissions(log_file_);
+  EXPECT_CALL(observer_, CompletionCallback(log_file_, false)).Times(1);
+  StartAndWaitForUpload();
+}
+
+TEST_F(WebRtcEventLogUploaderImplTest, FailureToDeleteFileHandledGracefully) {
+  // Prepare for end of test cleanup.
+  int permissions;
+  ASSERT_TRUE(base::GetPosixFilePermissions(log_dir_.GetPath(), &permissions));
+
+  // The uploader won't be able to delete the file, but it would be able to
+  // read and upload it.
+  RemoveWritePermissions(log_dir_.GetPath());
+  SetUrlFetcherResponse(net::HTTP_OK, net::URLRequestStatus::SUCCESS);
+  EXPECT_CALL(observer_, CompletionCallback(log_file_, true)).Times(1);
+  StartAndWaitForUpload();
+
+  // Sanity over the test itself - the file really could not be deleted.
+  ASSERT_TRUE(base::PathExists(log_file_));
+
+  // Cleaup
+  ASSERT_TRUE(base::SetPosixFilePermissions(log_dir_.GetPath(), permissions));
+}
+#endif  // defined(OS_POSIX) && !defined(OS_FUCHSIA)
+
+TEST_F(WebRtcEventLogUploaderImplTest, FilesUpToMaxSizeUploaded) {
+  int64_t log_file_size_bytes;
+  ASSERT_TRUE(base::GetFileSize(log_file_, &log_file_size_bytes));
+
+  SetUrlFetcherResponse(net::HTTP_OK, net::URLRequestStatus::SUCCESS);
+  EXPECT_CALL(observer_, CompletionCallback(log_file_, true)).Times(1);
+  StartAndWaitForUploadWithCustomMaxSize(log_file_size_bytes);
+  EXPECT_FALSE(base::PathExists(log_file_));
+}
+
+TEST_F(WebRtcEventLogUploaderImplTest, ExcessivelyLargeFilesNotUploaded) {
+  int64_t log_file_size_bytes;
+  ASSERT_TRUE(base::GetFileSize(log_file_, &log_file_size_bytes));
+
+  SetUrlFetcherResponse(net::HTTP_OK, net::URLRequestStatus::SUCCESS);
+  EXPECT_CALL(observer_, CompletionCallback(log_file_, false)).Times(1);
+  StartAndWaitForUploadWithCustomMaxSize(log_file_size_bytes - 1);
+  EXPECT_FALSE(base::PathExists(log_file_));
+}
diff --git a/chrome/browser/notifications/notification_platform_bridge_win.cc b/chrome/browser/notifications/notification_platform_bridge_win.cc
index 6d848b1..dc0265893 100644
--- a/chrome/browser/notifications/notification_platform_bridge_win.cc
+++ b/chrome/browser/notifications/notification_platform_bridge_win.cc
@@ -739,19 +739,18 @@
 }
 
 // static
-bool NotificationPlatformBridgeWin::HandleActivation() {
+bool NotificationPlatformBridgeWin::HandleActivation(
+    const base::CommandLine& command_line) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
-  base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
-  std::string launch_id_str =
-      command_line->GetSwitchValueASCII(switches::kNotificationLaunchId);
-  NotificationLaunchId launch_id(launch_id_str);
+  NotificationLaunchId launch_id(
+      command_line.GetSwitchValueASCII(switches::kNotificationLaunchId));
   if (!launch_id.is_valid())
     return false;
 
   base::Optional<base::string16> reply;
   base::string16 inline_reply =
-      command_line->GetSwitchValueNative(switches::kNotificationInlineReply);
+      command_line.GetSwitchValueNative(switches::kNotificationInlineReply);
   if (!inline_reply.empty())
     reply = inline_reply;
 
diff --git a/chrome/browser/notifications/notification_platform_bridge_win.h b/chrome/browser/notifications/notification_platform_bridge_win.h
index 9c3a5f9..876f491 100644
--- a/chrome/browser/notifications/notification_platform_bridge_win.h
+++ b/chrome/browser/notifications/notification_platform_bridge_win.h
@@ -14,6 +14,10 @@
 #include "base/sequenced_task_runner.h"
 #include "chrome/browser/notifications/notification_platform_bridge.h"
 
+namespace base {
+class CommandLine;
+}
+
 class NotificationPlatformBridgeWinImpl;
 class NotificationTemplateBuilder;
 
@@ -38,9 +42,11 @@
       const GetDisplayedNotificationsCallback& callback) const override;
   void SetReadyCallback(NotificationBridgeReadyCallback callback) override;
 
-  // Handles notification activation from the notification_helper process.
-  // Returns false if the launch id, passed via the command line, is invalid.
-  static bool HandleActivation();
+  // Handles notification activation encoded in |command_line| from the
+  // notification_helper process.
+  // Returns false if |command_line| does not contain a valid
+  // notification-launch-id switch.
+  static bool HandleActivation(const base::CommandLine& command_line);
 
   // Extracts the profile ID from |launch_id_str|.
   static std::string GetProfileIdFromLaunchId(const std::string& launch_id_str);
diff --git a/chrome/browser/offline_pages/android/downloads/offline_page_download_bridge.cc b/chrome/browser/offline_pages/android/downloads/offline_page_download_bridge.cc
index 70e46d3..c501da3 100644
--- a/chrome/browser/offline_pages/android/downloads/offline_page_download_bridge.cc
+++ b/chrome/browser/offline_pages/android/downloads/offline_page_download_bridge.cc
@@ -8,6 +8,7 @@
 
 #include "base/android/jni_string.h"
 #include "base/bind.h"
+#include "base/bind_helpers.h"
 #include "base/guid.h"
 #include "base/logging.h"
 #include "base/memory/ptr_util.h"
@@ -107,10 +108,6 @@
   return tab->web_contents();
 }
 
-void SavePageLaterCallback(AddRequestResult result) {
-  // do nothing.
-}
-
 void SavePageIfNotNavigatedAway(const GURL& url,
                                 const GURL& original_url,
                                 const ScopedJavaGlobalRef<jobject>& j_tab_ref,
@@ -147,8 +144,8 @@
           RequestCoordinator::RequestAvailability::DISABLED_FOR_OFFLINER;
       params.original_url = original_url;
       params.request_origin = origin;
-      request_id = request_coordinator->SavePageLater(
-          params, base::Bind(&SavePageLaterCallback));
+      request_id =
+          request_coordinator->SavePageLater(params, base::DoNothing());
     } else {
       DVLOG(1) << "SavePageIfNotNavigatedAway has no valid coordinator.";
     }
diff --git a/chrome/browser/offline_pages/offline_page_tab_helper.cc b/chrome/browser/offline_pages/offline_page_tab_helper.cc
index 4be14cc..501e5af 100644
--- a/chrome/browser/offline_pages/offline_page_tab_helper.cc
+++ b/chrome/browser/offline_pages/offline_page_tab_helper.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/offline_pages/offline_page_tab_helper.h"
 
 #include "base/bind.h"
+#include "base/bind_helpers.h"
 #include "base/guid.h"
 #include "base/logging.h"
 #include "base/memory/ptr_util.h"
@@ -41,10 +42,6 @@
 #endif
   return url.SchemeIsFile();
 }
-
-void SavePageLaterCallback(AddRequestResult result) {
-  // do nothing.
-}
 }  // namespace
 
 OfflinePageTabHelper::LoadedOfflinePageInfo::LoadedOfflinePageInfo()
@@ -388,8 +385,7 @@
   params.url = url;
   params.client_id = offline_pages::ClientId(name_space, base::GenerateGUID());
   params.request_origin = request_origin;
-  request_coordinator->SavePageLater(params,
-                                     base::Bind(&SavePageLaterCallback));
+  request_coordinator->SavePageLater(params, base::DoNothing());
 
   if (static_cast<int>(ui_action) &
       static_cast<int>(OfflinePageUtils::DownloadUIActionFlags::
diff --git a/chrome/browser/offline_pages/prefetch/offline_prefetch_download_client.cc b/chrome/browser/offline_pages/prefetch/offline_prefetch_download_client.cc
index b40b3d8a..581e35a 100644
--- a/chrome/browser/offline_pages/prefetch/offline_prefetch_download_client.cc
+++ b/chrome/browser/offline_pages/prefetch/offline_prefetch_download_client.cc
@@ -9,11 +9,13 @@
 #include <utility>
 
 #include "base/logging.h"
+#include "base/threading/sequenced_task_runner_handle.h"
 #include "chrome/browser/download/download_service_factory.h"
 #include "chrome/browser/offline_pages/prefetch/prefetch_service_factory.h"
 #include "components/download/public/background_service/download_metadata.h"
 #include "components/offline_pages/core/prefetch/prefetch_downloader.h"
 #include "components/offline_pages/core/prefetch/prefetch_service.h"
+#include "services/network/public/cpp/resource_request_body.h"
 
 namespace offline_pages {
 
@@ -99,6 +101,13 @@
   return true;
 }
 
+void OfflinePrefetchDownloadClient::GetUploadData(
+    const std::string& guid,
+    download::GetUploadDataCallback callback) {
+  base::SequencedTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::BindOnce(std::move(callback), nullptr));
+}
+
 PrefetchDownloader* OfflinePrefetchDownloadClient::GetPrefetchDownloader()
     const {
   PrefetchService* prefetch_service =
diff --git a/chrome/browser/offline_pages/prefetch/offline_prefetch_download_client.h b/chrome/browser/offline_pages/prefetch/offline_prefetch_download_client.h
index 2ba25d9..2f439c8 100644
--- a/chrome/browser/offline_pages/prefetch/offline_prefetch_download_client.h
+++ b/chrome/browser/offline_pages/prefetch/offline_prefetch_download_client.h
@@ -45,6 +45,8 @@
       const download::CompletionInfo& completion_info) override;
   bool CanServiceRemoveDownloadedFile(const std::string& guid,
                                       bool force_delete) override;
+  void GetUploadData(const std::string& guid,
+                     download::GetUploadDataCallback callback) override;
 
   PrefetchDownloader* GetPrefetchDownloader() const;
 
diff --git a/chrome/browser/password_manager/password_manager_test_base.h b/chrome/browser/password_manager/password_manager_test_base.h
index 3e8d25b..99deff3 100644
--- a/chrome/browser/password_manager/password_manager_test_base.h
+++ b/chrome/browser/password_manager/password_manager_test_base.h
@@ -11,6 +11,7 @@
 #include "base/run_loop.h"
 #include "chrome/browser/ssl/cert_verifier_browser_test.h"
 #include "chrome/test/base/in_process_browser_test.h"
+#include "chrome/test/views/scoped_macviews_browser_mode.h"
 #include "components/password_manager/core/browser/password_store_consumer.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
@@ -208,6 +209,7 @@
   net::EmbeddedTestServer& https_test_server() { return https_test_server_; }
 
  private:
+  test::ScopedMacViewsBrowserMode views_mode_{true};
   net::EmbeddedTestServer https_test_server_;
   // A tab with some hooks injected.
   content::WebContents* web_contents_;
diff --git a/chrome/browser/payments/chrome_payment_request_delegate.cc b/chrome/browser/payments/chrome_payment_request_delegate.cc
index 2b3262a..54f2c34 100644
--- a/chrome/browser/payments/chrome_payment_request_delegate.cc
+++ b/chrome/browser/payments/chrome_payment_request_delegate.cc
@@ -26,6 +26,7 @@
 #include "components/autofill/core/browser/region_data_loader_impl.h"
 #include "components/keyed_service/core/service_access_type.h"
 #include "components/payments/content/payment_manifest_web_data_service.h"
+#include "components/payments/content/payment_request.h"
 #include "components/payments/content/payment_request_dialog.h"
 #include "components/payments/core/payment_prefs.h"
 #include "components/signin/core/browser/signin_manager.h"
@@ -53,31 +54,35 @@
 
 ChromePaymentRequestDelegate::ChromePaymentRequestDelegate(
     content::WebContents* web_contents)
-    : dialog_(nullptr), web_contents_(web_contents) {}
+    : shown_dialog_(nullptr), web_contents_(web_contents) {}
 
 ChromePaymentRequestDelegate::~ChromePaymentRequestDelegate() {}
 
 void ChromePaymentRequestDelegate::ShowDialog(PaymentRequest* request) {
-  DCHECK_EQ(nullptr, dialog_);
-  dialog_ = chrome::CreatePaymentRequestDialog(request);
-  dialog_->ShowDialog();
+  DCHECK_EQ(nullptr, shown_dialog_);
+  hidden_dialog_ = std::unique_ptr<PaymentRequestDialog>(
+      chrome::CreatePaymentRequestDialog(request));
+  MaybeShowHiddenDialog(request);
 }
 
 void ChromePaymentRequestDelegate::CloseDialog() {
-  if (dialog_) {
-    dialog_->CloseDialog();
-    dialog_ = nullptr;
+  if (shown_dialog_) {
+    shown_dialog_->CloseDialog();
+    shown_dialog_ = nullptr;
   }
+
+  if (hidden_dialog_)
+    hidden_dialog_.reset();
 }
 
 void ChromePaymentRequestDelegate::ShowErrorMessage() {
-  if (dialog_)
-    dialog_->ShowErrorMessage();
+  if (shown_dialog_)
+    shown_dialog_->ShowErrorMessage();
 }
 
 void ChromePaymentRequestDelegate::ShowProcessingSpinner() {
-  if (dialog_)
-    dialog_->ShowProcessingSpinner();
+  if (shown_dialog_)
+    shown_dialog_->ShowProcessingSpinner();
 }
 
 autofill::PersonalDataManager*
@@ -111,7 +116,9 @@
     const autofill::CreditCard& credit_card,
     base::WeakPtr<autofill::payments::FullCardRequest::ResultDelegate>
         result_delegate) {
-  dialog_->ShowCvcUnmaskPrompt(credit_card, result_delegate, web_contents_);
+  if (shown_dialog_)
+    shown_dialog_->ShowCvcUnmaskPrompt(credit_card, result_delegate,
+                                       web_contents_);
 }
 
 autofill::RegionDataLoader*
@@ -171,10 +178,26 @@
 void ChromePaymentRequestDelegate::EmbedPaymentHandlerWindow(
     const GURL& url,
     PaymentHandlerOpenWindowCallback callback) {
-  if (dialog_)
-    dialog_->ShowPaymentHandlerScreen(url, std::move(callback));
-  else
-    std::move(callback).Run(false, 0, 0);
+  if (hidden_dialog_) {
+    shown_dialog_ = hidden_dialog_.release();
+    shown_dialog_->ShowDialogAtPaymentHandlerSheet(url, std::move(callback));
+  } else if (shown_dialog_) {
+    shown_dialog_->ShowPaymentHandlerScreen(url, std::move(callback));
+  } else {
+    std::move(callback).Run(/*success=*/false,
+                            /*render_process_id=*/0,
+                            /*render_frame_id=*/0);
+  }
+}
+
+void ChromePaymentRequestDelegate::MaybeShowHiddenDialog(
+    PaymentRequest* request) {
+  if (request->SatisfiesSkipUIConstraints()) {
+    request->Pay();
+  } else {
+    shown_dialog_ = hidden_dialog_.release();
+    shown_dialog_->ShowDialog();
+  }
 }
 
 }  // namespace payments
diff --git a/chrome/browser/payments/chrome_payment_request_delegate.h b/chrome/browser/payments/chrome_payment_request_delegate.h
index 6157bcc..761c1c6 100644
--- a/chrome/browser/payments/chrome_payment_request_delegate.h
+++ b/chrome/browser/payments/chrome_payment_request_delegate.h
@@ -54,8 +54,24 @@
  protected:
   // Reference to the dialog so that we can satisfy calls to CloseDialog(). This
   // reference is invalid once CloseDialog() has been called on it, because the
-  // dialog will be destroyed. Protected for testing.
-  PaymentRequestDialog* dialog_;
+  // dialog will be destroyed. Owned by the views:: dialog machinery. Protected
+  // for testing.
+  PaymentRequestDialog* shown_dialog_;
+
+  // The instance of the dialog that was created but not shown yet. Since it
+  // hasn't been shown, it's still owned by it's creator. This is non null only
+  // when the current Payment Request supports skipping the payment sheet (see
+  // PaymentRequest::SatisfiesSkipUIConstraints) and is reset once the
+  // underlying pointer becomes owned by the views:: machinery (when the dialog
+  // is shown).
+  std::unique_ptr<PaymentRequestDialog> hidden_dialog_;
+
+  // Shows |hidden_dialog_| if the current Payment Request doesn't support the
+  // skip UI flow. This also transfer its ownership to the views dialog code and
+  // keep a reference to it in |shown_dialog_|.
+  // Otherwise, this calls Pay() on the current Payment Request to allow the
+  // skip UI flow to carry on.
+  void MaybeShowHiddenDialog(PaymentRequest* request);
 
  private:
   // Not owned but outlives the PaymentRequest object that owns this.
diff --git a/chrome/browser/predictors/preconnect_manager.cc b/chrome/browser/predictors/preconnect_manager.cc
index 298d0f0..bf278c2 100644
--- a/chrome/browser/predictors/preconnect_manager.cc
+++ b/chrome/browser/predictors/preconnect_manager.cc
@@ -6,11 +6,14 @@
 
 #include <utility>
 
+#include "base/trace_event/trace_event.h"
 #include "chrome/browser/predictors/resource_prefetch_predictor.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/resource_hints.h"
 #include "net/base/net_errors.h"
 #include "net/http/transport_security_state.h"
+#include "net/proxy_resolution/proxy_info.h"
+#include "net/proxy_resolution/proxy_resolution_service.h"
 #include "net/url_request/url_request_context.h"
 
 namespace predictors {
@@ -160,9 +163,16 @@
     PreresolveInfo* info = job.info;
 
     if (!info || !info->was_canceled) {
-      int status = PreresolveUrl(
-          job.url, base::Bind(&PreconnectManager::OnPreresolveFinished,
-                              weak_factory_.GetWeakPtr(), job));
+      int status;
+      if (WouldLikelyProxyURL(job.url)) {
+        // Skip preresolve and go straight to preconnect if a proxy is enabled.
+        status = net::OK;
+      } else {
+        status = PreresolveUrl(
+            job.url, base::Bind(&PreconnectManager::OnPreresolveFinished,
+                                weak_factory_.GetWeakPtr(), job));
+      }
+
       if (status == net::ERR_IO_PENDING) {
         // Will complete asynchronously.
         if (info)
@@ -243,4 +253,17 @@
   return url.ReplaceComponents(replacements);
 }
 
+bool PreconnectManager::WouldLikelyProxyURL(const GURL& url) const {
+  auto* proxy_resolution_service =
+      context_getter_->GetURLRequestContext()->proxy_resolution_service();
+  if (!proxy_resolution_service)
+    return false;
+
+  net::ProxyInfo info;
+  bool synchronous_success =
+      proxy_resolution_service->TryResolveProxySynchronously(
+          url, std::string(), &info, nullptr, net::NetLogWithSource());
+  return synchronous_success && !info.is_direct();
+}
+
 }  // namespace predictors
diff --git a/chrome/browser/predictors/preconnect_manager.h b/chrome/browser/predictors/preconnect_manager.h
index e7cbb2b..1d80e6d 100644
--- a/chrome/browser/predictors/preconnect_manager.h
+++ b/chrome/browser/predictors/preconnect_manager.h
@@ -141,6 +141,7 @@
   void FinishPreresolve(const PreresolveJob& job, bool found, bool cached);
   void AllPreresolvesForUrlFinished(PreresolveInfo* info);
   GURL GetHSTSRedirect(const GURL& url) const;
+  bool WouldLikelyProxyURL(const GURL& url) const;
 
   base::WeakPtr<Delegate> delegate_;
   scoped_refptr<net::URLRequestContextGetter> context_getter_;
diff --git a/chrome/browser/predictors/preconnect_manager_unittest.cc b/chrome/browser/predictors/preconnect_manager_unittest.cc
index d25f720..a9eddddd 100644
--- a/chrome/browser/predictors/preconnect_manager_unittest.cc
+++ b/chrome/browser/predictors/preconnect_manager_unittest.cc
@@ -14,6 +14,9 @@
 #include "base/threading/thread_task_runner_handle.h"
 #include "chrome/browser/predictors/resource_prefetch_predictor.h"
 #include "content/public/test/test_browser_thread_bundle.h"
+#include "net/proxy_resolution/mock_proxy_resolver.h"
+#include "net/proxy_resolution/proxy_config.h"
+#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
 #include "net/url_request/url_request_test_util.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -332,4 +335,46 @@
   base::RunLoop().RunUntilIdle();
 }
 
+class MockProxyConfigService : public net::ProxyConfigService {
+ public:
+  explicit MockProxyConfigService(const net::ProxyConfig& config)
+      : config_(net::ProxyConfigWithAnnotation(config,
+                                               TRAFFIC_ANNOTATION_FOR_TESTS)) {}
+  void AddObserver(Observer* observer) override {}
+  void RemoveObserver(Observer* observer) override {}
+  ConfigAvailability GetLatestProxyConfig(
+      net::ProxyConfigWithAnnotation* results) override {
+    *results = config_;
+    return CONFIG_VALID;
+  }
+
+ private:
+  net::ProxyConfigWithAnnotation config_;
+};
+
+// Tests that the predictor doesn't preresolve in the presence of the proxy
+// server.
+TEST_F(PreconnectManagerTest, TestPreresolveSkippedIfProxyEnabled) {
+  net::ProxyConfig proxy_config;
+  proxy_config.proxy_rules().ParseFromString("foopy:8080");
+  proxy_config.set_auto_detect(false);
+  net::ProxyResolutionService proxy_service(
+      std::make_unique<MockProxyConfigService>(proxy_config),
+      std::make_unique<net::MockAsyncProxyResolverFactory>(false), nullptr);
+  context_getter_->GetURLRequestContext()->set_proxy_resolution_service(
+      &proxy_service);
+
+  GURL main_frame_url("http://google.com");
+  GURL url_to_preconnect("http://cdn.google.com");
+  GURL url_to_preresolve("http://images.google.com");
+
+  EXPECT_CALL(*preconnect_manager_,
+              PreconnectUrl(url_to_preconnect, main_frame_url, 1, true));
+  EXPECT_CALL(*mock_delegate_, PreconnectFinishedProxy(main_frame_url));
+  preconnect_manager_->Start(main_frame_url,
+                             {PreconnectRequest(url_to_preconnect, 1),
+                              PreconnectRequest(url_to_preresolve, 0)});
+  base::RunLoop().RunUntilIdle();
+}
+
 }  // namespace predictors
diff --git a/chrome/browser/ui/browser_focus_uitest.cc b/chrome/browser/ui/browser_focus_uitest.cc
index 57f714e..0080f7f 100644
--- a/chrome/browser/ui/browser_focus_uitest.cc
+++ b/chrome/browser/ui/browser_focus_uitest.cc
@@ -33,6 +33,7 @@
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/interactive_test_utils.h"
 #include "chrome/test/base/ui_test_utils.h"
+#include "chrome/test/views/scoped_macviews_browser_mode.h"
 #include "components/omnibox/browser/autocomplete_match_type.h"
 #include "components/omnibox/browser/omnibox_edit_controller.h"
 #include "components/omnibox/browser/omnibox_edit_model.h"
@@ -166,6 +167,9 @@
       }
     }
   }
+
+ private:
+  test::ScopedMacViewsBrowserMode views_mode_{true};
 };
 
 // A test interstitial page with typical HTML contents.
@@ -275,7 +279,7 @@
     { false, true, false, true, false }
   };
 
-  for (int i = 1; i < 3; i++) {
+  for (int i = 0; i < 3; i++) {
     for (int j = 0; j < 5; j++) {
       // Activate the tab.
       browser()->tab_strip_model()->ActivateTabAt(j, true);
diff --git a/chrome/browser/ui/cocoa/extensions/browser_action_test_util_views_cocoa.mm b/chrome/browser/ui/cocoa/extensions/browser_action_test_util_views_cocoa.mm
index bb2101a..c56c265 100644
--- a/chrome/browser/ui/cocoa/extensions/browser_action_test_util_views_cocoa.mm
+++ b/chrome/browser/ui/cocoa/extensions/browser_action_test_util_views_cocoa.mm
@@ -215,6 +215,7 @@
   std::unique_ptr<BrowserActionTestUtil> CreateOverflowBar() override;
   gfx::Size GetMinPopupSize() override;
   gfx::Size GetMaxPopupSize() override;
+  bool CanBeResized() override;
 
  private:
   friend class BrowserActionTestUtil;
@@ -334,6 +335,12 @@
   return GetExtensionPopupTestManager()->GetMaxPopupSize();
 }
 
+bool BrowserActionTestUtilCocoa::CanBeResized() {
+  BrowserActionsContainerView* containerView =
+      [GetController(browser_, test_helper_.get()) containerView];
+  return [containerView canBeResized];
+}
+
 BrowserActionTestUtilCocoa::BrowserActionTestUtilCocoa(
     Browser* browser,
     BrowserActionTestUtilCocoa* main_bar)
diff --git a/chrome/browser/ui/cocoa/extensions/browser_actions_container_view.h b/chrome/browser/ui/cocoa/extensions/browser_actions_container_view.h
index 2890c9a..a673e4d 100644
--- a/chrome/browser/ui/cocoa/extensions/browser_actions_container_view.h
+++ b/chrome/browser/ui/cocoa/extensions/browser_actions_container_view.h
@@ -106,6 +106,9 @@
 // Stops any animation in progress.
 - (void)stopAnimation;
 
+// Returns true if this view is currently resizable.
+- (BOOL)canBeResized;
+
 @property(nonatomic) CGFloat minWidth;
 @property(nonatomic) CGFloat maxWidth;
 @property(nonatomic) BOOL grippyPinned;
diff --git a/chrome/browser/ui/cocoa/extensions/browser_actions_container_view.mm b/chrome/browser/ui/cocoa/extensions/browser_actions_container_view.mm
index 251d337..a72edbc 100644
--- a/chrome/browser/ui/cocoa/extensions/browser_actions_container_view.mm
+++ b/chrome/browser/ui/cocoa/extensions/browser_actions_container_view.mm
@@ -140,7 +140,7 @@
   if (highlight || highlight_) {
     highlight_ = std::move(highlight);
     // We don't allow resizing when the container is highlighting.
-    resizable_ = highlight.get() == nullptr;
+    resizable_ = highlight_.get() == nullptr;
     [self setNeedsDisplay:YES];
   }
 }
@@ -302,6 +302,10 @@
     [resizeAnimation_ stopAnimation];
 }
 
+- (BOOL)canBeResized {
+  return resizable_;
+}
+
 #pragma mark -
 #pragma mark Private Methods
 
diff --git a/chrome/browser/ui/extensions/browser_action_test_util.h b/chrome/browser/ui/extensions/browser_action_test_util.h
index 00c051c..f392ed8 100644
--- a/chrome/browser/ui/extensions/browser_action_test_util.h
+++ b/chrome/browser/ui/extensions/browser_action_test_util.h
@@ -104,6 +104,9 @@
   // Returns the maximum allowed size of an extension popup.
   virtual gfx::Size GetMaxPopupSize() = 0;
 
+  // Returns whether the browser action container can currently be resized.
+  virtual bool CanBeResized() = 0;
+
  protected:
   BrowserActionTestUtil() {}
 
diff --git a/chrome/browser/ui/startup/startup_browser_creator_impl.cc b/chrome/browser/ui/startup/startup_browser_creator_impl.cc
index 9a9a46ff..47258dd 100644
--- a/chrome/browser/ui/startup/startup_browser_creator_impl.cc
+++ b/chrome/browser/ui/startup/startup_browser_creator_impl.cc
@@ -399,7 +399,7 @@
   // Launch() call is from notification_helper.exe to process toast activation.
   // Delegate to the notification system; do not open a browser window here.
   if (command_line_.HasSwitch(switches::kNotificationLaunchId)) {
-    if (NotificationPlatformBridgeWin::HandleActivation()) {
+    if (NotificationPlatformBridgeWin::HandleActivation(command_line_)) {
       RecordLaunchModeHistogram(LM_WIN_PLATFORM_NOTIFICATION);
       return true;
     }
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 7bc0fefc..5187060 100644
--- a/chrome/browser/ui/views/find_bar_views_interactive_uitest.cc
+++ b/chrome/browser/ui/views/find_bar_views_interactive_uitest.cc
@@ -19,6 +19,7 @@
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/interactive_test_utils.h"
 #include "chrome/test/base/ui_test_utils.h"
+#include "chrome/test/views/scoped_macviews_browser_mode.h"
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/web_contents.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
@@ -86,6 +87,8 @@
   }
 
  private:
+  test::ScopedMacViewsBrowserMode views_mode_{true};
+
   DISALLOW_COPY_AND_ASSIGN(FindInPageTest);
 };
 
diff --git a/chrome/browser/ui/views/location_bar/star_view_browsertest.cc b/chrome/browser/ui/views/location_bar/star_view_browsertest.cc
index f38b1a2..483e975d 100644
--- a/chrome/browser/ui/views/location_bar/star_view_browsertest.cc
+++ b/chrome/browser/ui/views/location_bar/star_view_browsertest.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/ui/views/location_bar/star_view.h"
 
 #include "base/command_line.h"
+#include "base/macros.h"
 #include "base/run_loop.h"
 #include "base/strings/utf_string_conversions.h"
 #include "build/build_config.h"
@@ -16,6 +17,7 @@
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/interactive_test_utils.h"
 #include "chrome/test/base/ui_test_utils.h"
+#include "chrome/test/views/scoped_macviews_browser_mode.h"
 #include "components/prefs/pref_service.h"
 #include "content/public/test/browser_test_utils.h"
 #include "content/public/test/test_utils.h"
@@ -30,7 +32,16 @@
 
 namespace {
 
-typedef InProcessBrowserTest StarViewTest;
+class StarViewTest : public InProcessBrowserTest {
+ public:
+  StarViewTest() = default;
+  ~StarViewTest() override = default;
+
+ private:
+  test::ScopedMacViewsBrowserMode views_mode_{true};
+
+  DISALLOW_COPY_AND_ASSIGN(StarViewTest);
+};
 
 // Verify that clicking the bookmark star a second time hides the bookmark
 // bubble.
diff --git a/chrome/browser/ui/views/omnibox/omnibox_result_view.cc b/chrome/browser/ui/views/omnibox/omnibox_result_view.cc
index 7fa59e6..2a1e15d53 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_result_view.cc
+++ b/chrome/browser/ui/views/omnibox/omnibox_result_view.cc
@@ -127,6 +127,14 @@
 }  // namespace
 
 ////////////////////////////////////////////////////////////////////////////////
+// OmniboxResultView:
+
+class OmniboxImageView : public views::ImageView {
+ public:
+  bool CanProcessEventsWithinSubtree() const override { return false; }
+};
+
+////////////////////////////////////////////////////////////////////////////////
 // OmniboxResultView, public:
 
 OmniboxResultView::OmniboxResultView(OmniboxPopupContentsView* model,
@@ -139,9 +147,9 @@
           font_list.GetHeight(),
           font_list.DeriveWithWeight(gfx::Font::Weight::BOLD).GetHeight())),
       animation_(new gfx::SlideAnimation(this)),
-      icon_view_(AddImageView()),
-      image_view_(AddImageView()),
-      keyword_icon_view_(AddImageView()),
+      icon_view_(AddOmniboxImageView()),
+      image_view_(AddOmniboxImageView()),
+      keyword_icon_view_(AddOmniboxImageView()),
       content_view_(AddOmniboxTextView(font_list)),
       description_view_(AddOmniboxTextView(font_list)),
       keyword_content_view_(AddOmniboxTextView(font_list)),
@@ -183,9 +191,7 @@
   match_ = match.GetMatchWithContentsAndDescriptionPossiblySwapped();
   animation_->Reset();
   is_hovered_ = false;
-  icon_view_->SetImage(GetIcon().ToImageSkia());
   image_view_->SetVisible(false);  // Until SetAnswerImage is called.
-
   keyword_icon_view_->SetVisible(match_.associated_keyword.get());
   if (tab_switch_button_) {
     if (match.type == AutocompleteMatchType::TAB_SEARCH &&
@@ -220,6 +226,16 @@
     SetBackground(CreateBackgroundWithColor(color));
   }
 
+  // Recreate the icons in case the color needs to change.
+  // Note: if this is an extension icon or favicon then this can be done in
+  //       SetMatch() once (rather than repeatedly, as happens here). There may
+  //       be an optimization opportunity here.
+  // TODO(dschuyler): determine whether to optimize the color changes.
+  icon_view_->SetImage(GetIcon().ToImageSkia());
+  keyword_icon_view_->SetImage(gfx::CreateVectorIcon(
+      omnibox::kKeywordSearchIcon, GetLayoutConstant(LOCATION_BAR_ICON_SIZE),
+      GetVectorIconColor()));
+
   if (match_.answer) {
     content_view_->SetText(match_.answer->first_line());
     description_view_->SetText(match_.answer->second_line());
@@ -390,8 +406,8 @@
 ////////////////////////////////////////////////////////////////////////////////
 // OmniboxResultView, private:
 
-views::ImageView* OmniboxResultView::AddImageView() {
-  views::ImageView* view = new views::ImageView();
+OmniboxImageView* OmniboxResultView::AddOmniboxImageView() {
+  OmniboxImageView* view = new OmniboxImageView();
   AddChildView(view);
   return view;
 }
diff --git a/chrome/browser/ui/views/omnibox/omnibox_result_view.h b/chrome/browser/ui/views/omnibox/omnibox_result_view.h
index 001b7de..555b260 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_result_view.h
+++ b/chrome/browser/ui/views/omnibox/omnibox_result_view.h
@@ -29,6 +29,7 @@
 class Image;
 }
 
+class OmniboxImageView;
 class OmniboxTabSwitchButton;
 class OmniboxTextView;
 
@@ -97,7 +98,7 @@
 
  private:
   // Create instance and add it as a child.
-  views::ImageView* AddImageView();
+  OmniboxImageView* AddOmniboxImageView();
   OmniboxTextView* AddOmniboxTextView(const gfx::FontList& font_list);
 
   // Returns the height of the text portion of the result view.
diff --git a/chrome/browser/ui/views/omnibox/omnibox_text_view.cc b/chrome/browser/ui/views/omnibox/omnibox_text_view.cc
index be49242e..15fbecba 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_text_view.cc
+++ b/chrome/browser/ui/views/omnibox/omnibox_text_view.cc
@@ -121,6 +121,10 @@
   return render_text_->GetStringSize();
 }
 
+bool OmniboxTextView::CanProcessEventsWithinSubtree() const {
+  return false;
+}
+
 const char* OmniboxTextView::GetClassName() const {
   return "OmniboxTextView";
 }
diff --git a/chrome/browser/ui/views/omnibox/omnibox_text_view.h b/chrome/browser/ui/views/omnibox/omnibox_text_view.h
index 743c76c..5c62fa4 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_text_view.h
+++ b/chrome/browser/ui/views/omnibox/omnibox_text_view.h
@@ -32,6 +32,7 @@
 
   // views::View.
   gfx::Size CalculatePreferredSize() const override;
+  bool CanProcessEventsWithinSubtree() const override;
   const char* GetClassName() const override;
   int GetHeightForWidth(int width) const override;
   void OnPaint(gfx::Canvas* canvas) override;
diff --git a/chrome/browser/ui/views/omnibox/omnibox_view_views_browsertest.cc b/chrome/browser/ui/views/omnibox/omnibox_view_views_browsertest.cc
index 418f3a8..c53283df 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_view_views_browsertest.cc
+++ b/chrome/browser/ui/views/omnibox/omnibox_view_views_browsertest.cc
@@ -22,6 +22,7 @@
 #include "chrome/grit/generated_resources.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/interactive_test_utils.h"
+#include "chrome/test/views/scoped_macviews_browser_mode.h"
 #include "components/omnibox/browser/omnibox_popup_model.h"
 #include "components/omnibox/browser/test_scheme_classifier.h"
 #include "content/public/browser/web_contents.h"
@@ -116,6 +117,8 @@
     ASSERT_TRUE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_OMNIBOX));
   }
 
+  test::ScopedMacViewsBrowserMode views_mode_{true};
+
   DISALLOW_COPY_AND_ASSIGN(OmniboxViewViewsTest);
 };
 
diff --git a/chrome/browser/ui/views/passwords/password_bubble_interactive_uitest.cc b/chrome/browser/ui/views/passwords/password_bubble_interactive_uitest.cc
index b7dc50a..263c596 100644
--- a/chrome/browser/ui/views/passwords/password_bubble_interactive_uitest.cc
+++ b/chrome/browser/ui/views/passwords/password_bubble_interactive_uitest.cc
@@ -25,6 +25,7 @@
 #include "chrome/browser/ui/views/toolbar/toolbar_view.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/test/base/interactive_test_utils.h"
+#include "chrome/test/views/scoped_macviews_browser_mode.h"
 #include "content/public/browser/notification_types.h"
 #include "content/public/browser/render_view_host.h"
 #include "content/public/common/content_features.h"
@@ -93,6 +94,7 @@
   }
 
  private:
+  test::ScopedMacViewsBrowserMode views_mode_{true};
   base::test::ScopedFeatureList scoped_feature_list_;
 
   DISALLOW_COPY_AND_ASSIGN(PasswordBubbleInteractiveUiTest);
diff --git a/chrome/browser/ui/views/payments/payment_request_dialog_view.cc b/chrome/browser/ui/views/payments/payment_request_dialog_view.cc
index a75b083ab..e02a940 100644
--- a/chrome/browser/ui/views/payments/payment_request_dialog_view.cc
+++ b/chrome/browser/ui/views/payments/payment_request_dialog_view.cc
@@ -141,6 +141,19 @@
   constrained_window::ShowWebModalDialogViews(this, request_->web_contents());
 }
 
+void PaymentRequestDialogView::ShowDialogAtPaymentHandlerSheet(
+    const GURL& url,
+    PaymentHandlerOpenWindowCallback callback) {
+  view_stack_->Push(CreateViewAndInstallController(
+                        std::make_unique<PaymentHandlerWebFlowViewController>(
+                            request_->spec(), request_->state(), this,
+                            GetProfile(), url, std::move(callback)),
+                        &controller_map_),
+                    /* animate = */ false);
+  HideProcessingSpinner();
+  ShowDialog();
+}
+
 void PaymentRequestDialogView::CloseDialog() {
   // This calls PaymentRequestDialogView::Cancel() before closing.
   // ViewHierarchyChanged() also gets called after Cancel().
diff --git a/chrome/browser/ui/views/payments/payment_request_dialog_view.h b/chrome/browser/ui/views/payments/payment_request_dialog_view.h
index 652570d..6037b176 100644
--- a/chrome/browser/ui/views/payments/payment_request_dialog_view.h
+++ b/chrome/browser/ui/views/payments/payment_request_dialog_view.h
@@ -106,6 +106,9 @@
 
   // payments::PaymentRequestDialog:
   void ShowDialog() override;
+  void ShowDialogAtPaymentHandlerSheet(
+      const GURL& url,
+      PaymentHandlerOpenWindowCallback callback) override;
   void CloseDialog() override;
   void ShowErrorMessage() override;
   void ShowProcessingSpinner() override;
diff --git a/chrome/browser/ui/views/payments/payment_request_payment_app_browsertest.cc b/chrome/browser/ui/views/payments/payment_request_payment_app_browsertest.cc
index 7f203003..f1c400c1 100644
--- a/chrome/browser/ui/views/payments/payment_request_payment_app_browsertest.cc
+++ b/chrome/browser/ui/views/payments/payment_request_payment_app_browsertest.cc
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include "base/macros.h"
+#include "base/test/scoped_feature_list.h"
 #include "chrome/browser/content_settings/host_content_settings_map_factory.h"
 #include "chrome/browser/permissions/permission_request_manager.h"
 #include "chrome/browser/ui/browser.h"
@@ -11,9 +12,11 @@
 #include "chrome/browser/ui/views/payments/payment_request_dialog_view_ids.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/ui_test_utils.h"
+#include "components/autofill/core/browser/autofill_test_utils.h"
 #include "components/content_settings/core/browser/host_content_settings_map.h"
 #include "components/network_session_configurator/common/network_switches.h"
 #include "components/payments/content/service_worker_payment_app_factory.h"
+#include "components/payments/core/features.h"
 #include "components/payments/core/test_payment_manifest_downloader.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/storage_partition.h"
@@ -33,7 +36,7 @@
         bobpay_(net::EmbeddedTestServer::TYPE_HTTPS),
         frankpay_(net::EmbeddedTestServer::TYPE_HTTPS) {
     scoped_feature_list_.InitAndEnableFeature(
-        features::kServiceWorkerPaymentApps);
+        ::features::kServiceWorkerPaymentApps);
   }
 
   PermissionRequestManager* GetPermissionRequestManager() {
@@ -73,6 +76,26 @@
         << contents;
   }
 
+  // Invokes the JavaScript function install(|method_name|) in
+  // components/test/data/payments/bobpay.com/app1/index.js, which responds
+  // back via domAutomationController.
+  void InstallBobPayForMethod(const std::string& method_name) {
+    ui_test_utils::NavigateToURL(browser(),
+                                 bobpay_.GetURL("bobpay.com", "/app1/"));
+
+    std::string contents;
+    std::string script = "install('" + method_name + "');";
+    ASSERT_TRUE(content::ExecuteScriptAndExtractString(
+        browser()->tab_strip_model()->GetActiveWebContents(), script,
+        &contents))
+        << "Script execution failed: " << script;
+    ASSERT_NE(std::string::npos,
+              contents.find("Payment app for \"" + method_name +
+                            "\" method installed."))
+        << method_name << " method install message not found in:\n"
+        << contents;
+  }
+
   void BlockAlicePay() {
     GURL origin = alicepay_.GetURL("alicepay.com", "/app1/").GetOrigin();
     HostContentSettingsMapFactory::GetForProfile(browser()->profile())
@@ -366,4 +389,99 @@
   }
 }
 
+IN_PROC_BROWSER_TEST_F(PaymentRequestPaymentAppTest, SkipUIEnabledWithBobPay) {
+  base::test::ScopedFeatureList features;
+  features.InitWithFeatures(
+      {
+          payments::features::kWebPaymentsSingleAppUiSkip,
+          ::features::kServiceWorkerPaymentApps,
+      },
+      {});
+  InstallBobPayForMethod("https://bobpay.com");
+
+  {
+    SetDownloaderAndIgnorePortInAppScopeForTesting();
+
+    NavigateTo("/payment_request_bobpay_ui_skip_test.html");
+
+    // Since the skip UI flow is available, the request will complete without
+    // interaction besides hitting "pay" on the website.
+    ResetEventWaiterForSequence(
+        {DialogEvent::DIALOG_OPENED, DialogEvent::DIALOG_CLOSED});
+    content::WebContents* web_contents = GetActiveWebContents();
+    const std::string click_buy_button_js =
+        "(function() { document.getElementById('buy').click(); })();";
+    ASSERT_TRUE(content::ExecuteScript(web_contents, click_buy_button_js));
+    WaitForObservedEvent();
+
+    ExpectBodyContains({"bobpay.com"});
+  }
+}
+
+IN_PROC_BROWSER_TEST_F(PaymentRequestPaymentAppTest,
+                       SkipUIDisabledWithMultipleAcceptedMethods) {
+  base::test::ScopedFeatureList features;
+  features.InitWithFeatures(
+      {
+          payments::features::kWebPaymentsSingleAppUiSkip,
+          ::features::kServiceWorkerPaymentApps,
+      },
+      {});
+  InstallBobPayForMethod("https://bobpay.com");
+
+  {
+    SetDownloaderAndIgnorePortInAppScopeForTesting();
+
+    NavigateTo("/payment_request_bobpay_test.html");
+
+    // Since the skip UI flow is not available, the request will complete only
+    // after clicking on the Pay button in the dialog.
+    InvokePaymentRequestUI();
+
+    ResetEventWaiterForSequence(
+        {DialogEvent::PROCESSING_SPINNER_SHOWN, DialogEvent::DIALOG_CLOSED});
+    ClickOnDialogViewAndWait(DialogViewID::PAY_BUTTON, dialog_view());
+
+    ExpectBodyContains({"bobpay.com"});
+  }
+}
+
+IN_PROC_BROWSER_TEST_F(PaymentRequestPaymentAppTest,
+                       SkipUIDisabledWithRequestedPayerEmail) {
+  base::test::ScopedFeatureList features;
+  features.InitWithFeatures(
+      {
+          payments::features::kWebPaymentsSingleAppUiSkip,
+          ::features::kServiceWorkerPaymentApps,
+      },
+      {});
+  InstallBobPayForMethod("https://bobpay.com");
+  autofill::AutofillProfile profile(autofill::test::GetFullProfile());
+  AddAutofillProfile(profile);
+
+  {
+    SetDownloaderAndIgnorePortInAppScopeForTesting();
+
+    NavigateTo("/payment_request_bobpay_ui_skip_test.html");
+
+    // Since the skip UI flow is not available because the payer's email is
+    // requested, the request will complete only after clicking on the Pay
+    // button in the dialog.
+    ResetEventWaiter(DialogEvent::DIALOG_OPENED);
+    content::WebContents* web_contents = GetActiveWebContents();
+    const std::string click_buy_button_js =
+        "(function() { "
+        "document.getElementById('buyWithRequestedEmail').click(); })();";
+    ASSERT_TRUE(content::ExecuteScript(web_contents, click_buy_button_js));
+    WaitForObservedEvent();
+    EXPECT_TRUE(IsPayButtonEnabled());
+
+    ResetEventWaiterForSequence(
+        {DialogEvent::PROCESSING_SPINNER_SHOWN, DialogEvent::DIALOG_CLOSED});
+    ClickOnDialogViewAndWait(DialogViewID::PAY_BUTTON, dialog_view());
+
+    ExpectBodyContains({"bobpay.com"});
+  }
+}
+
 }  // namespace payments
diff --git a/chrome/browser/ui/views/payments/test_chrome_payment_request_delegate.cc b/chrome/browser/ui/views/payments/test_chrome_payment_request_delegate.cc
index a503560..97d498d8 100644
--- a/chrome/browser/ui/views/payments/test_chrome_payment_request_delegate.cc
+++ b/chrome/browser/ui/views/payments/test_chrome_payment_request_delegate.cc
@@ -22,10 +22,9 @@
       is_browser_window_active_(is_browser_window_active) {}
 
 void TestChromePaymentRequestDelegate::ShowDialog(PaymentRequest* request) {
-  PaymentRequestDialogView* dialog_view =
-      new PaymentRequestDialogView(request, observer_);
-  dialog_view->ShowDialog();
-  dialog_ = dialog_view;
+  hidden_dialog_ =
+      std::make_unique<PaymentRequestDialogView>(request, observer_);
+  MaybeShowHiddenDialog(request);
 }
 
 bool TestChromePaymentRequestDelegate::IsIncognito() const {
diff --git a/chrome/browser/ui/views/payments/test_chrome_payment_request_delegate.h b/chrome/browser/ui/views/payments/test_chrome_payment_request_delegate.h
index e0d5eaa..4208c5f 100644
--- a/chrome/browser/ui/views/payments/test_chrome_payment_request_delegate.h
+++ b/chrome/browser/ui/views/payments/test_chrome_payment_request_delegate.h
@@ -41,7 +41,7 @@
   bool IsBrowserWindowActive() const override;
 
   PaymentRequestDialogView* dialog_view() {
-    return static_cast<PaymentRequestDialogView*>(dialog_);
+    return static_cast<PaymentRequestDialogView*>(shown_dialog_);
   }
 
  private:
diff --git a/chrome/browser/ui/views/profiles/profile_chooser_view.cc b/chrome/browser/ui/views/profiles/profile_chooser_view.cc
index 4fa6e91..815b33ffb 100644
--- a/chrome/browser/ui/views/profiles/profile_chooser_view.cc
+++ b/chrome/browser/ui/views/profiles/profile_chooser_view.cc
@@ -41,6 +41,7 @@
 #include "chrome/browser/ui/chrome_pages.h"
 #include "chrome/browser/ui/profile_chooser_constants.h"
 #include "chrome/browser/ui/singleton_tabs.h"
+#include "chrome/browser/ui/sync/sync_promo_ui.h"
 #include "chrome/browser/ui/user_manager.h"
 #include "chrome/browser/ui/views/accessibility/non_accessible_image_view.h"
 #include "chrome/browser/ui/views/harmony/chrome_layout_provider.h"
@@ -180,13 +181,18 @@
 }
 
 BadgedProfilePhoto::BadgeType GetProfileBadgeType(Profile* profile) {
-  if (!profile->IsSupervised()) {
-    return AccountConsistencyModeManager::IsDiceEnabledForProfile(profile)
-               ? BadgedProfilePhoto::BADGE_TYPE_SYNC_COMPLETE
-               : BadgedProfilePhoto::BADGE_TYPE_NONE;
+  if (profile->IsSupervised()) {
+    return profile->IsChild() ? BadgedProfilePhoto::BADGE_TYPE_CHILD
+                              : BadgedProfilePhoto::BADGE_TYPE_SUPERVISOR;
   }
-  return profile->IsChild() ? BadgedProfilePhoto::BADGE_TYPE_CHILD
-                            : BadgedProfilePhoto::BADGE_TYPE_SUPERVISOR;
+  // |Profile::IsSyncAllowed| is needed to check whether sync is allowed by GPO
+  // policy.
+  if (AccountConsistencyModeManager::IsDiceEnabledForProfile(profile) &&
+      profile->IsSyncAllowed() &&
+      SigninManagerFactory::GetForProfile(profile)->IsAuthenticated()) {
+    return BadgedProfilePhoto::BADGE_TYPE_SYNC_COMPLETE;
+  }
+  return BadgedProfilePhoto::BADGE_TYPE_NONE;
 }
 
 std::vector<gfx::Image> GetImagesForAccounts(
@@ -655,9 +661,13 @@
         profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT :
         profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER);
   } else if (sender == current_profile_card_) {
-    if (dice_enabled_) {
+    if (dice_enabled_ &&
+        SigninManagerFactory::GetForProfile(browser_->profile())
+            ->IsAuthenticated()) {
       chrome::ShowSettingsSubPage(browser_, chrome::kSyncSetupSubPage);
     } else {
+      // Open settings to edit profile name and image. The profile doesn't need
+      // to be authenticated to open this.
       avatar_menu_->EditProfile(avatar_menu_->GetActiveProfileIndex());
       PostActionPerformed(ProfileMetrics::PROFILE_DESKTOP_MENU_EDIT_IMAGE);
       PostActionPerformed(ProfileMetrics::PROFILE_DESKTOP_MENU_EDIT_NAME);
@@ -933,8 +943,10 @@
 views::View* ProfileChooserView::CreateCurrentProfileView(
     const AvatarMenu::Item& avatar_item,
     bool is_guest) {
-  if (!avatar_item.signed_in && dice_enabled_)
+  if (!avatar_item.signed_in && dice_enabled_ &&
+      SyncPromoUI::ShouldShowSyncPromo(browser_->profile())) {
     return CreateDiceSigninView();
+  }
 
   ChromeLayoutProvider* provider = ChromeLayoutProvider::Get();
 
@@ -959,8 +971,9 @@
   bool show_email =
       !is_guest && avatar_item.signed_in && !account_consistency_enabled;
   const base::string16 hover_button_title =
-      dice_enabled_ ? l10n_util::GetStringUTF16(IDS_PROFILES_SYNCED_TO_TITLE)
-                    : profile_name;
+      dice_enabled_ && browser_->profile()->IsSyncAllowed()
+          ? l10n_util::GetStringUTF16(IDS_PROFILES_SYNCED_TO_TITLE)
+          : profile_name;
   HoverButton* profile_card = new HoverButton(
       this, std::move(current_profile_photo), hover_button_title,
       show_email ? avatar_item.username : base::string16());
@@ -997,9 +1010,8 @@
     return view;
   }
 
-  SigninManagerBase* signin_manager = SigninManagerFactory::GetForProfile(
-      browser_->profile()->GetOriginalProfile());
-  if (signin_manager->IsSigninAllowed()) {
+  if (!dice_enabled_ && SigninManagerFactory::GetForProfile(browser_->profile())
+                            ->IsSigninAllowed()) {
     views::View* extra_links_view = new views::View();
     extra_links_view->SetLayoutManager(std::make_unique<views::BoxLayout>(
         views::BoxLayout::kVertical,
diff --git a/chrome/browser/ui/views/sad_tab_view_interactive_uitest.cc b/chrome/browser/ui/views/sad_tab_view_interactive_uitest.cc
index dd1c3991..ec1caa65 100644
--- a/chrome/browser/ui/views/sad_tab_view_interactive_uitest.cc
+++ b/chrome/browser/ui/views/sad_tab_view_interactive_uitest.cc
@@ -13,6 +13,7 @@
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/interactive_test_utils.h"
 #include "chrome/test/base/ui_test_utils.h"
+#include "chrome/test/views/scoped_macviews_browser_mode.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/common/result_codes.h"
@@ -126,6 +127,8 @@
   }
 
  private:
+  test::ScopedMacViewsBrowserMode views_mode_{true};
+
   DISALLOW_COPY_AND_ASSIGN(SadTabViewInteractiveUITest);
 };
 
diff --git a/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc b/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc
index d394cb5f..ad49921 100644
--- a/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc
+++ b/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc
@@ -38,6 +38,7 @@
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/interactive_test_utils.h"
 #include "chrome/test/base/ui_test_utils.h"
+#include "chrome/test/views/scoped_macviews_browser_mode.h"
 #include "content/public/browser/notification_details.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_service.h"
@@ -551,6 +552,8 @@
   Browser* browser() const { return InProcessBrowserTest::browser(); }
 
  private:
+  test::ScopedMacViewsBrowserMode views_mode_{true};
+
 #if defined(OS_CHROMEOS)
   std::unique_ptr<ui::test::EventGenerator> event_generator_;
 #endif
diff --git a/chrome/browser/ui/views/toolbar/browser_action_test_util_views.cc b/chrome/browser/ui/views/toolbar/browser_action_test_util_views.cc
index e3edd35..fc5eb8af 100644
--- a/chrome/browser/ui/views/toolbar/browser_action_test_util_views.cc
+++ b/chrome/browser/ui/views/toolbar/browser_action_test_util_views.cc
@@ -198,6 +198,19 @@
   return gfx::Size(ExtensionPopup::kMaxWidth, ExtensionPopup::kMaxHeight);
 }
 
+bool BrowserActionTestUtilViews::CanBeResized() {
+  BrowserActionsContainer* container =
+      BrowserView::GetBrowserViewForBrowser(browser_)
+          ->toolbar()
+          ->browser_actions();
+
+  // The container can only be resized if we can start a drag for the view.
+  DCHECK_LE(1u, container->num_toolbar_actions());
+  ToolbarActionView* action_view = container->GetToolbarActionViewAt(0);
+  gfx::Point point(action_view->x(), action_view->y());
+  return container->CanStartDragForView(action_view, point, point);
+}
+
 BrowserActionTestUtilViews::BrowserActionTestUtilViews(
     Browser* browser,
     BrowserActionTestUtilViews* main_bar)
diff --git a/chrome/browser/ui/views/toolbar/browser_action_test_util_views.h b/chrome/browser/ui/views/toolbar/browser_action_test_util_views.h
index 0a67b46..908a3cc6 100644
--- a/chrome/browser/ui/views/toolbar/browser_action_test_util_views.h
+++ b/chrome/browser/ui/views/toolbar/browser_action_test_util_views.h
@@ -32,6 +32,7 @@
   std::unique_ptr<BrowserActionTestUtil> CreateOverflowBar() override;
   gfx::Size GetMinPopupSize() override;
   gfx::Size GetMaxPopupSize() override;
+  bool CanBeResized() override;
 
  private:
   friend class BrowserActionTestUtil;
diff --git a/chrome/browser/ui/views/toolbar/browser_actions_container_browsertest.cc b/chrome/browser/ui/views/toolbar/browser_actions_container_browsertest.cc
index 9a9d0f4..c67312c 100644
--- a/chrome/browser/ui/views/toolbar/browser_actions_container_browsertest.cc
+++ b/chrome/browser/ui/views/toolbar/browser_actions_container_browsertest.cc
@@ -18,6 +18,7 @@
 #include "chrome/browser/ui/views/frame/browser_view.h"
 #include "chrome/browser/ui/views/toolbar/toolbar_action_view.h"
 #include "chrome/browser/ui/views/toolbar/toolbar_view.h"
+#include "chrome/test/views/scoped_macviews_browser_mode.h"
 #include "extensions/browser/extension_prefs.h"
 #include "extensions/browser/extension_registry.h"
 #include "extensions/common/extension.h"
@@ -27,6 +28,8 @@
 #include "ui/views/test/test_views.h"
 #include "ui/views/view.h"
 
+namespace {
+
 // TODO(devlin): Continue moving any tests that should be platform independent
 // from this file to the crossplatform tests in
 // chrome/browser/ui/toolbar/browser_actions_bar_browsertest.cc.
@@ -34,7 +37,16 @@
 // Test that dragging browser actions works, and that dragging a browser action
 // from the overflow menu results in it "popping" out (growing the container
 // size by 1), rather than just reordering the extensions.
-IN_PROC_BROWSER_TEST_F(BrowserActionsBarBrowserTest, DragBrowserActions) {
+
+// The two drag & drop tests are currently restricted to Views browsers in the
+// absence of a good way to abstract drag & drop actions.
+class BrowserActionsBarViewsBrowserTest : public BrowserActionsBarBrowserTest {
+ private:
+  test::ScopedMacViewsBrowserMode views_mode_{true};
+};
+}  // namespace
+
+IN_PROC_BROWSER_TEST_F(BrowserActionsBarViewsBrowserTest, DragBrowserActions) {
   LoadExtensions();
 
   // Sanity check: All extensions showing; order is A B C.
@@ -147,7 +159,7 @@
 
 // Test that changes performed in one container affect containers in other
 // windows so that it is consistent.
-IN_PROC_BROWSER_TEST_F(BrowserActionsBarBrowserTest, MultipleWindows) {
+IN_PROC_BROWSER_TEST_F(BrowserActionsBarViewsBrowserTest, MultipleWindows) {
   LoadExtensions();
   BrowserActionsContainer* first =
       BrowserView::GetBrowserViewForBrowser(browser())->toolbar()->
@@ -214,16 +226,7 @@
 
   EXPECT_EQ(3, browser_actions_bar()->VisibleBrowserActions());
   EXPECT_EQ(3, browser_actions_bar()->NumberOfBrowserActions());
-
-  BrowserActionsContainer* container =
-      BrowserView::GetBrowserViewForBrowser(browser())
-          ->toolbar()->browser_actions();
-
-  // Currently, dragging should be enabled.
-  ToolbarActionView* action_view = container->GetToolbarActionViewAt(0);
-  ASSERT_TRUE(action_view);
-  gfx::Point point(action_view->x(), action_view->y());
-  EXPECT_TRUE(container->CanStartDragForView(action_view, point, point));
+  EXPECT_TRUE(browser_actions_bar()->CanBeResized());
 
   std::vector<std::string> action_ids;
   action_ids.push_back(extension_a()->id());
@@ -236,15 +239,13 @@
   EXPECT_EQ(2, browser_actions_bar()->NumberOfBrowserActions());
 
   // We shouldn't be able to drag in highlight mode.
-  action_view = container->GetToolbarActionViewAt(0);
-  EXPECT_FALSE(container->CanStartDragForView(action_view, point, point));
+  EXPECT_FALSE(browser_actions_bar()->CanBeResized());
 
   // We should go back to normal after leaving highlight mode.
   toolbar_model()->StopHighlighting();
   EXPECT_EQ(3, browser_actions_bar()->VisibleBrowserActions());
   EXPECT_EQ(3, browser_actions_bar()->NumberOfBrowserActions());
-  action_view = container->GetToolbarActionViewAt(0);
-  EXPECT_TRUE(container->CanStartDragForView(action_view, point, point));
+  EXPECT_TRUE(browser_actions_bar()->CanBeResized());
 }
 
 // Test the behavior of the overflow container for Extension Actions.
diff --git a/chrome/browser/ui/views/toolbar/toolbar_action_view_interactive_uitest.cc b/chrome/browser/ui/views/toolbar/toolbar_action_view_interactive_uitest.cc
index 8f2ecc6..9f015618 100644
--- a/chrome/browser/ui/views/toolbar/toolbar_action_view_interactive_uitest.cc
+++ b/chrome/browser/ui/views/toolbar/toolbar_action_view_interactive_uitest.cc
@@ -23,6 +23,7 @@
 #include "chrome/browser/ui/views/toolbar/extension_toolbar_menu_view.h"
 #include "chrome/browser/ui/views/toolbar/toolbar_view.h"
 #include "chrome/test/base/interactive_test_utils.h"
+#include "chrome/test/views/scoped_macviews_browser_mode.h"
 #include "extensions/browser/notification_types.h"
 #include "extensions/common/extension_builder.h"
 #include "extensions/common/feature_switch.h"
@@ -141,6 +142,8 @@
   void TearDownOnMainThread() override;
 
  private:
+  test::ScopedMacViewsBrowserMode views_mode_{true};
+
   DISALLOW_COPY_AND_ASSIGN(ToolbarActionViewInteractiveUITest);
 };
 
diff --git a/chrome/browser/ui/webui/print_preview/print_preview_handler_unittest.cc b/chrome/browser/ui/webui/print_preview/print_preview_handler_unittest.cc
index bc72b510..91dfd885 100644
--- a/chrome/browser/ui/webui/print_preview/print_preview_handler_unittest.cc
+++ b/chrome/browser/ui/webui/print_preview/print_preview_handler_unittest.cc
@@ -6,11 +6,11 @@
 
 #include "base/base64.h"
 #include "base/containers/flat_set.h"
-#include "base/i18n/rtl.h"
 #include "base/json/json_writer.h"
 #include "base/memory/ref_counted_memory.h"
 #include "base/strings/string16.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/test/icu_test_util.h"
 #include "base/values.h"
 #include "chrome/browser/printing/print_view_manager.h"
 #include "chrome/browser/ui/webui/print_preview/print_preview_ui.h"
@@ -342,7 +342,7 @@
   void Initialize() {
     // Set locale since the delimeters we check in VerifyInitialSettings()
     // depend on it.
-    base::i18n::SetICUDefaultLocale("en");
+    base::test::ScopedRestoreICUDefaultLocale scoped_locale("en");
 
     // Sending this message will enable javascript, so it must always be called
     // before any other messages are sent.
@@ -394,14 +394,14 @@
     ASSERT_TRUE(settings->FindKeyOfType("isInAppKioskMode",
                                         base::Value::Type::BOOLEAN));
 
-    const base::Value* thousandsDelimeter = settings->FindKeyOfType(
+    const base::Value* thousands_delimeter = settings->FindKeyOfType(
         "thousandsDelimeter", base::Value::Type::STRING);
-    ASSERT_TRUE(thousandsDelimeter);
-    EXPECT_EQ(",", thousandsDelimeter->GetString());
-    const base::Value* decimalDelimeter =
+    ASSERT_TRUE(thousands_delimeter);
+    EXPECT_EQ(",", thousands_delimeter->GetString());
+    const base::Value* decimal_delimeter =
         settings->FindKeyOfType("decimalDelimeter", base::Value::Type::STRING);
-    ASSERT_TRUE(decimalDelimeter);
-    EXPECT_EQ(".", decimalDelimeter->GetString());
+    ASSERT_TRUE(decimal_delimeter);
+    EXPECT_EQ(".", decimal_delimeter->GetString());
 
     ASSERT_TRUE(
         settings->FindKeyOfType("unitType", base::Value::Type::INTEGER));
diff --git a/chrome/browser/vr/elements/draw_phase.cc b/chrome/browser/vr/elements/draw_phase.cc
index 4ffdda01..ec8ad62 100644
--- a/chrome/browser/vr/elements/draw_phase.cc
+++ b/chrome/browser/vr/elements/draw_phase.cc
@@ -11,8 +11,8 @@
 namespace {
 
 static const char* g_draw_phase_strings[] = {
-    "kPhaseNone", "kPhaseBackground", "kPhaseForeground",
-    "kPhaseOverlayForeground",
+    "kPhaseNone",       "kPhaseBackground",        "kPhaseBackplanes",
+    "kPhaseForeground", "kPhaseOverlayForeground",
 };
 
 static_assert(
diff --git a/chrome/browser/vr/elements/draw_phase.h b/chrome/browser/vr/elements/draw_phase.h
index b525fa50..f8533eb 100644
--- a/chrome/browser/vr/elements/draw_phase.h
+++ b/chrome/browser/vr/elements/draw_phase.h
@@ -16,6 +16,7 @@
   // kPhaseNone is to be used for elements that do not draw. Eg, layouts.
   kPhaseNone = 0,
   kPhaseBackground,
+  kPhaseBackplanes,
   kPhaseForeground,
   kPhaseOverlayForeground,
   kNumDrawPhases = kPhaseOverlayForeground
diff --git a/chrome/browser/vr/elements/repositioner.cc b/chrome/browser/vr/elements/repositioner.cc
index 14c47d2..1d6b359 100644
--- a/chrome/browser/vr/elements/repositioner.cc
+++ b/chrome/browser/vr/elements/repositioner.cc
@@ -13,6 +13,7 @@
 
 namespace {
 
+constexpr float kDragThresholdDegrees = 3.0f;
 constexpr float kHeadUpTransitionStartDegrees = 60.0f;
 constexpr float kHeadUpTransitionEndDegrees = 30.0f;
 constexpr gfx::Vector3dF kUp = {0, 1, 0};
@@ -58,6 +59,7 @@
   if (enabled) {
     initial_transform_ = transform_;
     initial_laser_direction_ = laser_direction_;
+    has_moved_beyond_threshold_ = false;
   }
 }
 
@@ -93,6 +95,10 @@
   gfx::Vector3dF expected_right = gfx::CrossProduct(new_forward, up);
   gfx::Quaternion rotate_to_expected_right(new_right, expected_right);
   transform_.ConcatTransform(gfx::Transform(rotate_to_expected_right));
+  if (gfx::AngleBetweenVectorsInDegrees(
+          initial_laser_direction_, laser_direction_) > kDragThresholdDegrees) {
+    has_moved_beyond_threshold_ = true;
+  }
 
   // Potentially bake our current transform, to avoid situations where
   // |laser_direction_| and |initial_laser_direction_| are nearly 180 degrees
diff --git a/chrome/browser/vr/elements/repositioner.h b/chrome/browser/vr/elements/repositioner.h
index 33487b5..47e74197 100644
--- a/chrome/browser/vr/elements/repositioner.h
+++ b/chrome/browser/vr/elements/repositioner.h
@@ -32,6 +32,11 @@
   void SetEnabled(bool enabled);
   void Reset();
 
+  // This method returns true if the user has repositioned far enough that we
+  // should consider it an intentional drag (and the UI may want to respond
+  // different if this has happened).
+  bool HasMovedBeyondThreshold() const { return has_moved_beyond_threshold_; }
+
  private:
   gfx::Transform LocalTransform() const override;
   gfx::Transform GetTargetLocalTransform() const override;
@@ -43,6 +48,7 @@
 #endif
 
   bool enabled_ = false;
+  bool has_moved_beyond_threshold_ = false;
   gfx::Transform transform_;
   gfx::Vector3dF laser_direction_;
 
diff --git a/chrome/browser/vr/elements/reticle.cc b/chrome/browser/vr/elements/reticle.cc
index 21cdac1..873a826 100644
--- a/chrome/browser/vr/elements/reticle.cc
+++ b/chrome/browser/vr/elements/reticle.cc
@@ -5,10 +5,14 @@
 #include "chrome/browser/vr/elements/reticle.h"
 
 #include "base/numerics/math_constants.h"
+#include "chrome/browser/vr/databinding/binding.h"
+#include "chrome/browser/vr/elements/rect.h"
+#include "chrome/browser/vr/elements/vector_icon.h"
 #include "chrome/browser/vr/model/model.h"
 #include "chrome/browser/vr/ui_element_renderer.h"
 #include "chrome/browser/vr/ui_scene.h"
 #include "chrome/browser/vr/ui_scene_constants.h"
+#include "chrome/browser/vr/vector_icons/vector_icons.h"
 #include "chrome/browser/vr/vr_gl_util.h"
 
 namespace vr {
@@ -64,13 +68,13 @@
 );
 // clang-format on
 
-static constexpr float kRingDiameter = 1.0f;
-static constexpr float kInnerHole = 0.0f;
-static constexpr float kInnerRingEnd = 0.177f;
-static constexpr float kInnerRingThickness = 0.14f;
-static constexpr float kMidRingEnd = 0.177f;
-static constexpr float kMidRingOpacity = 0.22f;
-static constexpr float kReticleColor[] = {1.0f, 1.0f, 1.0f, 1.0f};
+constexpr float kRingDiameter = 1.0f;
+constexpr float kInnerHole = 0.0f;
+constexpr float kInnerRingEnd = 0.177f;
+constexpr float kInnerRingThickness = 0.14f;
+constexpr float kMidRingEnd = 0.177f;
+constexpr float kMidRingOpacity = 0.22f;
+constexpr float kReticleColor[] = {1.0f, 1.0f, 1.0f, 1.0f};
 
 }  // namespace
 
@@ -87,34 +91,10 @@
 
 void Reticle::Render(UiElementRenderer* renderer,
                      const CameraModel& model) const {
-  // Scale the reticle to have a fixed FOV size at any distance.
-  const float eye_to_target =
-      std::sqrt(model_->reticle.target_point.SquaredDistanceTo(kOrigin));
-
-  gfx::Transform mat;
-  mat.Scale3d(kReticleWidth * eye_to_target, kReticleHeight * eye_to_target, 1);
-
-  gfx::Quaternion rotation;
-
-  UiElement* target = TargetElement();
-  if (target) {
-    // Make the reticle planar to the element it's hitting.
-    rotation = gfx::Quaternion(gfx::Vector3dF(0.0f, 0.0f, -1.0f),
-                               -target->GetNormal());
-  } else {
-    // Rotate the reticle to directly face the eyes.
-    rotation = gfx::Quaternion(gfx::Vector3dF(0.0f, 0.0f, -1.0f),
-                               model_->reticle.target_point - kOrigin);
-  }
-  gfx::Transform rotation_mat(rotation);
-  mat = rotation_mat * mat;
-
-  mat.matrix().postTranslate(model_->reticle.target_point.x(),
-                             model_->reticle.target_point.y(),
-                             model_->reticle.target_point.z());
-  gfx::Transform transform =
-      model.view_proj_matrix * world_space_transform() * mat;
-  renderer->DrawReticle(computed_opacity(), transform);
+  if (model_->reticle.cursor_type != kCursorDefault)
+    return;
+  renderer->DrawReticle(computed_opacity(),
+                        model.view_proj_matrix * world_space_transform());
 }
 
 Reticle::Renderer::Renderer()
@@ -162,4 +142,33 @@
   return kVertexShader;
 }
 
+gfx::Transform Reticle::LocalTransform() const {
+  // Scale the reticle to have a fixed FOV size at any distance.
+  const float eye_to_target =
+      std::sqrt(model_->reticle.target_point.SquaredDistanceTo(kOrigin));
+
+  if (eye_to_target == 0.0f)
+    return gfx::Transform();
+
+  gfx::Transform mat;
+  mat.Scale3d(kReticleWidth * eye_to_target, kReticleHeight * eye_to_target, 1);
+
+  // This will make the reticle planar to the target element (if there is one),
+  // and directly face the user, otherwise.
+  UiElement* target = TargetElement();
+  gfx::Transform rotation_mat(gfx::Quaternion(
+      gfx::Vector3dF(0.0f, 0.0f, -1.0f),
+      target ? -target->GetNormal() : model_->reticle.target_point - kOrigin));
+  mat = rotation_mat * mat;
+
+  mat.matrix().postTranslate(model_->reticle.target_point.x(),
+                             model_->reticle.target_point.y(),
+                             model_->reticle.target_point.z());
+  return mat;
+}
+
+gfx::Transform Reticle::GetTargetLocalTransform() const {
+  return LocalTransform();
+}
+
 }  // namespace vr
diff --git a/chrome/browser/vr/elements/reticle.h b/chrome/browser/vr/elements/reticle.h
index 8d73cb2..1000013 100644
--- a/chrome/browser/vr/elements/reticle.h
+++ b/chrome/browser/vr/elements/reticle.h
@@ -47,6 +47,8 @@
  private:
   void Render(UiElementRenderer* renderer,
               const CameraModel& model) const final;
+  gfx::Transform LocalTransform() const final;
+  gfx::Transform GetTargetLocalTransform() const final;
 
   gfx::Point3F origin_;
   gfx::Point3F target_;
diff --git a/chrome/browser/vr/elements/shadow.cc b/chrome/browser/vr/elements/shadow.cc
index 8474533..6f0d7bda 100644
--- a/chrome/browser/vr/elements/shadow.cc
+++ b/chrome/browser/vr/elements/shadow.cc
@@ -121,15 +121,18 @@
 
 Shadow::Shadow() {
   set_bounds_contain_children(true);
+  set_bounds_contain_padding(false);
 }
 
 Shadow::~Shadow() {}
 
 void Shadow::Render(UiElementRenderer* renderer,
                     const CameraModel& camera_model) const {
+  DCHECK_EQ(left_padding(), right_padding());
+  DCHECK_EQ(top_padding(), bottom_padding());
   renderer->DrawShadow(
       camera_model.view_proj_matrix * world_space_transform(), size(),
-      x_padding(), y_padding(),
+      left_padding(), right_padding(),
       gfx::Tween::FloatValueBetween(depth_, 0.0f, 1.0f), SK_ColorBLACK,
       computed_opacity() * kShadowOpacity * intensity_, corner_radius());
 }
@@ -149,12 +152,6 @@
     set_corner_radius(children().front()->corner_radii().MaxRadius());
 }
 
-gfx::SizeF Shadow::ContributedSize() const {
-  gfx::RectF bounds(size());
-  bounds.Inset(x_padding(), y_padding());
-  return bounds.size();
-}
-
 Shadow::Renderer::Renderer()
     : BaseQuadRenderer(kVertexShader, kFragmentShader) {
   model_view_proj_matrix_handle_ =
diff --git a/chrome/browser/vr/elements/shadow.h b/chrome/browser/vr/elements/shadow.h
index c773c0f..1e1a7e4 100644
--- a/chrome/browser/vr/elements/shadow.h
+++ b/chrome/browser/vr/elements/shadow.h
@@ -25,8 +25,6 @@
   void LayOutChildren() override;
   void set_intensity(float intensity) { intensity_ = intensity; }
 
-  gfx::SizeF ContributedSize() const override;
-
   class Renderer : public BaseQuadRenderer {
    public:
     Renderer();
diff --git a/chrome/browser/vr/elements/shadow_unittest.cc b/chrome/browser/vr/elements/shadow_unittest.cc
index a6f3aca9..994d572 100644
--- a/chrome/browser/vr/elements/shadow_unittest.cc
+++ b/chrome/browser/vr/elements/shadow_unittest.cc
@@ -26,17 +26,17 @@
   scene.AddUiElement(kRoot, std::move(shadow));
 
   scene.OnBeginFrame(MsToTicks(0), kStartHeadPose);
-  float old_x_padding = shadow_ptr->x_padding();
-  float old_y_padding = shadow_ptr->y_padding();
-  EXPECT_LE(0.0f, old_x_padding);
-  EXPECT_LE(0.0f, old_y_padding);
+  float old_left_padding = shadow_ptr->left_padding();
+  float old_top_padding = shadow_ptr->top_padding();
+  EXPECT_LE(0.0f, old_left_padding);
+  EXPECT_LE(0.0f, old_top_padding);
 
   rect_ptr->SetTranslate(0, 0, 0.15);
   scene.OnBeginFrame(MsToTicks(0), kStartHeadPose);
-  float new_x_padding = shadow_ptr->x_padding();
-  float new_y_padding = shadow_ptr->y_padding();
-  EXPECT_LE(old_x_padding, new_x_padding);
-  EXPECT_LE(old_y_padding, new_y_padding);
+  float new_left_padding = shadow_ptr->left_padding();
+  float new_top_padding = shadow_ptr->top_padding();
+  EXPECT_LE(old_left_padding, new_left_padding);
+  EXPECT_LE(old_top_padding, new_top_padding);
 }
 
 }  // namespace vr
diff --git a/chrome/browser/vr/elements/ui_element.cc b/chrome/browser/vr/elements/ui_element.cc
index d47e608..8f4e597e 100644
--- a/chrome/browser/vr/elements/ui_element.cc
+++ b/chrome/browser/vr/elements/ui_element.cc
@@ -87,6 +87,7 @@
 
 EventHandlers::EventHandlers() = default;
 EventHandlers::~EventHandlers() = default;
+EventHandlers::EventHandlers(const EventHandlers& other) = default;
 
 UiElement::UiElement() : id_(AllocateId()) {
   animation_.set_target(this);
@@ -256,7 +257,11 @@
 void UiElement::OnSetSize(const gfx::SizeF& size) {}
 
 gfx::SizeF UiElement::ContributedSize() const {
-  return size();
+  gfx::RectF bounds(size());
+  if (!bounds_contain_padding_) {
+    bounds.Inset(left_padding_, bottom_padding_, right_padding_, top_padding_);
+  }
+  return bounds.size();
 }
 
 void UiElement::SetVisible(bool visible) {
@@ -687,8 +692,10 @@
 void UiElement::DoLayOutChildren() {
   LayOutChildren();
   if (!bounds_contain_children_) {
-    DCHECK_EQ(0.0f, x_padding_);
-    DCHECK_EQ(0.0f, y_padding_);
+    DCHECK_EQ(0.0f, right_padding_);
+    DCHECK_EQ(0.0f, left_padding_);
+    DCHECK_EQ(0.0f, top_padding_);
+    DCHECK_EQ(0.0f, bottom_padding_);
     return;
   }
 
@@ -719,7 +726,8 @@
     bounds.Union(local_rect);
   }
 
-  bounds.Inset(-x_padding_, -y_padding_);
+  bounds.Inset(-left_padding_, -bottom_padding_, -right_padding_,
+               -top_padding_);
   bounds.set_origin(bounds.CenterPoint());
   local_origin_ = bounds.origin();
   if (bounds.size() == GetTargetSize())
diff --git a/chrome/browser/vr/elements/ui_element.h b/chrome/browser/vr/elements/ui_element.h
index b16db7e2..df491db 100644
--- a/chrome/browser/vr/elements/ui_element.h
+++ b/chrome/browser/vr/elements/ui_element.h
@@ -23,6 +23,7 @@
 #include "chrome/browser/vr/elements/ui_element_name.h"
 #include "chrome/browser/vr/elements/ui_element_type.h"
 #include "chrome/browser/vr/model/camera_model.h"
+#include "chrome/browser/vr/model/reticle_model.h"
 #include "chrome/browser/vr/target_property.h"
 #include "ui/gfx/geometry/point3_f.h"
 #include "ui/gfx/geometry/quaternion.h"
@@ -57,6 +58,7 @@
 
 struct EventHandlers {
   EventHandlers();
+  EventHandlers(const EventHandlers& other);
   ~EventHandlers();
   base::RepeatingCallback<void()> hover_enter;
   base::RepeatingCallback<void()> hover_leave;
@@ -228,7 +230,7 @@
   // their children. Eg, for shadows.
   // TODO(crbug.com/820507): change this to LayoutSize and update all layout
   // code to make use of this instead of size().
-  virtual gfx::SizeF ContributedSize() const;
+  gfx::SizeF ContributedSize() const;
 
   gfx::PointF local_origin() const { return local_origin_; }
 
@@ -298,6 +300,11 @@
     bounds_contain_children_ = bounds_contain_children;
   }
 
+  bool bounds_contain_padding() const { return bounds_contain_padding_; }
+  void set_bounds_contain_padding(bool bounds_contain_padding) {
+    bounds_contain_padding_ = bounds_contain_padding;
+  }
+
   bool contributes_to_parent_bounds() const {
     return contributes_to_parent_bounds_;
   }
@@ -305,11 +312,23 @@
     contributes_to_parent_bounds_ = value;
   }
 
-  float x_padding() const { return x_padding_; }
-  float y_padding() const { return y_padding_; }
-  void set_padding(float x_padding, float y_padding) {
-    x_padding_ = x_padding;
-    y_padding_ = y_padding;
+  float left_padding() const { return left_padding_; }
+  float right_padding() const { return right_padding_; }
+  float top_padding() const { return top_padding_; }
+  float bottom_padding() const { return bottom_padding_; }
+
+  void set_padding(float x, float y) {
+    left_padding_ = x;
+    right_padding_ = x;
+    top_padding_ = y;
+    bottom_padding_ = y;
+  }
+
+  void set_padding(float left, float top, float right, float bottom) {
+    left_padding_ = left;
+    right_padding_ = right;
+    top_padding_ = top;
+    bottom_padding_ = bottom;
   }
 
   const gfx::Transform& inheritable_transform() const {
@@ -433,6 +452,9 @@
     return updated_visibility_this_frame_;
   }
 
+  void set_cursor_type(CursorType cursor_type) { cursor_type_ = cursor_type; }
+  CursorType cursor_type() const { return cursor_type_; }
+
   std::string DebugName() const;
 
 #ifndef NDEBUG
@@ -539,9 +561,12 @@
   // size to accommodate all descendants, adding in the padding below along the
   // x and y axes.
   bool bounds_contain_children_ = false;
+  bool bounds_contain_padding_ = true;
   bool contributes_to_parent_bounds_ = true;
-  float x_padding_ = 0.0f;
-  float y_padding_ = 0.0f;
+  float left_padding_ = 0.0f;
+  float right_padding_ = 0.0f;
+  float top_padding_ = 0.0f;
+  float bottom_padding_ = 0.0f;
 
   Animation animation_;
 
@@ -595,6 +620,8 @@
   // Indicates that this element may be resized by parent layout elements.
   bool resizable_by_layout_ = false;
 
+  CursorType cursor_type_ = kCursorDefault;
+
   DISALLOW_COPY_AND_ASSIGN(UiElement);
 };
 
diff --git a/chrome/browser/vr/elements/ui_element_name.cc b/chrome/browser/vr/elements/ui_element_name.cc
index a6b9af04..0010ac9 100644
--- a/chrome/browser/vr/elements/ui_element_name.cc
+++ b/chrome/browser/vr/elements/ui_element_name.cc
@@ -32,6 +32,7 @@
     "kControllerGroup",
     "kLaser",
     "kController",
+    "kRepositionCursor",
     "kReticle",
     "kReticleLaserGroup",
     "kKeyboardVisibilityControlForVoice",
@@ -42,6 +43,7 @@
     "kFloor",
     "kStars",
     "kUpdateKeyboardPrompt",
+    "kUrlBarBackplane",
     "kUrlBarPositioner",
     "kUrlBarDmmRoot",
     "kUrlBar",
diff --git a/chrome/browser/vr/elements/ui_element_name.h b/chrome/browser/vr/elements/ui_element_name.h
index 4774010..e3a4b41 100644
--- a/chrome/browser/vr/elements/ui_element_name.h
+++ b/chrome/browser/vr/elements/ui_element_name.h
@@ -31,6 +31,7 @@
   kControllerGroup,
   kLaser,
   kController,
+  kRepositionCursor,
   kReticle,
   kReticleLaserGroup,
   kKeyboardVisibilityControlForVoice,
@@ -41,6 +42,7 @@
   kFloor,
   kStars,
   kUpdateKeyboardPrompt,
+  kUrlBarBackplane,
   kUrlBarPositioner,
   kUrlBarDmmRoot,
   kUrlBar,
diff --git a/chrome/browser/vr/elements/ui_element_type.cc b/chrome/browser/vr/elements/ui_element_type.cc
index c4f088d..e82595c1 100644
--- a/chrome/browser/vr/elements/ui_element_type.cc
+++ b/chrome/browser/vr/elements/ui_element_type.cc
@@ -36,6 +36,8 @@
     "kTypeToastText",
     "kTypeSnackbarButton",
     "kTypeSnackbarDescription",
+    "kTypeCursorBackground",
+    "kTypeCursorForeground",
 };
 
 static_assert(
diff --git a/chrome/browser/vr/elements/ui_element_type.h b/chrome/browser/vr/elements/ui_element_type.h
index acb4dc08..7c69daf 100644
--- a/chrome/browser/vr/elements/ui_element_type.h
+++ b/chrome/browser/vr/elements/ui_element_type.h
@@ -36,6 +36,8 @@
   kTypeToastText,
   kTypeSnackbarButton,
   kTypeSnackbarDescription,
+  kTypeCursorBackground,
+  kTypeCursorForeground,
 
   // This must be last.
   kNumUiElementTypes,
diff --git a/chrome/browser/vr/model/color_scheme.cc b/chrome/browser/vr/model/color_scheme.cc
index 8b29674..6a1226d 100644
--- a/chrome/browser/vr/model/color_scheme.cc
+++ b/chrome/browser/vr/model/color_scheme.cc
@@ -152,6 +152,10 @@
   normal_scheme.incognito_factor = 0.0f;
   normal_scheme.fullscreen_factor = 0.0f;
 
+  normal_scheme.cursor_background_center = 0x24000000;
+  normal_scheme.cursor_background_edge = SK_ColorTRANSPARENT;
+  normal_scheme.cursor_foreground = SK_ColorWHITE;
+
   g_fullscreen_scheme.Get() = normal_scheme;
   ColorScheme& fullscreen_scheme = g_fullscreen_scheme.Get();
   fullscreen_scheme.world_background = 0xFF000714;
diff --git a/chrome/browser/vr/model/color_scheme.h b/chrome/browser/vr/model/color_scheme.h
index ce17eb2..3fde9c2d 100644
--- a/chrome/browser/vr/model/color_scheme.h
+++ b/chrome/browser/vr/model/color_scheme.h
@@ -137,6 +137,10 @@
   SkColor reposition_label;
   SkColor reposition_label_background;
 
+  SkColor cursor_background_center;
+  SkColor cursor_background_edge;
+  SkColor cursor_foreground;
+
   // These are used for blending between colors that are available only in
   // shaders. They are, as you might expect, one for a given mode, but zero
   // otherwise.
diff --git a/chrome/browser/vr/model/reticle_model.h b/chrome/browser/vr/model/reticle_model.h
index 768ae3e..9a32c13b 100644
--- a/chrome/browser/vr/model/reticle_model.h
+++ b/chrome/browser/vr/model/reticle_model.h
@@ -9,6 +9,11 @@
 
 namespace vr {
 
+enum CursorType {
+  kCursorDefault,
+  kCursorReposition,
+};
+
 // The ReticleModel contains information related to the target of the
 // controller's laser. It is computed by the UiInputManager and is used by the
 // input manager in the production of gestures as well as by the Reticle element
@@ -17,6 +22,7 @@
   gfx::Point3F target_point;
   gfx::PointF target_local_point;
   int target_element_id = 0;
+  CursorType cursor_type = kCursorDefault;
 };
 
 }  // namespace vr
diff --git a/chrome/browser/vr/ui_input_manager.cc b/chrome/browser/vr/ui_input_manager.cc
index a861bec..bf72bcff 100644
--- a/chrome/browser/vr/ui_input_manager.cc
+++ b/chrome/browser/vr/ui_input_manager.cc
@@ -84,6 +84,7 @@
     reticle_model->target_element_id = element->id();
     reticle_model->target_local_point = result.local_hit_point;
     reticle_model->target_point = result.hit_point;
+    reticle_model->cursor_type = element->cursor_type();
     break;
   }
 }
diff --git a/chrome/browser/vr/ui_scene.cc b/chrome/browser/vr/ui_scene.cc
index f780f5d..5d83300 100644
--- a/chrome/browser/vr/ui_scene.cc
+++ b/chrome/browser/vr/ui_scene.cc
@@ -167,6 +167,7 @@
 UiScene::Elements UiScene::GetVisibleElementsToDraw() const {
   return GetVisibleElements(GetUiElementByName(kRoot), [](UiElement* element) {
     return element->draw_phase() == kPhaseForeground ||
+           element->draw_phase() == kPhaseBackplanes ||
            element->draw_phase() == kPhaseBackground;
   });
 }
diff --git a/chrome/browser/vr/ui_scene_constants.h b/chrome/browser/vr/ui_scene_constants.h
index fcecad38..e78c8cf17 100644
--- a/chrome/browser/vr/ui_scene_constants.h
+++ b/chrome/browser/vr/ui_scene_constants.h
@@ -75,6 +75,8 @@
 static constexpr float kUrlBarSecuritySeparatorHeightDMM = 0.026f;
 static constexpr float kUrlBarOriginFadeWidth = 0.044f;
 static constexpr float kUrlBarOriginMinimumPathWidth = 0.044f;
+static constexpr float kUrlBarBackplaneTopPadding = 0.065f;
+static constexpr float kUrlBarBackplanePadding = 0.005f;
 
 static constexpr float kOverlayPlaneDistance = 2.3f;
 
@@ -283,20 +285,7 @@
 static constexpr float kSkyDistance = 1000.0f;
 static constexpr float kGridOpacity = 0.5f;
 
-static constexpr float kRepositionButtonDiameter = 0.75f * kCloseButtonDiameter;
-// This allows the button to be hittable even when hidden.
-static constexpr float kRepositionButtonMinOpacity = 0.001f;
-static constexpr float kRepositionButtonMidOpacity = 0.3f;
-static constexpr float kRepositionButtonMaxOpacity = 1.0f;
-static constexpr float kRepositionButtonXOffset = kIndicatorGap;
-static constexpr float kRepositionButtonYOffset = 0.5f * kIndicatorGap;
-static constexpr int kRepositionButtonTransitionDurationMs = 750;
-static constexpr float kRepositionLabelWidth = 0.55f * kContentWidth;
-static constexpr float kRepositionLabelFontHeight = kControllerLabelFontHeight;
-static constexpr float kRepositionLabelFontScale = 1.5f;
-static constexpr float kRepositionLabelBackgroundPadding = 0.06f;
 static constexpr float kRepositionContentOpacity = 0.2f;
-static constexpr float kRepositionLabelBackgroundCornerRadius = 0.02f;
 
 static constexpr float kPromptWidthDMM = 0.63f;
 static constexpr float kPromptHeightDMM = 0.218f;
@@ -304,6 +293,9 @@
 static constexpr float kPromptShadowOffsetDMM = 0.1f;
 static constexpr float kPromptDistance = 2.4f;
 
+static constexpr float kRepositionCursorBackgroundSize = 1.4f;
+static constexpr float kRepositionCursorSize = 1.2f;
+
 static constexpr float kMinResizerScale = 0.5f;
 static constexpr float kMaxResizerScale = 1.5f;
 
diff --git a/chrome/browser/vr/ui_scene_creator.cc b/chrome/browser/vr/ui_scene_creator.cc
index eac1ff6..56fab4be 100644
--- a/chrome/browser/vr/ui_scene_creator.cc
+++ b/chrome/browser/vr/ui_scene_creator.cc
@@ -588,6 +588,22 @@
   return controller;
 }
 
+EventHandlers CreateRepositioningHandlers(Model* model, UiScene* scene) {
+  EventHandlers handlers;
+  handlers.button_down = base::BindRepeating(
+      [](Model* model) { model->push_mode(kModeRepositionWindow); },
+      base::Unretained(model));
+  handlers.button_up = base::BindRepeating(
+      [](Model* model, Repositioner* repositioner) {
+        if (repositioner->HasMovedBeyondThreshold())
+          model->pop_mode(kModeRepositionWindow);
+      },
+      base::Unretained(model),
+      base::Unretained(static_cast<Repositioner*>(
+          scene->GetUiElementByName(k2dBrowsingRepositioner))));
+  return handlers;
+}
+
 }  // namespace
 
 UiSceneCreator::UiSceneCreator(UiBrowserInterface* browser,
@@ -925,9 +941,13 @@
 void UiSceneCreator::CreateContentQuad() {
   // Place an invisible but hittable plane behind the content quad, to keep the
   // reticle roughly planar with the content if near content.
-  auto hit_plane = Create<InvisibleHitTarget>(kBackplane, kPhaseForeground);
+  auto hit_plane = Create<InvisibleHitTarget>(kBackplane, kPhaseBackplanes);
   hit_plane->SetSize(kBackplaneSize, kSceneHeight);
   hit_plane->set_contributes_to_parent_bounds(false);
+  hit_plane->set_cursor_type(kCursorReposition);
+
+  hit_plane->set_event_handlers(CreateRepositioningHandlers(model_, scene_));
+
   scene_->AddUiElement(k2dBrowsingContentGroup, std::move(hit_plane));
 
   auto resizer = Create<Resizer>(kContentResizer, kPhaseNone);
@@ -1476,77 +1496,6 @@
 }
 
 void UiSceneCreator::CreateContentRepositioningAffordance() {
-  auto reposition_button = Create<DiscButton>(
-      kContentQuadRepositionButton, kPhaseForeground,
-      base::BindRepeating(
-          [](Model* model) { model->push_mode(kModeRepositionWindow); },
-          base::Unretained(model_)),
-      kRepositionIcon, audio_delegate_);
-  reposition_button->SetSize(kRepositionButtonDiameter,
-                             kRepositionButtonDiameter);
-  reposition_button->set_y_anchoring(BOTTOM);
-  reposition_button->set_x_anchoring(RIGHT);
-  reposition_button->set_x_centering(LEFT);
-  reposition_button->set_y_centering(BOTTOM);
-  reposition_button->SetTranslate(kRepositionButtonXOffset,
-                                  kRepositionButtonYOffset, 0);
-  reposition_button->SetTransitionedProperties({OPACITY});
-  reposition_button->SetTransitionDuration(
-      base::TimeDelta::FromMilliseconds(kRepositionButtonTransitionDurationMs));
-  reposition_button->background()->SetTransitionedProperties(
-      {BACKGROUND_COLOR, TRANSFORM});
-  reposition_button->SetOpacity(kRepositionButtonMinOpacity);
-  reposition_button->SetSounds(kSoundNone, kSoundNone, nullptr);
-  reposition_button->AddBinding(std::make_unique<Binding<float>>(
-      VR_BIND_LAMBDA(
-          [](Model* model, Button* button) {
-            if (!model->experimental_features_enabled)
-              return 0.0f;
-            if (button->hovered())
-              return kRepositionButtonMaxOpacity;
-            if (!model->controller.quiescent)
-              return kRepositionButtonMidOpacity;
-            return kRepositionButtonMinOpacity;
-          },
-          base::Unretained(model_), base::Unretained(reposition_button.get())),
-      VR_BIND_LAMBDA(
-          [](UiElement* button, const float& opacity) {
-            if (opacity == 1.0f)
-              button->SetVisibleImmediately(true);
-            else
-              button->SetOpacity(opacity);
-          },
-          base::Unretained(reposition_button.get()))));
-  VR_BIND_BUTTON_COLORS(model_, reposition_button.get(),
-                        &ColorScheme::button_colors,
-                        &DiscButton::SetButtonColors);
-  scene_->AddUiElement(kContentQuad, std::move(reposition_button));
-
-  auto label_background =
-      Create<Rect>(kContentRepositionLabel, kPhaseForeground);
-  label_background->set_bounds_contain_children(true);
-  label_background->set_corner_radius(kRepositionLabelBackgroundCornerRadius);
-  label_background->set_padding(kRepositionLabelBackgroundPadding,
-                                kRepositionLabelBackgroundPadding);
-  label_background->set_contributes_to_parent_bounds(false);
-  VR_BIND_COLOR(model_, label_background.get(),
-                &ColorScheme::reposition_label_background, &Rect::SetColor);
-  VR_BIND_VISIBILITY(label_background, model->reposition_window_enabled());
-
-  auto label =
-      Create<Text>(kNone, kPhaseForeground, kRepositionLabelFontHeight);
-  label->SetText(l10n_util::GetStringUTF16(IDS_VR_REPOSITION_LABEL));
-  label->SetVisible(true);
-  label->SetAlignment(UiTexture::kTextAlignmentCenter);
-  label->SetLayoutMode(kSingleLineFixedHeight);
-  label->SetScale(kRepositionLabelFontScale, kRepositionLabelFontScale,
-                  kRepositionLabelFontScale);
-  VR_BIND_COLOR(model_, label.get(), &ColorScheme::reposition_label,
-                &Text::SetColor);
-
-  label_background->AddChild(std::move(label));
-  scene_->AddUiElement(k2dBrowsingContentGroup, std::move(label_background));
-
   auto content_toggle =
       Create<UiElement>(kContentRepositionVisibilityToggle, kPhaseNone);
   content_toggle->SetTransitionedProperties({OPACITY});
@@ -1555,13 +1504,15 @@
       float, Model, model_,
       model->reposition_window_enabled() ? kRepositionContentOpacity : 1.0f,
       UiElement, content_toggle.get(), SetOpacity));
-  scene_->AddParentUiElement(kContentResizer, std::move(content_toggle));
+  scene_->AddParentUiElement(k2dBrowsingForeground,
+                             std::move(content_toggle));
 
   auto hit_plane =
       Create<InvisibleHitTarget>(kContentRepositionHitPlane, kPhaseForeground);
   hit_plane->set_contributes_to_parent_bounds(false);
   hit_plane->SetSize(kSceneSize, kSceneSize);
   hit_plane->SetTranslate(0.0f, 0.0f, -kContentDistance);
+  hit_plane->set_cursor_type(kCursorReposition);
   EventHandlers event_handlers;
   event_handlers.button_up = base::BindRepeating(
       [](Model* m) {
@@ -1653,6 +1604,35 @@
   auto reticle = std::make_unique<Reticle>(scene_, model_);
   reticle->SetDrawPhase(kPhaseForeground);
 
+  auto reposition_group = Create<UiElement>(kRepositionCursor, kPhaseNone);
+  VR_BIND_VISIBILITY(reposition_group,
+                     model->reticle.cursor_type == kCursorReposition);
+
+  auto reposition_bg = Create<Rect>(kNone, kPhaseForeground);
+  reposition_bg->set_owner_name_for_test(kRepositionCursor);
+  reposition_bg->SetType(kTypeCursorBackground);
+  reposition_bg->SetSize(kRepositionCursorBackgroundSize,
+                         kRepositionCursorBackgroundSize);
+  reposition_bg->SetDrawPhase(kPhaseForeground);
+  VR_BIND_COLOR(model_, reposition_bg.get(),
+                &ColorScheme::cursor_background_edge, &Rect::SetEdgeColor);
+  VR_BIND_COLOR(model_, reposition_bg.get(),
+                &ColorScheme::cursor_background_center, &Rect::SetCenterColor);
+
+  auto reposition_icon = std::make_unique<VectorIcon>(128);
+  reposition_icon->set_owner_name_for_test(kRepositionCursor);
+  reposition_icon->SetType(kTypeCursorForeground);
+  reposition_icon->SetIcon(kRepositionIcon);
+  reposition_icon->SetDrawPhase(kPhaseForeground);
+  reposition_icon->SetSize(kRepositionCursorSize, kRepositionCursorSize);
+  VR_BIND_COLOR(model_, reposition_icon.get(), &ColorScheme::cursor_foreground,
+                &VectorIcon::SetColor);
+
+  reposition_group->AddChild(std::move(reposition_bg));
+  reposition_group->AddChild(std::move(reposition_icon));
+
+  reticle->AddChild(std::move(reposition_group));
+
   reticle_laser_group->AddChild(std::move(laser));
   reticle_laser_group->AddChild(std::move(reticle));
 
@@ -1706,11 +1686,20 @@
   scaler->set_contributes_to_parent_bounds(false);
   scene_->AddUiElement(kUrlBarPositioner, std::move(scaler));
 
+  auto backplane =
+      Create<InvisibleHitTarget>(kUrlBarBackplane, kPhaseBackplanes);
+  backplane->set_bounds_contain_children(true);
+  backplane->set_contributes_to_parent_bounds(false);
+  backplane->set_padding(kUrlBarBackplanePadding, kUrlBarBackplaneTopPadding,
+                         kUrlBarBackplanePadding, kUrlBarBackplanePadding);
+  backplane->set_event_handlers(CreateRepositioningHandlers(model_, scene_));
+  VR_BIND_VISIBILITY(backplane, !model->fullscreen_enabled());
+  scene_->AddUiElement(kUrlBarDmmRoot, std::move(backplane));
+
   auto url_bar = Create<UiElement>(kUrlBar, kPhaseNone);
   url_bar->SetRotate(1, 0, 0, kUrlBarRotationRad);
   url_bar->set_bounds_contain_children(true);
-  VR_BIND_VISIBILITY(url_bar, !model->fullscreen_enabled());
-  scene_->AddUiElement(kUrlBarDmmRoot, std::move(url_bar));
+  scene_->AddUiElement(kUrlBarBackplane, std::move(url_bar));
 
   auto layout =
       Create<LinearLayout>(kUrlBarLayout, kPhaseNone, LinearLayout::kRight);
diff --git a/chrome/browser/vr/ui_unittest.cc b/chrome/browser/vr/ui_unittest.cc
index d2736985..6594260a 100644
--- a/chrome/browser/vr/ui_unittest.cc
+++ b/chrome/browser/vr/ui_unittest.cc
@@ -52,6 +52,7 @@
     kContentQuad,
     kContentQuadShadow,
     kBackplane,
+    kUrlBarBackplane,
     kUrlBarBackButton,
     kUrlBarBackButtonIcon,
     kUrlBarSeparator,
@@ -1193,36 +1194,6 @@
   EXPECT_FALSE(IsVisible(kControllerBackButtonLabel));
 }
 
-TEST_F(UiTest, RepositionButton) {
-  CreateScene(kNotInCct, kNotInWebVr);
-  DiscButton* button = static_cast<DiscButton*>(
-      scene_->GetUiElementByName(kContentQuadRepositionButton));
-  EXPECT_FALSE(IsVisible(button->name()));
-
-  model_->experimental_features_enabled = true;
-  model_->controller.quiescent = true;
-  OnBeginFrame();
-  EXPECT_EQ(kRepositionButtonMinOpacity, button->GetTargetOpacity());
-
-  model_->controller.quiescent = false;
-  OnBeginFrame();
-  EXPECT_EQ(kRepositionButtonMidOpacity, button->GetTargetOpacity());
-
-  button->OnHoverEnter({0, 0});
-  OnBeginFrame();
-  EXPECT_EQ(kRepositionButtonMaxOpacity, button->GetTargetOpacity());
-
-  // If hovered, the button should remain visible, even the controller is
-  // quiescent.
-  model_->controller.quiescent = true;
-  OnBeginFrame();
-  EXPECT_EQ(kRepositionButtonMaxOpacity, button->GetTargetOpacity());
-
-  button->OnHoverLeave();
-  OnBeginFrame();
-  EXPECT_EQ(kRepositionButtonMinOpacity, button->GetTargetOpacity());
-}
-
 TEST_F(UiTest, ResetRepositioner) {
   CreateScene(kNotInCct, kNotInWebVr);
 
diff --git a/chrome/browser/vr/vector_icons/daydream_controller_app_button.icon b/chrome/browser/vr/vector_icons/daydream_controller_app_button.icon
index 446554f5..ea1b5d59 100644
--- a/chrome/browser/vr/vector_icons/daydream_controller_app_button.icon
+++ b/chrome/browser/vr/vector_icons/daydream_controller_app_button.icon
@@ -15,5 +15,4 @@
 CUBIC_TO, 36.88f, 27, 38, 25.88f, 38, 24.5f,
 CUBIC_TO, 38, 23.12f, 36.88f, 22, 35.5f, 22,
 LINE_TO, 12.5f, 22,
-CLOSE,
-END
\ No newline at end of file
+CLOSE
diff --git a/chrome/browser/vr/vector_icons/daydream_controller_home_button.icon b/chrome/browser/vr/vector_icons/daydream_controller_home_button.icon
index aac6e7a..59a3cabd 100644
--- a/chrome/browser/vr/vector_icons/daydream_controller_home_button.icon
+++ b/chrome/browser/vr/vector_icons/daydream_controller_home_button.icon
@@ -19,5 +19,4 @@
 CUBIC_TO, 16, 19.58f, 19.58f, 16, 24, 16,
 CUBIC_TO, 28.42f, 16, 32, 19.58f, 32, 24,
 CUBIC_TO, 32, 28.42f, 28.42f, 32, 24, 32,
-CLOSE,
-END
\ No newline at end of file
+CLOSE
diff --git a/chrome/browser/vr/vector_icons/file_download_done.icon b/chrome/browser/vr/vector_icons/file_download_done.icon
index d5c94e4..6bc679b 100644
--- a/chrome/browser/vr/vector_icons/file_download_done.icon
+++ b/chrome/browser/vr/vector_icons/file_download_done.icon
@@ -16,5 +16,4 @@
 LINE_TO, 17, 4,
 R_LINE_TO, 2, 2,
 R_LINE_TO, -9.4f, 9.3f,
-CLOSE,
-END
\ No newline at end of file
+CLOSE
diff --git a/chrome/browser/vr/vector_icons/reposition.icon b/chrome/browser/vr/vector_icons/reposition.icon
index a703388..3476931 100644
--- a/chrome/browser/vr/vector_icons/reposition.icon
+++ b/chrome/browser/vr/vector_icons/reposition.icon
@@ -38,5 +38,4 @@
 R_LINE_TO, 5, -5,
 R_H_LINE_TO, -3,
 R_V_LINE_TO, -3,
-CLOSE,
-END
+CLOSE
diff --git a/chrome/browser/vr/vector_icons/sad_tab.icon b/chrome/browser/vr/vector_icons/sad_tab.icon
index 9e3e3ddd..69a69c6 100644
--- a/chrome/browser/vr/vector_icons/sad_tab.icon
+++ b/chrome/browser/vr/vector_icons/sad_tab.icon
@@ -44,5 +44,4 @@
 LINE_TO, 28, 23,
 LINE_TO, 28, 18,
 LINE_TO, 28, 18,
-CLOSE,
-END
+CLOSE
diff --git a/chrome/browser/webshare/share_service_impl.cc b/chrome/browser/webshare/share_service_impl.cc
index 81757c03..d785f94 100644
--- a/chrome/browser/webshare/share_service_impl.cc
+++ b/chrome/browser/webshare/share_service_impl.cc
@@ -9,7 +9,6 @@
 #include <map>
 #include <utility>
 
-#include "base/strings/strcat.h"
 #include "base/strings/string_util.h"
 #include "chrome/browser/engagement/site_engagement_service.h"
 #include "chrome/browser/profiles/profile.h"
@@ -21,81 +20,8 @@
 #include "chrome/browser/webshare/webshare_target.h"
 #include "chrome/common/pref_names.h"
 #include "components/prefs/pref_service.h"
+#include "content/public/common/manifest_share_target_util.h"
 #include "mojo/public/cpp/bindings/strong_binding.h"
-#include "net/base/escape.h"
-
-namespace {
-
-// Determines whether a character is allowed in a URL template placeholder.
-bool IsIdentifier(char c) {
-  return base::IsAsciiAlpha(c) || base::IsAsciiDigit(c) || c == '-' || c == '_';
-}
-
-// Returns to |out| the result of running the "replace placeholders" algorithm
-// on |template_string|. The algorithm is specified at
-// https://wicg.github.io/web-share-target/#dfn-replace-placeholders
-bool ReplacePlaceholders(base::StringPiece template_string,
-                         base::StringPiece title,
-                         base::StringPiece text,
-                         const GURL& share_url,
-                         std::string* out) {
-  constexpr char kTitlePlaceholder[] = "title";
-  constexpr char kTextPlaceholder[] = "text";
-  constexpr char kUrlPlaceholder[] = "url";
-
-  std::map<base::StringPiece, std::string> placeholder_to_data;
-  placeholder_to_data[kTitlePlaceholder] =
-      net::EscapeQueryParamValue(title, false);
-  placeholder_to_data[kTextPlaceholder] =
-      net::EscapeQueryParamValue(text, false);
-  placeholder_to_data[kUrlPlaceholder] =
-      net::EscapeQueryParamValue(share_url.spec(), false);
-
-  std::vector<base::StringPiece> split_template;
-  bool last_saw_open = false;
-  size_t start_index_to_copy = 0;
-  for (size_t i = 0; i < template_string.size(); ++i) {
-    if (last_saw_open) {
-      if (template_string[i] == '}') {
-        base::StringPiece placeholder = template_string.substr(
-            start_index_to_copy + 1, i - 1 - start_index_to_copy);
-        auto it = placeholder_to_data.find(placeholder);
-        if (it != placeholder_to_data.end()) {
-          // Replace the placeholder text with the parameter value.
-          split_template.push_back(it->second);
-        }
-
-        last_saw_open = false;
-        start_index_to_copy = i + 1;
-      } else if (!IsIdentifier(template_string[i])) {
-        // Error: Non-identifier character seen after open.
-        return false;
-      }
-    } else {
-      if (template_string[i] == '}') {
-        // Error: Saw close, with no corresponding open.
-        return false;
-      } else if (template_string[i] == '{') {
-        split_template.push_back(template_string.substr(
-            start_index_to_copy, i - start_index_to_copy));
-
-        last_saw_open = true;
-        start_index_to_copy = i;
-      }
-    }
-  }
-  if (last_saw_open) {
-    // Error: Saw open that was never closed.
-    return false;
-  }
-  split_template.push_back(template_string.substr(
-      start_index_to_copy, template_string.size() - start_index_to_copy));
-
-  *out = base::StrCat(split_template);
-  return true;
-}
-
-}  // namespace
 
 ShareServiceImpl::ShareServiceImpl() : weak_factory_(this) {}
 ShareServiceImpl::~ShareServiceImpl() = default;
@@ -106,32 +32,6 @@
                           std::move(request));
 }
 
-// static
-bool ShareServiceImpl::ReplaceUrlPlaceholders(const GURL& url_template,
-                                              base::StringPiece title,
-                                              base::StringPiece text,
-                                              const GURL& share_url,
-                                              GURL* url_template_filled) {
-  std::string new_query;
-  std::string new_ref;
-  if (!ReplacePlaceholders(url_template.query_piece(), title, text, share_url,
-                           &new_query) ||
-      !ReplacePlaceholders(url_template.ref_piece(), title, text, share_url,
-                           &new_ref)) {
-    return false;
-  }
-
-  // Check whether |url_template| has a query in order to preserve the '?' in a
-  // URL with an empty query. e.g. http://www.google.com/?
-  GURL::Replacements url_replacements;
-  if (url_template.has_query())
-    url_replacements.SetQueryStr(new_query);
-  if (url_template.has_ref())
-    url_replacements.SetRefStr(new_ref);
-  *url_template_filled = url_template.ReplaceComponents(url_replacements);
-  return true;
-}
-
 void ShareServiceImpl::ShowPickerDialog(
     std::vector<WebShareTarget> targets,
     chrome::WebShareTargetPickerCallback callback) {
@@ -223,8 +123,9 @@
   }
 
   GURL url_template_filled;
-  if (!ReplaceUrlPlaceholders(result->url_template(), title, text, share_url,
-                              &url_template_filled)) {
+  if (!content::ReplaceWebShareUrlPlaceholders(result->url_template(), title,
+                                               text, share_url,
+                                               &url_template_filled)) {
     // TODO(mgiuca): This error should not be possible at share time, because
     // targets with invalid templates should not be chooseable. Fix
     // https://crbug.com/694380 and replace this with a DCHECK.
diff --git a/chrome/browser/webshare/share_service_impl.h b/chrome/browser/webshare/share_service_impl.h
index 0db65fd..1ac4eccd 100644
--- a/chrome/browser/webshare/share_service_impl.h
+++ b/chrome/browser/webshare/share_service_impl.h
@@ -39,12 +39,6 @@
              ShareCallback callback) override;
 
  private:
-  FRIEND_TEST_ALL_PREFIXES(ShareServiceImplUnittest,
-                           ReplaceUrlPlaceholdersInvalidTemplate);
-  FRIEND_TEST_ALL_PREFIXES(ShareServiceImplUnittest, ReplaceUrlPlaceholders);
-  FRIEND_TEST_ALL_PREFIXES(ShareServiceImplUnittest,
-                           ReplaceUrlPlaceholders_Escaping);
-
   Browser* GetBrowser();
 
   // Returns the URL template of the target identified by |target_url|
@@ -73,20 +67,6 @@
   // with the user.
   std::vector<WebShareTarget> GetTargetsWithSufficientEngagement();
 
-  // Writes to |url_template_filled|, a copy of |url_template| with all
-  // instances of "{title}", "{text}", and "{url}" in the query and fragment
-  // parts of the URL replaced with |title|, |text|, and |url| respectively.
-  // Replaces instances of "{X}" where "X" is any string besides "title",
-  // "text", and "url", with an empty string, for forwards compatibility.
-  // Returns false, if there are badly nested placeholders.
-  // This includes any case in which two "{" occur before a "}", or a "}"
-  // occurs with no preceding "{".
-  static bool ReplaceUrlPlaceholders(const GURL& url_template,
-                                     base::StringPiece title,
-                                     base::StringPiece text,
-                                     const GURL& share_url,
-                                     GURL* url_template_filled);
-
   void OnPickerClosed(const std::string& title,
                       const std::string& text,
                       const GURL& share_url,
diff --git a/chrome/browser/webshare/share_service_impl_unittest.cc b/chrome/browser/webshare/share_service_impl_unittest.cc
index 998dab0..bf3dcd7 100644
--- a/chrome/browser/webshare/share_service_impl_unittest.cc
+++ b/chrome/browser/webshare/share_service_impl_unittest.cc
@@ -380,240 +380,3 @@
   // Pick example-low.com.
   std::move(picker_callback).Run(&expected_targets[0]);
 }
-
-TEST_F(ShareServiceImplUnittest, ReplaceUrlPlaceholdersInvalidTemplate) {
-  const GURL kUrl(kUrlSpec);
-  GURL url_template_filled;
-
-  // Badly nested placeholders.
-  GURL url_template = GURL("http://example.com/?q={");
-  bool succeeded = ShareServiceImpl::ReplaceUrlPlaceholders(
-      url_template, kTitle, kText, kUrl, &url_template_filled);
-  EXPECT_FALSE(succeeded);
-
-  url_template = GURL("http://example.com/?q={title");
-  succeeded = ShareServiceImpl::ReplaceUrlPlaceholders(
-      url_template, kTitle, kText, kUrl, &url_template_filled);
-  EXPECT_FALSE(succeeded);
-
-  url_template = GURL("http://example.com/?q={title{text}}");
-  succeeded = ShareServiceImpl::ReplaceUrlPlaceholders(
-      url_template, kTitle, kText, kUrl, &url_template_filled);
-  EXPECT_FALSE(succeeded);
-
-  url_template = GURL("http://example.com/?q={title{}");
-  succeeded = ShareServiceImpl::ReplaceUrlPlaceholders(
-      url_template, kTitle, kText, kUrl, &url_template_filled);
-  EXPECT_FALSE(succeeded);
-
-  url_template = GURL("http://example.com/?q={{title}}");
-  succeeded = ShareServiceImpl::ReplaceUrlPlaceholders(
-      url_template, kTitle, kText, kUrl, &url_template_filled);
-  EXPECT_FALSE(succeeded);
-
-  // Placeholder with non-identifier character.
-  url_template = GURL("http://example.com/?q={title?}");
-  succeeded = ShareServiceImpl::ReplaceUrlPlaceholders(
-      url_template, kTitle, kText, kUrl, &url_template_filled);
-  EXPECT_FALSE(succeeded);
-
-  // Invalid placeholder in URL fragment.
-  url_template = GURL("http://example.com/#{title?}");
-  succeeded = ShareServiceImpl::ReplaceUrlPlaceholders(
-      url_template, kTitle, kText, kUrl, &url_template_filled);
-  EXPECT_FALSE(succeeded);
-}
-
-TEST_F(ShareServiceImplUnittest, ReplaceUrlPlaceholders) {
-  const GURL kUrl(kUrlSpec);
-
-  // No placeholders.
-  GURL url_template = GURL("http://example.com/?q=a#a");
-  GURL url_template_filled;
-  bool succeeded = ShareServiceImpl::ReplaceUrlPlaceholders(
-      url_template, kTitle, kText, kUrl, &url_template_filled);
-  EXPECT_TRUE(succeeded);
-  EXPECT_EQ(url_template, url_template_filled);
-
-  // Empty |url_template|
-  url_template = GURL();
-  succeeded = ShareServiceImpl::ReplaceUrlPlaceholders(
-      url_template, kTitle, kText, kUrl, &url_template_filled);
-  EXPECT_TRUE(succeeded);
-  EXPECT_EQ(GURL(), url_template_filled);
-
-  // One title placeholder.
-  url_template = GURL("http://example.com/#{title}");
-  succeeded = ShareServiceImpl::ReplaceUrlPlaceholders(
-      url_template, kTitle, kText, kUrl, &url_template_filled);
-  EXPECT_TRUE(succeeded);
-  EXPECT_EQ("http://example.com/#My%20title", url_template_filled.spec());
-
-  // One text placeholder.
-  url_template = GURL("http://example.com/#{text}");
-  succeeded = ShareServiceImpl::ReplaceUrlPlaceholders(
-      url_template, kTitle, kText, kUrl, &url_template_filled);
-  EXPECT_TRUE(succeeded);
-  EXPECT_EQ("http://example.com/#My%20text", url_template_filled.spec());
-
-  // One url placeholder.
-  url_template = GURL("http://example.com/#{url}");
-  succeeded = ShareServiceImpl::ReplaceUrlPlaceholders(
-      url_template, kTitle, kText, kUrl, &url_template_filled);
-  EXPECT_TRUE(succeeded);
-  EXPECT_EQ("http://example.com/#https%3A%2F%2Fwww.google.com%2F",
-            url_template_filled.spec());
-
-  // One of each placeholder, in title, text, url order.
-  url_template = GURL("http://example.com/#{title}{text}{url}");
-  succeeded = ShareServiceImpl::ReplaceUrlPlaceholders(
-      url_template, kTitle, kText, kUrl, &url_template_filled);
-  EXPECT_TRUE(succeeded);
-  EXPECT_EQ(
-      "http://example.com/#My%20titleMy%20texthttps%3A%2F%2Fwww.google.com%2F",
-      url_template_filled.spec());
-
-  // One of each placeholder, in url, text, title order.
-  url_template = GURL("http://example.com/#{url}{text}{title}");
-  succeeded = ShareServiceImpl::ReplaceUrlPlaceholders(
-      url_template, kTitle, kText, kUrl, &url_template_filled);
-  EXPECT_TRUE(succeeded);
-  EXPECT_EQ(
-      "http://example.com/#https%3A%2F%2Fwww.google.com%2FMy%20textMy%20title",
-      url_template_filled.spec());
-
-  // Two of each placeholder, some next to each other, others not.
-  url_template =
-      GURL("http://example.com/#{title}{url}{text}{text}{title}{url}");
-  succeeded = ShareServiceImpl::ReplaceUrlPlaceholders(
-      url_template, kTitle, kText, kUrl, &url_template_filled);
-  EXPECT_TRUE(succeeded);
-  EXPECT_EQ(
-      "http://example.com/"
-      "#My%20titlehttps%3A%2F%2Fwww.google.com%2FMy%20textMy%20textMy%"
-      "20titlehttps%3A%2F%2Fwww.google.com%2F",
-      url_template_filled.spec());
-
-  // Placeholders are in a query string, as values. The expected use case.
-  // Two of each placeholder, some next to each other, others not.
-  url_template = GURL(
-      "http://example.com?title={title}&url={url}&text={text}&text={text}&"
-      "title={title}&url={url}");
-  succeeded = ShareServiceImpl::ReplaceUrlPlaceholders(
-      url_template, kTitle, kText, kUrl, &url_template_filled);
-  EXPECT_TRUE(succeeded);
-  EXPECT_EQ(
-      "http://"
-      "example.com/?title=My%20title&url=https%3A%2F%2Fwww.google.com%2F&"
-      "text=My%20text&"
-      "text=My%20text&title=My%20title&url=https%3A%2F%2Fwww.google.com%2F",
-      url_template_filled.spec());
-
-  // Placeholder with digit character.
-  url_template = GURL("http://example.com/#{title1}");
-  succeeded = ShareServiceImpl::ReplaceUrlPlaceholders(
-      url_template, kTitle, kText, kUrl, &url_template_filled);
-  EXPECT_TRUE(succeeded);
-  EXPECT_EQ("http://example.com/#", url_template_filled.spec());
-
-  // Empty placeholder.
-  url_template = GURL("http://example.com/#{}");
-  succeeded = ShareServiceImpl::ReplaceUrlPlaceholders(
-      url_template, kTitle, kText, kUrl, &url_template_filled);
-  EXPECT_TRUE(succeeded);
-  EXPECT_EQ("http://example.com/#", url_template_filled.spec());
-
-  // Unexpected placeholders.
-  url_template = GURL("http://example.com/#{nonexistentplaceholder}");
-  succeeded = ShareServiceImpl::ReplaceUrlPlaceholders(
-      url_template, kTitle, kText, kUrl, &url_template_filled);
-  EXPECT_TRUE(succeeded);
-  EXPECT_EQ("http://example.com/#", url_template_filled.spec());
-
-  // Placeholders should only be replaced in query and fragment.
-  url_template = GURL("http://example.com/subpath{title}/?q={title}#{title}");
-  succeeded = ShareServiceImpl::ReplaceUrlPlaceholders(
-      url_template, kTitle, kText, kUrl, &url_template_filled);
-  EXPECT_TRUE(succeeded);
-  EXPECT_EQ("http://example.com/subpath%7Btitle%7D/?q=My%20title#My%20title",
-            url_template_filled.spec());
-
-  // Braces in the path, which would be invalid, but should parse fine as they
-  // are escaped.
-  url_template = GURL("http://example.com/subpath{/?q={title}");
-  succeeded = ShareServiceImpl::ReplaceUrlPlaceholders(
-      url_template, kTitle, kText, kUrl, &url_template_filled);
-  EXPECT_TRUE(succeeded);
-  EXPECT_EQ("http://example.com/subpath%7B/?q=My%20title",
-            url_template_filled.spec());
-
-  // |url_template| with % escapes.
-  url_template = GURL("http://example.com#%20{title}%20");
-  succeeded = ShareServiceImpl::ReplaceUrlPlaceholders(
-      url_template, kTitle, kText, kUrl, &url_template_filled);
-  EXPECT_TRUE(succeeded);
-  EXPECT_EQ("http://example.com/#%20My%20title%20", url_template_filled.spec());
-}
-
-// Test URL escaping done by ReplaceUrlPlaceholders().
-TEST_F(ShareServiceImplUnittest, ReplaceUrlPlaceholders_Escaping) {
-  const GURL kUrl(kUrlSpec);
-  const GURL kUrlTemplate("http://example.com/#{title}");
-
-  // Share data that contains percent escapes.
-  GURL url_template_filled;
-  bool succeeded = ShareServiceImpl::ReplaceUrlPlaceholders(
-      kUrlTemplate, "My%20title", kText, kUrl, &url_template_filled);
-  EXPECT_TRUE(succeeded);
-  EXPECT_EQ("http://example.com/#My%2520title", url_template_filled.spec());
-
-  // Share data that contains placeholders. These should not be replaced.
-  succeeded = ShareServiceImpl::ReplaceUrlPlaceholders(
-      kUrlTemplate, "{title}", kText, kUrl, &url_template_filled);
-  EXPECT_TRUE(succeeded);
-  EXPECT_EQ("http://example.com/#%7Btitle%7D", url_template_filled.spec());
-
-  // All characters that shouldn't be escaped.
-  succeeded = ShareServiceImpl::ReplaceUrlPlaceholders(
-      kUrlTemplate,
-      "-_.!~*'()0123456789"
-      "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
-      "abcdefghijklmnopqrstuvwxyz",
-      kText, kUrl, &url_template_filled);
-  EXPECT_TRUE(succeeded);
-  EXPECT_EQ(
-      "http://example.com/#-_.!~*'()0123456789"
-      "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
-      "abcdefghijklmnopqrstuvwxyz",
-      url_template_filled.spec());
-
-  // All characters that should be escaped.
-  succeeded = ShareServiceImpl::ReplaceUrlPlaceholders(
-      kUrlTemplate, " \"#$%&+,/:;<=>?@[\\]^`{|}", kText, kUrl,
-      &url_template_filled);
-  EXPECT_TRUE(succeeded);
-  EXPECT_EQ(
-      "http://example.com/"
-      "#%20%22%23%24%25%26%2B%2C%2F%3A%3B%3C%3D%3E%3F%40%5B%5C%5D%5E%60%7B%7C%"
-      "7D",
-      url_template_filled.spec());
-
-  // Unicode chars.
-  // U+263B
-  succeeded = ShareServiceImpl::ReplaceUrlPlaceholders(
-      kUrlTemplate, "\xe2\x98\xbb", kText, kUrl, &url_template_filled);
-  EXPECT_TRUE(succeeded);
-  EXPECT_EQ("http://example.com/#%E2%98%BB", url_template_filled.spec());
-
-  // U+00E9
-  succeeded = ShareServiceImpl::ReplaceUrlPlaceholders(
-      kUrlTemplate, "\xc3\xa9", kText, kUrl, &url_template_filled);
-  EXPECT_TRUE(succeeded);
-  EXPECT_EQ("http://example.com/#%C3%A9", url_template_filled.spec());
-
-  // U+1F4A9
-  succeeded = ShareServiceImpl::ReplaceUrlPlaceholders(
-      kUrlTemplate, "\xf0\x9f\x92\xa9", kText, kUrl, &url_template_filled);
-  EXPECT_TRUE(succeeded);
-  EXPECT_EQ("http://example.com/#%F0%9F%92%A9", url_template_filled.spec());
-}
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 9043946..12b8b0ca 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -2851,6 +2851,7 @@
       "../browser/media/router/discovery/discovery_network_monitor_unittest.cc",
       "../browser/media/webrtc/tab_desktop_media_list_unittest.cc",
       "../browser/media/webrtc/webrtc_event_log_manager_unittest.cc",
+      "../browser/media/webrtc/webrtc_event_log_uploader_impl_unittest.cc",
       "../browser/media_galleries/fileapi/native_media_file_util_unittest.cc",
       "../browser/media_galleries/gallery_watch_manager_unittest.cc",
       "../browser/media_galleries/mac/mtp_device_delegate_impl_mac_unittest.mm",
@@ -4908,6 +4909,11 @@
     }
 
     if (is_mac) {
+      sources += [
+        "base/interactive_test_utils_cocoa.h",
+        "base/interactive_test_utils_cocoa.mm",
+      ]
+
       data_deps += [
         "//chrome",
         "//chrome:chrome_framework",
@@ -4922,7 +4928,6 @@
           "../browser/ui/cocoa/extensions/browser_action_button_interactive_uitest.mm",
           "../browser/ui/cocoa/permission_bubble/permission_bubble_cocoa_interactive_uitest.mm",
           "../browser/ui/cocoa/translate/translate_bubble_test_utils_views_cocoa.mm",
-          "base/interactive_test_utils_cocoa.mm",
         ]
       }
     }
diff --git a/chrome/test/base/interactive_test_utils_cocoa.h b/chrome/test/base/interactive_test_utils_cocoa.h
new file mode 100644
index 0000000..9bd2407
--- /dev/null
+++ b/chrome/test/base/interactive_test_utils_cocoa.h
@@ -0,0 +1,27 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_TEST_BASE_INTERACTIVE_TEST_UTILS_COCOA_H_
+#define CHROME_TEST_BASE_INTERACTIVE_TEST_UTILS_COCOA_H_
+
+#include "chrome/browser/ui/view_ids.h"
+
+class Browser;
+
+namespace ui_test_utils {
+namespace internal {
+
+// Returns true of |vid| in |browser| is focused.
+bool IsViewFocusedCocoa(const Browser* browser, ViewID vid);
+
+// Simulates a mouse click on |vid| in |browser|.
+void ClickOnViewCocoa(const Browser* browser, ViewID vid);
+
+// Moves focus to |vid| in |browser|
+void FocusViewCocoa(const Browser* browser, ViewID vid);
+
+}  // namespace internal
+}  // namespace ui_test_utils
+
+#endif  // CHROME_TEST_BASE_INTERACTIVE_TEST_UTILS_COCOA_H_
diff --git a/chrome/test/base/interactive_test_utils_cocoa.mm b/chrome/test/base/interactive_test_utils_cocoa.mm
index 7743d9eb..ab1c185 100644
--- a/chrome/test/base/interactive_test_utils_cocoa.mm
+++ b/chrome/test/base/interactive_test_utils_cocoa.mm
@@ -2,21 +2,26 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/test/base/interactive_test_utils.h"
+#include "chrome/test/base/interactive_test_utils_cocoa.h"
 
 #import <Cocoa/Cocoa.h>
 
 #include "base/bind.h"
 #include "base/logging.h"
 #include "base/message_loop/message_loop.h"
+#include "build/buildflag.h"
 #include "chrome/app/chrome_command_ids.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_window.h"
 #import "chrome/browser/ui/cocoa/view_id_util.h"
+#include "chrome/test/base/interactive_test_utils.h"
 #include "ui/base/cocoa/cocoa_base_utils.h"
+#include "ui/base/ui_features.h"
 
 namespace ui_test_utils {
 
+namespace internal {
+
 namespace {
 
 void MoveMouseToNSViewCenterAndPress(
@@ -43,7 +48,7 @@
 
 }  // namespace
 
-bool IsViewFocused(const Browser* browser, ViewID vid) {
+bool IsViewFocusedCocoa(const Browser* browser, ViewID vid) {
   NSWindow* window = browser->window()->GetNativeWindow();
   DCHECK(window);
   NSView* view = view_id_util::GetView(window, vid);
@@ -72,7 +77,7 @@
   return false;
 }
 
-void ClickOnView(const Browser* browser, ViewID vid) {
+void ClickOnViewCocoa(const Browser* browser, ViewID vid) {
   NSWindow* window = browser->window()->GetNativeWindow();
   DCHECK(window);
   NSView* view = view_id_util::GetView(window, vid);
@@ -85,12 +90,28 @@
   content::RunMessageLoop();
 }
 
+void FocusViewCocoa(const Browser* browser, ViewID vid) {
+  NSWindow* window = browser->window()->GetNativeWindow();
+  DCHECK(window);
+  NSView* view = view_id_util::GetView(window, vid);
+  DCHECK(view);
+  [window makeFirstResponder:view];
+}
+
+}  // namespace internal
+
+#if !BUILDFLAG(MAC_VIEWS_BROWSER)
+bool IsViewFocused(const Browser* browser, ViewID vid) {
+  return internal::IsViewFocusedCocoa(browser, vid);
+}
+
+void ClickOnView(const Browser* browser, ViewID vid) {
+  internal::ClickOnViewCocoa(browser, vid);
+}
+
 void FocusView(const Browser* browser, ViewID vid) {
-   NSWindow* window = browser->window()->GetNativeWindow();
-   DCHECK(window);
-   NSView* view = view_id_util::GetView(window, vid);
-   DCHECK(view);
-   [window makeFirstResponder:view];
- }
+  internal::FocusViewCocoa(browser, vid);
+}
+#endif  // !BUILDFLAG(MAC_VIEWS_BROWSER)
 
 }  // namespace ui_test_utils
diff --git a/chrome/test/base/interactive_test_utils_views.cc b/chrome/test/base/interactive_test_utils_views.cc
index f1dce9d..5388a78f 100644
--- a/chrome/test/base/interactive_test_utils_views.cc
+++ b/chrome/test/base/interactive_test_utils_views.cc
@@ -5,13 +5,25 @@
 #include "chrome/test/base/interactive_test_utils.h"
 
 #include "base/message_loop/message_loop.h"
+#include "build/buildflag.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
+#include "chrome/browser/ui/views_mode_controller.h"
+#include "ui/base/ui_features.h"
 #include "ui/views/focus/focus_manager.h"
 
+#if BUILDFLAG(MAC_VIEWS_BROWSER)
+#include "chrome/test/base/interactive_test_utils_cocoa.h"
+#endif
+
 namespace ui_test_utils {
 
 bool IsViewFocused(const Browser* browser, ViewID vid) {
+#if BUILDFLAG(MAC_VIEWS_BROWSER)
+  if (views_mode_controller::IsViewsBrowserCocoa())
+    return internal::IsViewFocusedCocoa(browser, vid);
+#endif
+
   BrowserWindow* browser_window = browser->window();
   DCHECK(browser_window);
   gfx::NativeWindow window = browser_window->GetNativeWindow();
@@ -25,6 +37,11 @@
 }
 
 void ClickOnView(const Browser* browser, ViewID vid) {
+#if BUILDFLAG(MAC_VIEWS_BROWSER)
+  if (views_mode_controller::IsViewsBrowserCocoa())
+    return internal::ClickOnViewCocoa(browser, vid);
+#endif
+
   views::View* view =
       BrowserView::GetBrowserViewForBrowser(browser)->GetViewByID(vid);
   DCHECK(view);
@@ -35,6 +52,11 @@
 }
 
 void FocusView(const Browser* browser, ViewID vid) {
+#if BUILDFLAG(MAC_VIEWS_BROWSER)
+  if (views_mode_controller::IsViewsBrowserCocoa())
+    return internal::FocusViewCocoa(browser, vid);
+#endif
+
   views::View* view =
       BrowserView::GetBrowserViewForBrowser(browser)->GetViewByID(vid);
   DCHECK(view);
diff --git a/chrome/test/chromedriver/client/command_executor.py b/chrome/test/chromedriver/client/command_executor.py
index dca48d4..a267c39 100644
--- a/chrome/test/chromedriver/client/command_executor.py
+++ b/chrome/test/chromedriver/client/command_executor.py
@@ -62,6 +62,8 @@
   HOVER_OVER_ELEMENT = (_Method.POST, '/session/:sessionId/element/:id/hover')
   GET_ELEMENT_LOCATION = (
       _Method.GET, '/session/:sessionId/element/:id/location')
+  GET_ELEMENT_RECT = (
+      _Method.GET, '/session/:sessionId/element/:id/rect')
   GET_ELEMENT_LOCATION_ONCE_SCROLLED_INTO_VIEW = (
       _Method.GET, '/session/:sessionId/element/:id/location_in_view')
   GET_ELEMENT_SIZE = (_Method.GET, '/session/:sessionId/element/:id/size')
diff --git a/chrome/test/chromedriver/client/webelement.py b/chrome/test/chromedriver/client/webelement.py
index 1e150f38..f1a0796 100644
--- a/chrome/test/chromedriver/client/webelement.py
+++ b/chrome/test/chromedriver/client/webelement.py
@@ -61,5 +61,8 @@
   def GetLocation(self):
     return self._Execute(Command.GET_ELEMENT_LOCATION)
 
+  def GetRect(self):
+    return self._Execute(Command.GET_ELEMENT_RECT)
+
   def IsDisplayed(self):
     return self._Execute(Command.IS_ELEMENT_DISPLAYED)
diff --git a/chrome/test/chromedriver/element_commands.cc b/chrome/test/chromedriver/element_commands.cc
index e5edc7ff..6358b81 100644
--- a/chrome/test/chromedriver/element_commands.cc
+++ b/chrome/test/chromedriver/element_commands.cc
@@ -469,6 +469,58 @@
       value);
 }
 
+Status ExecuteGetElementRect(Session* session,
+                             WebView* web_view,
+                             const std::string& element_id,
+                             const base::DictionaryValue& params,
+                             std::unique_ptr<base::Value>* value) {
+  base::ListValue args;
+  args.Append(CreateElement(element_id));
+
+  std::unique_ptr<base::Value> location;
+  Status status = web_view->CallFunction(
+      session->GetCurrentFrameId(),
+      webdriver::atoms::asString(webdriver::atoms::GET_LOCATION), args,
+      &location);
+  if (status.IsError())
+    return status;
+
+  std::unique_ptr<base::Value> size;
+  web_view->CallFunction(session->GetCurrentFrameId(),
+                         webdriver::atoms::asString(webdriver::atoms::GET_SIZE),
+                         args, &size);
+
+  // do type conversions
+  base::DictionaryValue* size_dict;
+  if (!size->GetAsDictionary(&size_dict))
+    return Status(kUnknownError, "could not convert to DictionaryValue");
+  base::DictionaryValue* location_dict;
+  if (!location->GetAsDictionary(&location_dict))
+    return Status(kUnknownError, "could not convert to DictionaryValue");
+
+  // grab values
+  int x, y, width, height;
+  if (!location_dict->GetInteger("x", &x))
+    return Status(kUnknownError, "getting size failed to return x");
+
+  if (!location_dict->GetInteger("y", &y))
+    return Status(kUnknownError, "getting size failed to return y");
+
+  if (!size_dict->GetInteger("height", &height))
+    return Status(kUnknownError, "getting location failed to return height");
+
+  if (!size_dict->GetInteger("width", &width))
+    return Status(kUnknownError, "getting location failed to return width");
+
+  base::DictionaryValue ret;
+  ret.SetInteger("x", x);
+  ret.SetInteger("y", y);
+  ret.SetInteger("width", width);
+  ret.SetInteger("height", height);
+  value->reset(ret.DeepCopy());
+  return Status(kOk);
+}
+
 Status ExecuteGetElementLocationOnceScrolledIntoView(
     Session* session,
     WebView* web_view,
diff --git a/chrome/test/chromedriver/element_commands.h b/chrome/test/chromedriver/element_commands.h
index 320c3ee..566d29d 100644
--- a/chrome/test/chromedriver/element_commands.h
+++ b/chrome/test/chromedriver/element_commands.h
@@ -161,6 +161,12 @@
                                  const base::DictionaryValue& params,
                                  std::unique_ptr<base::Value>* value);
 
+Status ExecuteGetElementRect(Session* session,
+                             WebView* web_view,
+                             const std::string& element_id,
+                             const base::DictionaryValue& params,
+                             std::unique_ptr<base::Value>* value);
+
 // Returns the location of a given element in client coordinates, after
 // scrolling it into view.
 Status ExecuteGetElementLocationOnceScrolledIntoView(
diff --git a/chrome/test/chromedriver/server/http_handler.cc b/chrome/test/chromedriver/server/http_handler.cc
index 9374edda..25a7bfa 100644
--- a/chrome/test/chromedriver/server/http_handler.cc
+++ b/chrome/test/chromedriver/server/http_handler.cc
@@ -318,6 +318,9 @@
                      WrapToCommand("GetElementLocation",
                                    base::Bind(&ExecuteGetElementLocation))),
       CommandMapping(
+          kGet, "session/:sessionId/element/:id/rect",
+          WrapToCommand("GetElementRect", base::Bind(&ExecuteGetElementRect))),
+      CommandMapping(
           kGet, "session/:sessionId/element/:id/location_in_view",
           WrapToCommand(
               "GetElementLocationInView",
diff --git a/chrome/test/chromedriver/test/run_py_tests.py b/chrome/test/chromedriver/test/run_py_tests.py
index eec3f7d..c16322f 100755
--- a/chrome/test/chromedriver/test/run_py_tests.py
+++ b/chrome/test/chromedriver/test/run_py_tests.py
@@ -1362,6 +1362,16 @@
     self._driver.TouchUp(location['x'] + 1, location['y'] + 1)
     self.assertEquals('events: touchstart touchmove touchend', events.GetText())
 
+  def testGetElementRect(self):
+    self._driver.Load(self.GetHttpUrlForFile(
+        '/chromedriver/absolute_position_element.html'))
+    target = self._driver.FindElement('id', 'target')
+    rect = target.GetRect()
+    self.assertEquals(18, rect['x'])
+    self.assertEquals(10, rect['y'])
+    self.assertEquals(200, rect['height'])
+    self.assertEquals(210, rect['width'])
+
   def testTouchScrollElement(self):
     self._driver.Load(self.GetHttpUrlForFile(
         '/chromedriver/touch_action_tests.html'))
diff --git a/chrome/test/data/chromedriver/absolute_position_element.html b/chrome/test/data/chromedriver/absolute_position_element.html
new file mode 100644
index 0000000..1d00a4a
--- /dev/null
+++ b/chrome/test/data/chromedriver/absolute_position_element.html
@@ -0,0 +1,6 @@
+<!DOCTYPE html>
+<html>
+  <body>
+    <div x="80px" y="10px" style="position: absolute; left: 18px; top: 10px; width: 210px; height: 200px;" type="text" id="target">
+  </body>
+</html>
diff --git a/chrome/test/data/plugin_power_saver/poster_tests.html b/chrome/test/data/plugin_power_saver/poster_tests.html
index 0bfefb4..c9afb75 100644
--- a/chrome/test/data/plugin_power_saver/poster_tests.html
+++ b/chrome/test/data/plugin_power_saver/poster_tests.html
@@ -1,3 +1,10 @@
+<head>
+  <style>
+    * {
+      line-height: 18px;
+    }
+  </style>
+</head>
 <object id='plugin_src' type='application/x-shockwave-flash' width='100'
     height='100' poster='click_me.png'></object>
 <object id='plugin_srcset' type='application/x-shockwave-flash' width='100'
diff --git a/chrome/test/data/plugin_power_saver/small_cross_origin.html b/chrome/test/data/plugin_power_saver/small_cross_origin.html
index 432ddcf..340f521 100644
--- a/chrome/test/data/plugin_power_saver/small_cross_origin.html
+++ b/chrome/test/data/plugin_power_saver/small_cross_origin.html
@@ -1,3 +1,10 @@
+<head>
+  <style>
+    * {
+      line-height: 18px;
+    }
+  </style>
+</head>
 <object id='plugin' data='http://otherorigin.com/fake.swf'
     type='application/x-shockwave-flash' width='400' height='100'></object>
 <br>
diff --git a/chrome/test/media_router/media_router_integration_browsertest.cc b/chrome/test/media_router/media_router_integration_browsertest.cc
index 69e5aca..afa3c9f4 100644
--- a/chrome/test/media_router/media_router_integration_browsertest.cc
+++ b/chrome/test/media_router/media_router_integration_browsertest.cc
@@ -887,8 +887,9 @@
   RunBasicTest();
 }
 
+// TODO(crbug.com/822300): Flaky test.
 IN_PROC_BROWSER_TEST_F(MediaRouterIntegrationIncognitoBrowserTest,
-                       ReconnectSession) {
+                       MANUAL_ReconnectSession) {
   RunReconnectSessionTest();
 }
 
diff --git a/components/BUILD.gn b/components/BUILD.gn
index 16f332d..7166a3b 100644
--- a/components/BUILD.gn
+++ b/components/BUILD.gn
@@ -581,5 +581,15 @@
         deps += [ "//v8:v8_external_startup_data_assets" ]
       }
     }
+
+    if (!is_android) {
+      sources += [ "safe_browsing/db/v4_store_perftest.cc" ]
+      deps += [
+        "//components/safe_browsing/db:v4_protocol_manager_util",
+        "//components/safe_browsing/db:v4_store",
+        "//components/safe_browsing/db:v4_test_util",
+        "//crypto",
+      ]
+    }
   }
 }
diff --git a/components/arc/common/usb_host.mojom b/components/arc/common/usb_host.mojom
index d47e6df7..a08aecb9 100644
--- a/components/arc/common/usb_host.mojom
+++ b/components/arc/common/usb_host.mojom
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// Next MinVersion: 1
+// Next MinVersion: 2
 module arc.mojom;
 
 // re-use device.mojom.UsbDeviceInfo
@@ -10,11 +10,14 @@
 
 // Next method ID: 3
 interface UsbHostHost {
-  // Tries the open the USB device node for the device named 'guid'
-  // and returns an open file descriptor to this node.
-  // You need to have previously called RequestPermission for this 'guid'
-  // else this call will fail.
-  OpenDevice@0(string guid) => (handle usb_fd);
+  // Tries to open the USB device node for the device named 'guid' for caller
+  // 'pkg_name' and returns an open file descriptor to this node. 'pkg_name'
+  // needs to have previously called RequestPermission for this 'guid' else this
+  // call will fail. Note the 'pkg_name' is informational purposes only, there
+  // is no effective way that host can restrict access to only a specific
+  // package at the security boundary formed by this Mojo interface.
+  OpenDevice@0(string guid,
+               [Minversion=1] string? pkg_name) => (handle usb_fd);
 
   // Returns the USB device descriptors for the device named 'guid'.
   GetDeviceInfo@1(string guid) => (string device_name,
diff --git a/components/arc/usb/usb_host_bridge.cc b/components/arc/usb/usb_host_bridge.cc
index 1a00796..2aed8b9 100644
--- a/components/arc/usb/usb_host_bridge.cc
+++ b/components/arc/usb/usb_host_bridge.cc
@@ -120,14 +120,14 @@
                                          RequestPermissionCallback callback) {
   VLOG(2) << "USB RequestPermission " << guid << " package " << package;
   // Permission already requested.
-  if (HasPermissionForDevice(guid)) {
+  if (HasPermissionForDevice(guid, package)) {
     std::move(callback).Run(true);
     return;
   }
 
   // The other side was just checking, fail without asking the user.
   if (!interactive) {
-    std::move(callback).Run(false);
+    std::move(callback).Run(HasPermissionForDevice(guid, package));
     return;
   }
 
@@ -136,8 +136,9 @@
 }
 
 void ArcUsbHostBridge::OpenDevice(const std::string& guid,
+                                  const base::Optional<std::string>& package,
                                   OpenDeviceCallback callback) {
-  if (!usb_service_) {
+  if (!usb_service_ || !package) {
     std::move(callback).Run(mojo::ScopedHandle());
     return;
   }
@@ -150,7 +151,7 @@
   }
 
   // The RequestPermission was never done, abort.
-  if (!HasPermissionForDevice(guid)) {
+  if (!HasPermissionForDevice(guid, package.value())) {
     std::move(callback).Run(mojo::ScopedHandle());
     return;
   }
@@ -297,10 +298,23 @@
       std::move(callback));
 }
 
-bool ArcUsbHostBridge::HasPermissionForDevice(const std::string& guid) {
-  // TODO(lgcheng): implement permission settings
-  // fail close for now
-  return false;
+bool ArcUsbHostBridge::HasPermissionForDevice(const std::string& guid,
+                                              const std::string& package) {
+  if (!ui_delegate_)
+    return false;
+
+  if (!usb_service_)
+    return false;
+
+  scoped_refptr<device::UsbDevice> device = usb_service_->GetDevice(guid);
+  if (!device.get()) {
+    LOG(WARNING) << "Unknown USB device " << guid;
+    return false;
+  }
+
+  return ui_delegate_->HasUsbAccessPermission(
+      package, guid, device->serial_number(), device->vendor_id(),
+      device->product_id());
 }
 
 }  // namespace arc
diff --git a/components/arc/usb/usb_host_bridge.h b/components/arc/usb/usb_host_bridge.h
index f5490349..df88128f 100644
--- a/components/arc/usb/usb_host_bridge.h
+++ b/components/arc/usb/usb_host_bridge.h
@@ -54,6 +54,7 @@
                          bool interactive,
                          RequestPermissionCallback callback) override;
   void OpenDevice(const std::string& guid,
+                  const base::Optional<std::string>& package,
                   OpenDeviceCallback callback) override;
   void GetDeviceInfo(const std::string& guid,
                      GetDeviceInfoCallback callback) override;
@@ -77,7 +78,8 @@
   void DoRequestUserAuthorization(const std::string& guid,
                                   const std::string& package,
                                   RequestPermissionCallback callback);
-  bool HasPermissionForDevice(const std::string& guid);
+  bool HasPermissionForDevice(const std::string& guid,
+                              const std::string& package);
 
   ArcBridgeService* const arc_bridge_service_;  // Owned by ArcServiceManager.
   mojom::UsbHostHostPtr usb_host_ptr_;
diff --git a/components/data_reduction_proxy/core/common/data_reduction_proxy_headers.cc b/components/data_reduction_proxy/core/common/data_reduction_proxy_headers.cc
index cf3e45b..ef2d3122 100644
--- a/components/data_reduction_proxy/core/common/data_reduction_proxy_headers.cc
+++ b/components/data_reduction_proxy/core/common/data_reduction_proxy_headers.cc
@@ -373,6 +373,12 @@
     DataReductionProxyInfo* data_reduction_proxy_info) {
   DCHECK(data_reduction_proxy_info);
 
+  // Responses from the warmup URL probe should not be checked for bypass types.
+  // Doing so may unnecessarily cause all data saver proxies to be marked as
+  // bad (e.g., when via header is missing on the response to the probe from the
+  // HTTP proxy).
+  DCHECK(url_chain.empty() || (params::GetWarmupURL() != url_chain.back()));
+
   bool has_via_header = HasDataReductionProxyViaHeader(headers, nullptr);
 
   if (has_via_header && HasURLRedirectCycle(url_chain)) {
diff --git a/components/download/content/internal/download_driver_impl.cc b/components/download/content/internal/download_driver_impl.cc
index 47a9e6b..050d79d7 100644
--- a/components/download/content/internal/download_driver_impl.cc
+++ b/components/download/content/internal/download_driver_impl.cc
@@ -138,6 +138,7 @@
     const RequestParams& request_params,
     const std::string& guid,
     const base::FilePath& file_path,
+    scoped_refptr<network::ResourceRequestBody> post_body,
     const net::NetworkTrafficAnnotationTag& traffic_annotation) {
   DCHECK(!request_params.url.is_empty());
   DCHECK(!guid.empty());
@@ -168,6 +169,7 @@
     download_url_params->set_fetch_error_body(true);
   download_url_params->set_download_source(
       download::DownloadSource::INTERNAL_API);
+  download_url_params->set_post_body(post_body);
 
   download_manager_->DownloadUrl(std::move(download_url_params), nullptr);
 }
diff --git a/components/download/content/internal/download_driver_impl.h b/components/download/content/internal/download_driver_impl.h
index bc3a06e..f9a155f60 100644
--- a/components/download/content/internal/download_driver_impl.h
+++ b/components/download/content/internal/download_driver_impl.h
@@ -42,6 +42,7 @@
       const RequestParams& request_params,
       const std::string& guid,
       const base::FilePath& file_path,
+      scoped_refptr<network::ResourceRequestBody> post_body,
       const net::NetworkTrafficAnnotationTag& traffic_annotation) override;
   void Remove(const std::string& guid) override;
   void Pause(const std::string& guid) override;
diff --git a/components/download/internal/background_service/config.cc b/components/download/internal/background_service/config.cc
index 81aaaaa..99529ad7 100644
--- a/components/download/internal/background_service/config.cc
+++ b/components/download/internal/background_service/config.cc
@@ -76,6 +76,10 @@
 const base::TimeDelta kDefaultNavigationTimeoutDelay =
     base::TimeDelta::FromSeconds(300);
 
+// The default timeout for a pending upload.
+const base::TimeDelta kDefaultPendingUploadTimeoutDelay =
+    base::TimeDelta::FromSeconds(30);
+
 // The default value of download retry delay when the download is failed.
 const base::TimeDelta kDefaultDownloadRetryDelay =
     base::TimeDelta::FromSeconds(20);
@@ -146,6 +150,11 @@
       base::TimeDelta::FromSeconds(base::saturated_cast<int>(
           GetFinchConfigUInt(kNavigationTimeoutDelaySecondsConfig,
                              kDefaultNavigationTimeoutDelay.InSeconds())));
+  config->pending_upload_timeout_delay =
+      base::TimeDelta::FromSeconds(base::saturated_cast<int>(
+          GetFinchConfigUInt(kPendingUploadTimeoutDelaySecondsConfig,
+                             kDefaultPendingUploadTimeoutDelay.InSeconds())));
+
   config->download_retry_delay =
       base::TimeDelta::FromMilliseconds(base::saturated_cast<int>(
           GetFinchConfigUInt(kDownloadRetryDelayMsConfig,
@@ -170,6 +179,7 @@
       network_change_delay(kDefaultNetworkChangeDelay),
       navigation_completion_delay(kDefaultNavigationCompletionDelay),
       navigation_timeout_delay(kDefaultNavigationTimeoutDelay),
+      pending_upload_timeout_delay(kDefaultPendingUploadTimeoutDelay),
       download_retry_delay(kDefaultDownloadRetryDelay) {}
 
 }  // namespace download
diff --git a/components/download/internal/background_service/config.h b/components/download/internal/background_service/config.h
index 67276613..4e276f3 100644
--- a/components/download/internal/background_service/config.h
+++ b/components/download/internal/background_service/config.h
@@ -69,6 +69,12 @@
 constexpr char kNavigationTimeoutDelaySecondsConfig[] =
     "navigation_timeout_delay_seconds";
 
+// Configuration name for the timeout value after which an upload will be killed
+// if the client still hasn't responded with the upload data. Measured in
+// seconds.
+constexpr char kPendingUploadTimeoutDelaySecondsConfig[] =
+    "pending_upload_timeout_delay_seconds";
+
 // Configuration name for the retry delay when the download is failed, measured
 // in milliseconds.
 constexpr char kDownloadRetryDelayMsConfig[] = "retry_delay_ms";
@@ -142,6 +148,10 @@
   // The timeout to wait for after a navigation starts.
   base::TimeDelta navigation_timeout_delay;
 
+  // The timeout after which upload entries waiting on data from their clients
+  // will be aborted.
+  base::TimeDelta pending_upload_timeout_delay;
+
   // The delay to retry a download when the download is failed.
   base::TimeDelta download_retry_delay;
 
diff --git a/components/download/internal/background_service/controller_impl.cc b/components/download/internal/background_service/controller_impl.cc
index a0b841e0..77e5ada 100644
--- a/components/download/internal/background_service/controller_impl.cc
+++ b/components/download/internal/background_service/controller_impl.cc
@@ -32,6 +32,7 @@
 #include "components/download/public/background_service/download_metadata.h"
 #include "components/download/public/background_service/navigation_monitor.h"
 #include "net/traffic_annotation/network_traffic_annotation.h"
+#include "services/network/public/cpp/resource_request_body.h"
 
 namespace download {
 namespace {
@@ -962,7 +963,7 @@
     } else {
       stats::LogEntryEvent(stats::DownloadEvent::START);
       driver_->Start(
-          entry->request_params, entry->guid, entry->target_file_path,
+          entry->request_params, entry->guid, entry->target_file_path, nullptr,
           net::NetworkTrafficAnnotationTag(entry->traffic_annotation));
     }
   }
diff --git a/components/download/internal/background_service/controller_impl_unittest.cc b/components/download/internal/background_service/controller_impl_unittest.cc
index d98af57a..aaa2dda 100644
--- a/components/download/internal/background_service/controller_impl_unittest.cc
+++ b/components/download/internal/background_service/controller_impl_unittest.cc
@@ -31,6 +31,7 @@
 #include "components/download/public/background_service/test/empty_client.h"
 #include "components/download/public/background_service/test/mock_client.h"
 #include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
+#include "services/network/public/cpp/resource_request_body.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -1129,7 +1130,7 @@
   EXPECT_CALL(*client_,
               OnDownloadFailed(entry2.guid, Client::FailureReason::ABORTED))
       .Times(1);
-  driver_->Start(RequestParams(), entry2.guid, entry2.target_file_path,
+  driver_->Start(RequestParams(), entry2.guid, entry2.target_file_path, nullptr,
                  TRAFFIC_ANNOTATION_FOR_TESTS);
 
   // Test FailureReason::NETWORK.
@@ -1346,6 +1347,7 @@
 
   // Simulate a successful external download.
   driver_->NotifyDownloadSucceeded(dentry2);
+  task_runner_->RunUntilIdle();
 
   EXPECT_TRUE(driver_->Find(entry1.guid).has_value());
   EXPECT_FALSE(driver_->Find(entry1.guid).value().paused);
@@ -1391,7 +1393,7 @@
 
   // Simulate a newly created external download.
   driver_->Start(RequestParams(), dentry2.guid, dentry2.current_file_path,
-                 TRAFFIC_ANNOTATION_FOR_TESTS);
+                 nullptr, TRAFFIC_ANNOTATION_FOR_TESTS);
 
   EXPECT_TRUE(driver_->Find(entry1.guid).value().paused);
   EXPECT_FALSE(driver_->Find(entry2.guid).value().paused);
@@ -1420,7 +1422,7 @@
   // Rebuild the download so we can simulate more.
   dentry2.state = DriverEntry::State::IN_PROGRESS;
   driver_->Start(RequestParams(), dentry2.guid, dentry2.current_file_path,
-                 TRAFFIC_ANNOTATION_FOR_TESTS);
+                 nullptr, TRAFFIC_ANNOTATION_FOR_TESTS);
 
   EXPECT_TRUE(driver_->Find(entry1.guid).value().paused);
   EXPECT_FALSE(driver_->Find(entry2.guid).value().paused);
diff --git a/components/download/internal/background_service/debugging_client.cc b/components/download/internal/background_service/debugging_client.cc
index dedf1c1..427bf4d 100644
--- a/components/download/internal/background_service/debugging_client.cc
+++ b/components/download/internal/background_service/debugging_client.cc
@@ -4,6 +4,9 @@
 
 #include "components/download/internal/background_service/debugging_client.h"
 
+#include "base/threading/sequenced_task_runner_handle.h"
+#include "services/network/public/cpp/resource_request_body.h"
+
 namespace download {
 
 void DebuggingClient::OnServiceInitialized(
@@ -37,4 +40,10 @@
   return true;
 }
 
+void DebuggingClient::GetUploadData(const std::string& guid,
+                                    GetUploadDataCallback callback) {
+  base::SequencedTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::BindOnce(std::move(callback), nullptr));
+}
+
 }  // namespace download
diff --git a/components/download/internal/background_service/debugging_client.h b/components/download/internal/background_service/debugging_client.h
index bd249f3..89fc7a5 100644
--- a/components/download/internal/background_service/debugging_client.h
+++ b/components/download/internal/background_service/debugging_client.h
@@ -34,6 +34,8 @@
                            const CompletionInfo& completion_info) override;
   bool CanServiceRemoveDownloadedFile(const std::string& guid,
                                       bool force_delete) override;
+  void GetUploadData(const std::string& guid,
+                     GetUploadDataCallback callback) override;
 
   DISALLOW_COPY_AND_ASSIGN(DebuggingClient);
 };
diff --git a/components/download/internal/background_service/download_driver.h b/components/download/internal/background_service/download_driver.h
index 476fa76..0243340 100644
--- a/components/download/internal/background_service/download_driver.h
+++ b/components/download/internal/background_service/download_driver.h
@@ -17,6 +17,10 @@
 class FilePath;
 }  // namespace base
 
+namespace network {
+class ResourceRequestBody;
+}  // namespace network
+
 namespace download {
 
 struct RequestParams;
@@ -84,6 +88,7 @@
       const RequestParams& request_params,
       const std::string& guid,
       const base::FilePath& file_path,
+      scoped_refptr<network::ResourceRequestBody> post_body,
       const net::NetworkTrafficAnnotationTag& traffic_annotation) = 0;
 
   // Cancels an existing download, all data associated with this download should
diff --git a/components/download/internal/background_service/entry.cc b/components/download/internal/background_service/entry.cc
index 137b390..c13e42d 100644
--- a/components/download/internal/background_service/entry.cc
+++ b/components/download/internal/background_service/entry.cc
@@ -12,7 +12,8 @@
     : bytes_downloaded(0u),
       attempt_count(0),
       resumption_count(0),
-      cleanup_attempt_count(0) {}
+      cleanup_attempt_count(0),
+      has_upload_data(false) {}
 Entry::Entry(const Entry& other) = default;
 
 Entry::Entry(const DownloadParams& params)
@@ -25,6 +26,7 @@
       attempt_count(0),
       resumption_count(0),
       cleanup_attempt_count(0),
+      has_upload_data(false),
       traffic_annotation(params.traffic_annotation) {}
 
 Entry::~Entry() = default;
@@ -49,6 +51,7 @@
          attempt_count == other.attempt_count &&
          resumption_count == other.resumption_count &&
          cleanup_attempt_count == other.cleanup_attempt_count &&
+         has_upload_data == other.has_upload_data &&
          traffic_annotation == other.traffic_annotation;
 }
 
diff --git a/components/download/internal/background_service/entry.h b/components/download/internal/background_service/entry.h
index f3efe2b..85a24e3 100644
--- a/components/download/internal/background_service/entry.h
+++ b/components/download/internal/background_service/entry.h
@@ -96,6 +96,9 @@
   // Stores the number of times the service tried to delete the download file.
   uint32_t cleanup_attempt_count;
 
+  // Stores whether this request also has some data to be uploaded.
+  bool has_upload_data;
+
   // Traffic annotation for the network request.
   net::MutableNetworkTrafficAnnotationTag traffic_annotation;
 };
diff --git a/components/download/internal/background_service/in_memory_download_driver.cc b/components/download/internal/background_service/in_memory_download_driver.cc
index 9425674..99ba097 100644
--- a/components/download/internal/background_service/in_memory_download_driver.cc
+++ b/components/download/internal/background_service/in_memory_download_driver.cc
@@ -5,6 +5,7 @@
 #include "components/download/internal/background_service/in_memory_download_driver.h"
 
 #include "components/download/internal/background_service/in_memory_download.h"
+#include "services/network/public/cpp/resource_request_body.h"
 
 namespace download {
 
@@ -97,6 +98,7 @@
     const RequestParams& request_params,
     const std::string& guid,
     const base::FilePath& file_path,
+    scoped_refptr<network::ResourceRequestBody> post_body,
     const net::NetworkTrafficAnnotationTag& traffic_annotation) {
   std::unique_ptr<InMemoryDownload> download =
       download_factory_->Create(guid, request_params, traffic_annotation, this);
diff --git a/components/download/internal/background_service/in_memory_download_driver.h b/components/download/internal/background_service/in_memory_download_driver.h
index 881a0b9..b159499 100644
--- a/components/download/internal/background_service/in_memory_download_driver.h
+++ b/components/download/internal/background_service/in_memory_download_driver.h
@@ -61,6 +61,7 @@
       const RequestParams& request_params,
       const std::string& guid,
       const base::FilePath& file_path,
+      scoped_refptr<network::ResourceRequestBody> post_body,
       const net::NetworkTrafficAnnotationTag& traffic_annotation) override;
   void Remove(const std::string& guid) override;
   void Pause(const std::string& guid) override;
diff --git a/components/download/internal/background_service/in_memory_download_driver_unittest.cc b/components/download/internal/background_service/in_memory_download_driver_unittest.cc
index 675391c..cc7af9b 100644
--- a/components/download/internal/background_service/in_memory_download_driver_unittest.cc
+++ b/components/download/internal/background_service/in_memory_download_driver_unittest.cc
@@ -8,6 +8,7 @@
 
 #include "components/download/internal/background_service/test/mock_download_driver_client.h"
 #include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
+#include "services/network/public/cpp/resource_request_body.h"
 #include "storage/browser/blob/blob_data_handle.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -111,7 +112,7 @@
   void Start(const std::string& guid) {
     RequestParams params;
     base::FilePath path;
-    driver()->Start(params, guid, path, TRAFFIC_ANNOTATION_FOR_TESTS);
+    driver()->Start(params, guid, path, nullptr, TRAFFIC_ANNOTATION_FOR_TESTS);
   }
 
  private:
diff --git a/components/download/internal/background_service/proto/entry.proto b/components/download/internal/background_service/proto/entry.proto
index 2e7cfbb..9ebdbca 100644
--- a/components/download/internal/background_service/proto/entry.proto
+++ b/components/download/internal/background_service/proto/entry.proto
@@ -66,4 +66,5 @@
   optional uint32 cleanup_attempt_count = 13;
 
   optional uint32 resumption_count = 14;
+  optional bool has_upload_data = 15;
 }
diff --git a/components/download/internal/background_service/proto_conversions.cc b/components/download/internal/background_service/proto_conversions.cc
index ef1398eb..efd23472 100644
--- a/components/download/internal/background_service/proto_conversions.cc
+++ b/components/download/internal/background_service/proto_conversions.cc
@@ -281,6 +281,7 @@
   entry.attempt_count = proto.attempt_count();
   entry.resumption_count = proto.resumption_count();
   entry.cleanup_attempt_count = proto.cleanup_attempt_count();
+  entry.has_upload_data = proto.has_upload_data();
   entry.traffic_annotation =
       net::MutableNetworkTrafficAnnotationTag({proto.traffic_annotation()});
   entry.bytes_downloaded = proto.bytes_downloaded();
@@ -305,6 +306,7 @@
   proto.set_attempt_count(entry.attempt_count);
   proto.set_resumption_count(entry.resumption_count);
   proto.set_cleanup_attempt_count(entry.cleanup_attempt_count);
+  proto.set_has_upload_data(entry.has_upload_data);
   proto.set_traffic_annotation(entry.traffic_annotation.unique_id_hash_code);
   proto.set_bytes_downloaded(entry.bytes_downloaded);
   return proto;
diff --git a/components/download/internal/background_service/test/BUILD.gn b/components/download/internal/background_service/test/BUILD.gn
index 6dc81dd7..0ed3e44 100644
--- a/components/download/internal/background_service/test/BUILD.gn
+++ b/components/download/internal/background_service/test/BUILD.gn
@@ -43,5 +43,6 @@
 
   deps = [
     "//components/download/internal/background_service:internal",
+    "//services/network/public/cpp",
   ]
 }
diff --git a/components/download/internal/background_service/test/test_download_driver.cc b/components/download/internal/background_service/test/test_download_driver.cc
index 17a91765..54634cf 100644
--- a/components/download/internal/background_service/test/test_download_driver.cc
+++ b/components/download/internal/background_service/test/test_download_driver.cc
@@ -7,6 +7,7 @@
 #include "base/files/file_path.h"
 #include "components/download/public/background_service/download_params.h"
 #include "net/http/http_response_headers.h"
+#include "services/network/public/cpp/resource_request_body.h"
 
 namespace download {
 namespace test {
@@ -71,6 +72,7 @@
     const RequestParams& params,
     const std::string& guid,
     const base::FilePath& file_path,
+    scoped_refptr<network::ResourceRequestBody> post_body,
     const net::NetworkTrafficAnnotationTag& traffic_annotation) {
   DriverEntry entry;
   entry.guid = guid;
diff --git a/components/download/internal/background_service/test/test_download_driver.h b/components/download/internal/background_service/test/test_download_driver.h
index 9e89577..34b4e86 100644
--- a/components/download/internal/background_service/test/test_download_driver.h
+++ b/components/download/internal/background_service/test/test_download_driver.h
@@ -42,6 +42,7 @@
       const RequestParams& params,
       const std::string& guid,
       const base::FilePath& file_path,
+      scoped_refptr<network::ResourceRequestBody> post_body,
       const net::NetworkTrafficAnnotationTag& traffic_annotation) override;
   void Remove(const std::string& guid) override;
   void Pause(const std::string& guid) override;
diff --git a/components/download/public/background_service/DEPS b/components/download/public/background_service/DEPS
index 072ddca8..4d8aa673 100644
--- a/components/download/public/background_service/DEPS
+++ b/components/download/public/background_service/DEPS
@@ -4,6 +4,7 @@
   "+components/keyed_service",
   "+net/http",
   "+net/traffic_annotation",
+  "+services/network/public/cpp",
   "+storage/browser",
   "+url",
 ]
diff --git a/components/download/public/background_service/client.h b/components/download/public/background_service/client.h
index 8f0e6bcc..d42380e6 100644
--- a/components/download/public/background_service/client.h
+++ b/components/download/public/background_service/client.h
@@ -8,15 +8,23 @@
 #include <string>
 #include <vector>
 
+#include "base/callback.h"
 #include "base/files/file_path.h"
 #include "net/http/http_response_headers.h"
 #include "url/gurl.h"
 
+namespace network {
+class ResourceRequestBody;
+}  // namespace network
+
 namespace download {
 
 struct CompletionInfo;
 struct DownloadMetaData;
 
+using GetUploadDataCallback =
+    base::OnceCallback<void(scoped_refptr<network::ResourceRequestBody>)>;
+
 // The Client interface required by any feature that wants to start a download
 // through the DownloadService.  Should be registered immediately at startup
 // when the DownloadService is created (see the factory).
@@ -116,6 +124,12 @@
   // the outcome of this function.
   virtual bool CanServiceRemoveDownloadedFile(const std::string& guid,
                                               bool force_delete) = 0;
+
+  // Called by the service to ask the client to provide the upload data.
+  // The client is responsible for posting the callback with an appropriate
+  // ResourceRequestBody or nullptr, if it is a regular download.
+  virtual void GetUploadData(const std::string& guid,
+                             GetUploadDataCallback callback) = 0;
 };
 
 }  // namespace download
diff --git a/components/download/public/background_service/test/BUILD.gn b/components/download/public/background_service/test/BUILD.gn
index 39bfe9bb..fbe08cec 100644
--- a/components/download/public/background_service/test/BUILD.gn
+++ b/components/download/public/background_service/test/BUILD.gn
@@ -23,6 +23,10 @@
     "test_download_service.h",
   ]
 
+  deps = [
+    "//services/network/public/cpp",
+  ]
+
   public_deps = [
     "//base",
     "//components/download/public/background_service:public",
diff --git a/components/download/public/background_service/test/empty_client.cc b/components/download/public/background_service/test/empty_client.cc
index c908732ce..231e152 100644
--- a/components/download/public/background_service/test/empty_client.cc
+++ b/components/download/public/background_service/test/empty_client.cc
@@ -4,6 +4,9 @@
 
 #include "components/download/public/background_service/test/empty_client.h"
 
+#include "base/threading/sequenced_task_runner_handle.h"
+#include "services/network/public/cpp/resource_request_body.h"
+
 namespace download {
 namespace test {
 
@@ -33,5 +36,11 @@
   return true;
 }
 
+void EmptyClient::GetUploadData(const std::string& guid,
+                                GetUploadDataCallback callback) {
+  base::SequencedTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::BindOnce(std::move(callback), nullptr));
+}
+
 }  // namespace test
 }  // namespace download
diff --git a/components/download/public/background_service/test/empty_client.h b/components/download/public/background_service/test/empty_client.h
index d708d83..2c911e0 100644
--- a/components/download/public/background_service/test/empty_client.h
+++ b/components/download/public/background_service/test/empty_client.h
@@ -33,6 +33,8 @@
                            const CompletionInfo& completion_info) override;
   bool CanServiceRemoveDownloadedFile(const std::string& guid,
                                       bool force_delete) override;
+  void GetUploadData(const std::string& guid,
+                     GetUploadDataCallback callback) override;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(EmptyClient);
diff --git a/components/download/public/background_service/test/mock_client.cc b/components/download/public/background_service/test/mock_client.cc
index 7ae6151b..99662f1 100644
--- a/components/download/public/background_service/test/mock_client.cc
+++ b/components/download/public/background_service/test/mock_client.cc
@@ -4,11 +4,20 @@
 
 #include "components/download/public/background_service/test/mock_client.h"
 
+#include "base/threading/sequenced_task_runner_handle.h"
+#include "services/network/public/cpp/resource_request_body.h"
+
 namespace download {
 namespace test {
 
 MockClient::MockClient() = default;
 MockClient::~MockClient() = default;
 
+void MockClient::GetUploadData(const std::string& guid,
+                               GetUploadDataCallback callback) {
+  base::SequencedTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::BindOnce(std::move(callback), nullptr));
+}
+
 }  // namespace test
 }  // namespace download
diff --git a/components/download/public/background_service/test/mock_client.h b/components/download/public/background_service/test/mock_client.h
index a96c3885..763d650 100644
--- a/components/download/public/background_service/test/mock_client.h
+++ b/components/download/public/background_service/test/mock_client.h
@@ -32,6 +32,8 @@
   MOCK_METHOD2(OnDownloadSucceeded,
                void(const std::string&, const CompletionInfo&));
   MOCK_METHOD2(CanServiceRemoveDownloadedFile, bool(const std::string&, bool));
+  void GetUploadData(const std::string& guid,
+                     GetUploadDataCallback callback) override;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(MockClient);
diff --git a/components/history/core/browser/download_database.cc b/components/history/core/browser/download_database.cc
index 837b295..07f59dd 100644
--- a/components/history/core/browser/download_database.cc
+++ b/components/history/core/browser/download_database.cc
@@ -453,8 +453,6 @@
     info->total_bytes = statement_main.ColumnInt64(column++);
     int state = statement_main.ColumnInt(column++);
     info->state = IntToDownloadState(state);
-    if (info->state == DownloadState::INVALID)
-      UMA_HISTOGRAM_COUNTS("Download.DatabaseInvalidState", state);
     info->danger_type =
         IntToDownloadDangerType(statement_main.ColumnInt(column++));
     info->interrupt_reason =
diff --git a/components/omnibox/browser/vector_icons/blank.1x.icon b/components/omnibox/browser/vector_icons/blank.1x.icon
index 4e64b92..27913f6c 100644
--- a/components/omnibox/browser/vector_icons/blank.1x.icon
+++ b/components/omnibox/browser/vector_icons/blank.1x.icon
@@ -2,5 +2,4 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-CANVAS_DIMENSIONS, 16,
-END
+CANVAS_DIMENSIONS, 16
diff --git a/components/omnibox/browser/vector_icons/blank.icon b/components/omnibox/browser/vector_icons/blank.icon
index d7b844f..521d94a 100644
--- a/components/omnibox/browser/vector_icons/blank.icon
+++ b/components/omnibox/browser/vector_icons/blank.icon
@@ -2,5 +2,4 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-CANVAS_DIMENSIONS, 32,
-END
+CANVAS_DIMENSIONS, 32
diff --git a/components/omnibox/browser/vector_icons/calculator.1x.icon b/components/omnibox/browser/vector_icons/calculator.1x.icon
index 351e9f5..4ddd046 100644
--- a/components/omnibox/browser/vector_icons/calculator.1x.icon
+++ b/components/omnibox/browser/vector_icons/calculator.1x.icon
@@ -16,5 +16,4 @@
 LINE_TO, 4, 11,
 LINE_TO, 4, 9,
 LINE_TO, 4, 9,
-CLOSE,
-END
+CLOSE
diff --git a/components/omnibox/browser/vector_icons/calculator.icon b/components/omnibox/browser/vector_icons/calculator.icon
index 33a96db..da2e2f4 100644
--- a/components/omnibox/browser/vector_icons/calculator.icon
+++ b/components/omnibox/browser/vector_icons/calculator.icon
@@ -16,5 +16,4 @@
 LINE_TO, 8, 21,
 LINE_TO, 8, 18,
 LINE_TO, 8, 18,
-CLOSE,
-END
+CLOSE
diff --git a/components/omnibox/browser/vector_icons/extension_app.1x.icon b/components/omnibox/browser/vector_icons/extension_app.1x.icon
index d4782de..d2079f6 100644
--- a/components/omnibox/browser/vector_icons/extension_app.1x.icon
+++ b/components/omnibox/browser/vector_icons/extension_app.1x.icon
@@ -32,5 +32,4 @@
 CUBIC_TO, 14.36f, 9.57f, 15, 8.93f, 15, 8.14f,
 CUBIC_TO, 15, 7.35f, 14.36f, 6.71f, 13.57f, 6.71f,
 LINE_TO, 12.71f, 6.71f,
-CLOSE,
-END
+CLOSE
diff --git a/components/omnibox/browser/vector_icons/extension_app.icon b/components/omnibox/browser/vector_icons/extension_app.icon
index feaa917..f3270e8e 100644
--- a/components/omnibox/browser/vector_icons/extension_app.icon
+++ b/components/omnibox/browser/vector_icons/extension_app.icon
@@ -32,5 +32,4 @@
 CUBIC_TO, 27.72f, 20.14f, 29, 18.5f, 29, 17,
 CUBIC_TO, 29, 15.5f, 27.72f, 14.43f, 26, 14,
 LINE_TO, 24, 14,
-CLOSE,
-END
+CLOSE
diff --git a/components/omnibox/browser/vector_icons/http.icon b/components/omnibox/browser/vector_icons/http.icon
index 3323410b..dea3f3dcb 100644
--- a/components/omnibox/browser/vector_icons/http.icon
+++ b/components/omnibox/browser/vector_icons/http.icon
@@ -22,5 +22,4 @@
 LINE_TO, 11, 6,
 LINE_TO, 11, 13,
 LINE_TO, 5, 13,
-CLOSE,
-END
+CLOSE
diff --git a/components/omnibox/browser/vector_icons/keyword_search.icon b/components/omnibox/browser/vector_icons/keyword_search.icon
index cfd650b..f4ef5b4 100644
--- a/components/omnibox/browser/vector_icons/keyword_search.icon
+++ b/components/omnibox/browser/vector_icons/keyword_search.icon
@@ -16,5 +16,4 @@
 R_CUBIC_TO, 0, -0.83f, 0.77f, -1.5f, 1.71f, -1.5f,
 R_CUBIC_TO, 0.47f, 0, 0.9f, 0.17f, 1.21f, 0.44f,
 R_LINE_TO, 8.57f, 7.5f,
-CLOSE,
-END
+CLOSE
diff --git a/components/omnibox/browser/vector_icons/star.1x.icon b/components/omnibox/browser/vector_icons/star.1x.icon
index fc814dc..a3dab5a 100644
--- a/components/omnibox/browser/vector_icons/star.1x.icon
+++ b/components/omnibox/browser/vector_icons/star.1x.icon
@@ -14,5 +14,4 @@
 LINE_TO, 9.69f, 6.19f,
 LINE_TO, 8, 2,
 LINE_TO, 6.31f, 6.19f,
-CLOSE,
-END
+CLOSE
diff --git a/components/omnibox/browser/vector_icons/star.icon b/components/omnibox/browser/vector_icons/star.icon
index f6d8377..f1d4ff5 100644
--- a/components/omnibox/browser/vector_icons/star.icon
+++ b/components/omnibox/browser/vector_icons/star.icon
@@ -14,5 +14,4 @@
 LINE_TO, 19.73f, 12.67f,
 LINE_TO, 16.5f, 5,
 LINE_TO, 13.27f, 12.67f,
-CLOSE,
-END
+CLOSE
diff --git a/components/omnibox/browser/vector_icons/switch.icon b/components/omnibox/browser/vector_icons/switch.icon
index c34e69aa..e4c82d1 100644
--- a/components/omnibox/browser/vector_icons/switch.icon
+++ b/components/omnibox/browser/vector_icons/switch.icon
@@ -15,5 +15,4 @@
 LINE_TO, 16, 13,
 LINE_TO, 16, 7,
 LINE_TO, 4, 7,
-CLOSE,
-END
+CLOSE
diff --git a/components/omnibox/browser/vector_icons/tab.icon b/components/omnibox/browser/vector_icons/tab.icon
index 641e06d..7b99b5c 100644
--- a/components/omnibox/browser/vector_icons/tab.icon
+++ b/components/omnibox/browser/vector_icons/tab.icon
@@ -12,5 +12,4 @@
 LINE_TO, 9, 16,
 LINE_TO, 7, 26,
 LINE_TO, 3, 26,
-CLOSE,
-END
+CLOSE
diff --git a/components/omnibox/browser/vector_icons/touchable_bookmark.icon b/components/omnibox/browser/vector_icons/touchable_bookmark.icon
index 3610301..8942f9a 100644
--- a/components/omnibox/browser/vector_icons/touchable_bookmark.icon
+++ b/components/omnibox/browser/vector_icons/touchable_bookmark.icon
@@ -18,5 +18,4 @@
 R_LINE_TO, 2.73f, 2.49f,
 R_LINE_TO, -0.82f, 3.7f,
 LINE_TO, 10, 13.04f,
-CLOSE,
-END
+CLOSE
diff --git a/components/omnibox/browser/vector_icons/touchable_clear.icon b/components/omnibox/browser/vector_icons/touchable_clear.icon
index c81df6e..302c26c 100644
--- a/components/omnibox/browser/vector_icons/touchable_clear.icon
+++ b/components/omnibox/browser/vector_icons/touchable_clear.icon
@@ -26,5 +26,4 @@
 R_LINE_TO, 2.53f, 2.52f,
 R_LINE_TO, 0.81f, -0.81f,
 LINE_TO, 14.14f, 10,
-CLOSE,
-END
+CLOSE
diff --git a/components/omnibox/browser/vector_icons/touchable_page.icon b/components/omnibox/browser/vector_icons/touchable_page.icon
index 8c809680..869f53fe 100644
--- a/components/omnibox/browser/vector_icons/touchable_page.icon
+++ b/components/omnibox/browser/vector_icons/touchable_page.icon
@@ -17,5 +17,4 @@
 LINE_TO, 9, 11,
 LINE_TO, 9, 7,
 LINE_TO, 13, 11,
-CLOSE,
-END
+CLOSE
diff --git a/components/omnibox/browser/vector_icons/touchable_search.icon b/components/omnibox/browser/vector_icons/touchable_search.icon
index e19765a..ae427b6 100644
--- a/components/omnibox/browser/vector_icons/touchable_search.icon
+++ b/components/omnibox/browser/vector_icons/touchable_search.icon
@@ -21,5 +21,4 @@
 ARC_TO, 2.67f, 2.67f, 0, 0, 1, 9.86f, 7.33f,
 ARC_TO, 2.67f, 2.67f, 0, 0, 1, 12.53f, 10,
 R_ARC_TO, 2.67f, 2.67f, 0, 0, 1, -2.67f, 2.67f,
-CLOSE,
-END
+CLOSE
diff --git a/components/payments/content/payment_request.cc b/components/payments/content/payment_request.cc
index d253cc5..687ee54 100644
--- a/components/payments/content/payment_request.cc
+++ b/components/payments/content/payment_request.cc
@@ -16,6 +16,7 @@
 #include "components/payments/content/payment_request_converter.h"
 #include "components/payments/content/payment_request_web_contents_manager.h"
 #include "components/payments/core/can_make_payment_query.h"
+#include "components/payments/core/features.h"
 #include "components/payments/core/payment_details.h"
 #include "components/payments/core/payment_details_validation.h"
 #include "components/payments/core/payment_prefs.h"
@@ -352,6 +353,19 @@
   return delegate_->IsIncognito();
 }
 
+bool PaymentRequest::SatisfiesSkipUIConstraints() const {
+  return base::FeatureList::IsEnabled(features::kWebPaymentsSingleAppUiSkip) &&
+         base::FeatureList::IsEnabled(::features::kServiceWorkerPaymentApps) &&
+         state()->is_get_all_instruments_finished() &&
+         state()->available_instruments().size() == 1 &&
+         spec()->stringified_method_data().size() == 1 &&
+         !spec()->request_shipping() && !spec()->request_payer_name() &&
+         !spec()->request_payer_phone() &&
+         !spec()->request_payer_email()
+         // Only allowing URL base payment apps to skip the payment sheet.
+         && spec()->url_payment_method_identifiers().size() == 1;
+}
+
 void PaymentRequest::RecordFirstAbortReason(
     JourneyLogger::AbortReason abort_reason) {
   if (!has_recorded_completion_) {
@@ -382,7 +396,7 @@
   if (delegate_->IsIncognito()) {
     can_make_payment =
         spec()->HasBasicCardMethodName() ||
-        base::FeatureList::IsEnabled(features::kServiceWorkerPaymentApps);
+        base::FeatureList::IsEnabled(::features::kServiceWorkerPaymentApps);
   }
 
   mojom::CanMakePaymentQueryResult positive =
diff --git a/components/payments/content/payment_request.h b/components/payments/content/payment_request.h
index 30a7c556..400ae351 100644
--- a/components/payments/content/payment_request.h
+++ b/components/payments/content/payment_request.h
@@ -103,11 +103,19 @@
 
   bool IsIncognito() const;
 
+  // Returns true if this payment request supports skipping the Payment Sheet.
+  // Typically, this means only one payment method is supported, it's a URL
+  // based method, and no other info is requested from the user.
+  bool SatisfiesSkipUIConstraints() const;
+
   content::WebContents* web_contents() { return web_contents_; }
 
   PaymentRequestSpec* spec() { return spec_.get(); }
   PaymentRequestState* state() { return state_.get(); }
 
+  PaymentRequestSpec* spec() const { return spec_.get(); }
+  PaymentRequestState* state() const { return state_.get(); }
+
  private:
   // Only records the abort reason if it's the first completion for this Payment
   // Request. This is necessary since the aborts cascade into one another with
diff --git a/components/payments/content/payment_request_dialog.h b/components/payments/content/payment_request_dialog.h
index 3d23fcb..a08c1e64 100644
--- a/components/payments/content/payment_request_dialog.h
+++ b/components/payments/content/payment_request_dialog.h
@@ -22,6 +22,10 @@
 
   virtual void ShowDialog() = 0;
 
+  virtual void ShowDialogAtPaymentHandlerSheet(
+      const GURL& url,
+      PaymentHandlerOpenWindowCallback callback) = 0;
+
   virtual void CloseDialog() = 0;
 
   virtual void ShowErrorMessage() = 0;
diff --git a/components/payments/content/payment_request_display_manager.cc b/components/payments/content/payment_request_display_manager.cc
index 22283b2..5796321 100644
--- a/components/payments/content/payment_request_display_manager.cc
+++ b/components/payments/content/payment_request_display_manager.cc
@@ -27,7 +27,6 @@
     PaymentRequest* request) {
   DCHECK(request);
   DCHECK(delegate_);
-
   delegate_->ShowDialog(request);
 }
 
diff --git a/components/payments/core/features.cc b/components/payments/core/features.cc
index f60eae5..73e143e 100644
--- a/components/payments/core/features.cc
+++ b/components/payments/core/features.cc
@@ -21,5 +21,13 @@
 const base::Feature kWebPaymentsModifiers{"WebPaymentsModifiers",
                                           base::FEATURE_ENABLED_BY_DEFAULT};
 
+#if defined(OS_ANDROID)
+const base::Feature kWebPaymentsSingleAppUiSkip{
+    "WebPaymentsSingleAppUiSkip", base::FEATURE_ENABLED_BY_DEFAULT};
+#else
+const base::Feature kWebPaymentsSingleAppUiSkip{
+    "WebPaymentsSingleAppUiSkip", base::FEATURE_DISABLED_BY_DEFAULT};
+#endif
+
 }  // namespace features
 }  // namespace payments
diff --git a/components/payments/core/features.h b/components/payments/core/features.h
index a7e4a48cf..fe66a9f 100644
--- a/components/payments/core/features.h
+++ b/components/payments/core/features.h
@@ -27,6 +27,10 @@
 // Used to control the support for Payment Details modifiers.
 extern const base::Feature kWebPaymentsModifiers;
 
+// Used to control whether the Payment Sheet can be skipped for Payment Requests
+// with a single URL based payment app and no other info requested.
+extern const base::Feature kWebPaymentsSingleAppUiSkip;
+
 }  // namespace features
 }  // namespace payments
 
diff --git a/components/policy/proto/device_management_backend.proto b/components/policy/proto/device_management_backend.proto
index cc65cd0..fc7f1b5 100644
--- a/components/policy/proto/device_management_backend.proto
+++ b/components/policy/proto/device_management_backend.proto
@@ -40,7 +40,7 @@
 
 // Request from device to server to register a device, user or browser.
 message DeviceRegisterRequest {
-  reserved 5;
+  reserved 5, 10;
 
   // Reregister device without erasing server state.  It can be used
   // to refresh dmtoken etc.  Client MUST set this value to true if it
@@ -131,14 +131,16 @@
 
   // Enumerates different expected lifetimes of registration.
   enum Lifetime {
-    // Default case, no expiration.
-    LIFETIME_INDEFINITE = 0;
+    // Default case.
+    LIFETIME_UNDEFINED = 0;
+    // No expiration, most of the registrations have this lifetime.
+    LIFETIME_INDEFINITE = 1;
     // Lifetime for ephemeral user policy registration.
-    LIFETIME_EPHEMERAL_USER = 1;
+    LIFETIME_EPHEMERAL_USER = 2;
   }
 
   // Indicates the expected lifetime of registration.
-  optional Lifetime lifetime = 10;
+  optional Lifetime lifetime = 11 [default = LIFETIME_INDEFINITE];
 }
 
 // Response from server to device register request.
diff --git a/components/safe_browsing/db/BUILD.gn b/components/safe_browsing/db/BUILD.gn
index 487b155c..c34eb11 100644
--- a/components/safe_browsing/db/BUILD.gn
+++ b/components/safe_browsing/db/BUILD.gn
@@ -217,6 +217,17 @@
   ]
 }
 
+source_set("prefix_iterator") {
+  sources = [
+    "prefix_iterator.cc",
+    "prefix_iterator.h",
+  ]
+  deps = [
+    ":v4_protocol_manager_util",
+    "//base",
+  ]
+}
+
 if (is_android) {
   import("//build/config/android/rules.gni")
   java_cpp_enum("sb_threat_values") {
@@ -247,6 +258,7 @@
     ":v4_store_proto",
   ]
   deps = [
+    ":prefix_iterator",
     ":v4_protocol_manager_util",
     ":v4_rice",
     "//base",
diff --git a/components/safe_browsing/db/prefix_iterator.cc b/components/safe_browsing/db/prefix_iterator.cc
new file mode 100644
index 0000000..e7471ff
--- /dev/null
+++ b/components/safe_browsing/db/prefix_iterator.cc
@@ -0,0 +1,17 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/safe_browsing/db/prefix_iterator.h"
+
+namespace safe_browsing {
+
+PrefixIterator::PrefixIterator(base::StringPiece prefixes,
+                               size_t index,
+                               size_t size)
+    : prefixes_(prefixes), index_(index), size_(size) {}
+
+PrefixIterator::PrefixIterator(const PrefixIterator& rhs)
+    : prefixes_(rhs.prefixes_), index_(rhs.index_), size_(rhs.size_) {}
+
+}  // namespace safe_browsing
diff --git a/components/safe_browsing/db/prefix_iterator.h b/components/safe_browsing/db/prefix_iterator.h
new file mode 100644
index 0000000..1f95b1e
--- /dev/null
+++ b/components/safe_browsing/db/prefix_iterator.h
@@ -0,0 +1,99 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_SAFE_BROWSING_DB_PREFIX_ITERATOR_H_
+#define COMPONENTS_SAFE_BROWSING_DB_PREFIX_ITERATOR_H_
+
+#include <cstddef>
+#include <iterator>
+
+#include "base/strings/string_piece.h"
+#include "components/safe_browsing/db/v4_protocol_manager_util.h"
+
+namespace safe_browsing {
+
+// The prefix iterator is used to binary search within a |HashPrefixes|. It is
+// essentially a random access iterator that steps |PrefixSize| steps within the
+// underlying buffer.
+class PrefixIterator
+    : public std::iterator<std::random_access_iterator_tag, base::StringPiece> {
+ public:
+  using difference_type =
+      typename std::iterator<std::random_access_iterator_tag,
+                             base::StringPiece>::difference_type;
+
+  PrefixIterator(base::StringPiece prefixes, size_t index, size_t size);
+  PrefixIterator(const PrefixIterator& rhs);
+
+  base::StringPiece operator*() const { return GetPiece(index_); }
+  base::StringPiece operator[](const int& rhs) const {
+    return GetPiece(index_ + rhs);
+  }
+
+  PrefixIterator& operator=(const PrefixIterator& rhs) {
+    index_ = rhs.index_;
+    return *this;
+  }
+  PrefixIterator& operator+=(const int& rhs) {
+    index_ += rhs;
+    return *this;
+  }
+  PrefixIterator& operator-=(const int& rhs) {
+    index_ -= rhs;
+    return *this;
+  }
+  PrefixIterator& operator++() {
+    index_++;
+    return *this;
+  }
+  PrefixIterator& operator--() {
+    index_--;
+    return *this;
+  }
+
+  PrefixIterator operator+(const PrefixIterator& rhs) const {
+    return PrefixIterator(prefixes_, index_ + rhs.index_, size_);
+  }
+  difference_type operator-(const PrefixIterator& rhs) const {
+    return index_ - rhs.index_;
+  }
+  PrefixIterator operator+(const int& rhs) const {
+    return PrefixIterator(prefixes_, index_ + rhs, size_);
+  }
+  PrefixIterator operator-(const int& rhs) const {
+    return PrefixIterator(prefixes_, index_ - rhs, size_);
+  }
+
+  bool operator==(const PrefixIterator& rhs) const {
+    return index_ == rhs.index_;
+  }
+  bool operator!=(const PrefixIterator& rhs) const {
+    return index_ != rhs.index_;
+  }
+  bool operator>(const PrefixIterator& rhs) const {
+    return index_ > rhs.index_;
+  }
+  bool operator<(const PrefixIterator& rhs) const {
+    return index_ < rhs.index_;
+  }
+  bool operator>=(const PrefixIterator& rhs) const {
+    return index_ >= rhs.index_;
+  }
+  bool operator<=(const PrefixIterator& rhs) const {
+    return index_ <= rhs.index_;
+  }
+
+ private:
+  base::StringPiece GetPiece(size_t index) const {
+    return prefixes_.substr(index * size_, size_);
+  }
+
+  base::StringPiece prefixes_;
+  size_t index_;
+  size_t size_;
+};
+
+}  // namespace safe_browsing
+
+#endif  // COMPONENTS_SAFE_BROWSING_DB_PREFIX_ITERATOR_H_
diff --git a/components/safe_browsing/db/v4_store.cc b/components/safe_browsing/db/v4_store.cc
index 3ebcfcd..5911ca1 100644
--- a/components/safe_browsing/db/v4_store.cc
+++ b/components/safe_browsing/db/v4_store.cc
@@ -4,6 +4,7 @@
 
 #include "components/safe_browsing/db/v4_store.h"
 
+#include <algorithm>
 #include <utility>
 
 #include "base/base64.h"
@@ -13,6 +14,7 @@
 #include "base/metrics/histogram_macros.h"
 #include "base/stl_util.h"
 #include "base/strings/stringprintf.h"
+#include "components/safe_browsing/db/prefix_iterator.h"
 #include "components/safe_browsing/db/v4_rice.h"
 #include "components/safe_browsing/db/v4_store.pb.h"
 #include "components/safe_browsing/proto/webui.pb.h"
@@ -782,37 +784,20 @@
   checks_attempted_++;
   for (const auto& pair : hash_prefix_map_) {
     const PrefixSize& prefix_size = pair.first;
-    const HashPrefixes& hash_prefixes = pair.second;
-    HashPrefix hash_prefix = full_hash.substr(0, prefix_size);
-    if (HashPrefixMatches(hash_prefix, hash_prefixes.begin(),
-                          hash_prefixes.end())) {
-      return hash_prefix;
-    }
+    base::StringPiece hash_prefix =
+        base::StringPiece(full_hash).substr(0, prefix_size);
+    if (HashPrefixMatches(hash_prefix, pair.second, prefix_size))
+      return hash_prefix.as_string();
   }
   return HashPrefix();
 }
 
-// static
-bool V4Store::HashPrefixMatches(const HashPrefix& hash_prefix,
-                                const HashPrefixes::const_iterator& begin,
-                                const HashPrefixes::const_iterator& end) {
-  if (begin == end) {
-    return false;
-  }
-  size_t distance = std::distance(begin, end);
-  const PrefixSize prefix_size = hash_prefix.length();
-  DCHECK_EQ(0u, distance % prefix_size);
-  size_t mid_prefix_index = ((distance / prefix_size) / 2) * prefix_size;
-  HashPrefixes::const_iterator mid = begin + mid_prefix_index;
-  HashPrefix mid_prefix = HashPrefix(mid, mid + prefix_size);
-  int result = hash_prefix.compare(mid_prefix);
-  if (result == 0) {
-    return true;
-  } else if (result < 0) {
-    return HashPrefixMatches(hash_prefix, begin, mid);
-  } else {
-    return HashPrefixMatches(hash_prefix, mid + prefix_size, end);
-  }
+bool V4Store::HashPrefixMatches(base::StringPiece prefix,
+                                const HashPrefixes& prefixes,
+                                const PrefixSize& size) {
+  return std::binary_search(
+      PrefixIterator(prefixes, 0, size),
+      PrefixIterator(prefixes, prefixes.size() / size, size), prefix);
 }
 
 bool V4Store::VerifyChecksum() {
diff --git a/components/safe_browsing/db/v4_store.h b/components/safe_browsing/db/v4_store.h
index 4477e33..6db059f 100644
--- a/components/safe_browsing/db/v4_store.h
+++ b/components/safe_browsing/db/v4_store.h
@@ -319,10 +319,11 @@
       const IteratorMap& iterator_map,
       HashPrefix* smallest_hash_prefix);
 
-  // Returns true if |hash_prefix| exists between |begin| and |end| iterators.
-  static bool HashPrefixMatches(const HashPrefix& hash_prefix,
-                                const HashPrefixes::const_iterator& begin,
-                                const HashPrefixes::const_iterator& end);
+  // Returns true if |hash_prefix| with PrefixSize |size| exists in |prefixes|.
+  // This small method is exposed in the header so it can be tested separately.
+  static bool HashPrefixMatches(base::StringPiece prefix,
+                                const HashPrefixes& prefixes,
+                                const PrefixSize& size);
 
   // For each key in |hash_prefix_map|, sets the iterator at that key
   // |iterator_map| to hash_prefix_map[key].begin().
diff --git a/components/safe_browsing/db/v4_store_perftest.cc b/components/safe_browsing/db/v4_store_perftest.cc
new file mode 100644
index 0000000..e187dc4
--- /dev/null
+++ b/components/safe_browsing/db/v4_store_perftest.cc
@@ -0,0 +1,51 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/strings/stringprintf.h"
+#include "base/test/test_simple_task_runner.h"
+#include "base/timer/elapsed_timer.h"
+#include "components/safe_browsing/db/v4_protocol_manager_util.h"
+#include "components/safe_browsing/db/v4_test_util.h"
+#include "crypto/sha2.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/perf/perf_test.h"
+
+namespace safe_browsing {
+
+class V4StorePerftest : public testing::Test {};
+
+TEST_F(V4StorePerftest, StressTest) {
+  const int kNumPrefixes = 2000000;
+  std::vector<std::string> prefixes;
+  std::vector<std::string> full_hashes;
+  for (size_t i = 0; i < kNumPrefixes; i++) {
+    std::string sha256 = crypto::SHA256HashString(base::StringPrintf("%zu", i));
+    DCHECK_EQ(crypto::kSHA256Length, kMaxHashPrefixLength);
+    full_hashes.push_back(sha256);
+    prefixes.push_back(sha256.substr(0, kMinHashPrefixLength));
+  }
+
+  auto store = std::make_unique<TestV4Store>(
+      base::MakeRefCounted<base::TestSimpleTaskRunner>(), base::FilePath());
+  store->SetPrefixes(std::move(prefixes), kMinHashPrefixLength);
+
+  size_t matches = 0;
+  base::ElapsedTimer timer;
+  for (const auto& full_hash : full_hashes) {
+    matches += !store->GetMatchingHashPrefix(full_hash).empty();
+  }
+  perf_test::PrintResult("GetMachingHashPrefix", "", "",
+                         timer.Elapsed().InMillisecondsF(), "ms", true);
+
+  EXPECT_EQ(matches, full_hashes.size());
+}
+
+}  // namespace safe_browsing
diff --git a/components/safe_browsing/db/v4_store_unittest.cc b/components/safe_browsing/db/v4_store_unittest.cc
index c37efae..5f5e525 100644
--- a/components/safe_browsing/db/v4_store_unittest.cc
+++ b/components/safe_browsing/db/v4_store_unittest.cc
@@ -593,43 +593,37 @@
 TEST_F(V4StoreTest, TestHashPrefixExistsAtTheBeginning) {
   HashPrefixes hash_prefixes = "abcdebbbbbccccc";
   HashPrefix hash_prefix = "abcde";
-  EXPECT_TRUE(V4Store::HashPrefixMatches(hash_prefix, std::begin(hash_prefixes),
-                                         std::end(hash_prefixes)));
+  EXPECT_TRUE(V4Store::HashPrefixMatches(hash_prefix, hash_prefixes, 5));
 }
 
 TEST_F(V4StoreTest, TestHashPrefixExistsInTheMiddle) {
   HashPrefixes hash_prefixes = "abcdebbbbbccccc";
   HashPrefix hash_prefix = "bbbbb";
-  EXPECT_TRUE(V4Store::HashPrefixMatches(hash_prefix, std::begin(hash_prefixes),
-                                         std::end(hash_prefixes)));
+  EXPECT_TRUE(V4Store::HashPrefixMatches(hash_prefix, hash_prefixes, 5));
 }
 
 TEST_F(V4StoreTest, TestHashPrefixExistsAtTheEnd) {
   HashPrefixes hash_prefixes = "abcdebbbbbccccc";
   HashPrefix hash_prefix = "ccccc";
-  EXPECT_TRUE(V4Store::HashPrefixMatches(hash_prefix, std::begin(hash_prefixes),
-                                         std::end(hash_prefixes)));
+  EXPECT_TRUE(V4Store::HashPrefixMatches(hash_prefix, hash_prefixes, 5));
 }
 
 TEST_F(V4StoreTest, TestHashPrefixExistsAtTheBeginningOfEven) {
   HashPrefixes hash_prefixes = "abcdebbbbb";
   HashPrefix hash_prefix = "abcde";
-  EXPECT_TRUE(V4Store::HashPrefixMatches(hash_prefix, std::begin(hash_prefixes),
-                                         std::end(hash_prefixes)));
+  EXPECT_TRUE(V4Store::HashPrefixMatches(hash_prefix, hash_prefixes, 5));
 }
 
 TEST_F(V4StoreTest, TestHashPrefixExistsAtTheEndOfEven) {
   HashPrefixes hash_prefixes = "abcdebbbbb";
   HashPrefix hash_prefix = "bbbbb";
-  EXPECT_TRUE(V4Store::HashPrefixMatches(hash_prefix, std::begin(hash_prefixes),
-                                         std::end(hash_prefixes)));
+  EXPECT_TRUE(V4Store::HashPrefixMatches(hash_prefix, hash_prefixes, 5));
 }
 
 TEST_F(V4StoreTest, TestHashPrefixDoesNotExistInConcatenatedList) {
   HashPrefixes hash_prefixes = "abcdebbbbb";
   HashPrefix hash_prefix = "bbbbc";
-  EXPECT_FALSE(V4Store::HashPrefixMatches(
-      hash_prefix, std::begin(hash_prefixes), std::end(hash_prefixes)));
+  EXPECT_FALSE(V4Store::HashPrefixMatches(hash_prefix, hash_prefixes, 5));
 }
 
 TEST_F(V4StoreTest, TestFullHashExistsInMapWithSingleSize) {
diff --git a/components/safe_browsing/db/v4_test_util.cc b/components/safe_browsing/db/v4_test_util.cc
index 59eb8dc..cc275f8 100644
--- a/components/safe_browsing/db/v4_test_util.cc
+++ b/components/safe_browsing/db/v4_test_util.cc
@@ -4,9 +4,11 @@
 
 #include "components/safe_browsing/db/v4_test_util.h"
 
+#include <algorithm>
 #include <string>
 #include <utility>
 
+#include "base/strings/strcat.h"
 #include "components/safe_browsing/db/util.h"
 #include "crypto/sha2.h"
 
@@ -47,7 +49,16 @@
 }
 
 void TestV4Store::MarkPrefixAsBad(HashPrefix prefix) {
-  hash_prefix_map_[prefix.size()] += prefix;
+  auto& vec = mock_prefixes_[prefix.size()];
+  vec.insert(std::upper_bound(vec.begin(), vec.end(), prefix), prefix);
+  hash_prefix_map_[prefix.size()] = base::StrCat(vec);
+}
+
+void TestV4Store::SetPrefixes(std::vector<HashPrefix> prefixes,
+                              PrefixSize size) {
+  std::sort(prefixes.begin(), prefixes.end());
+  mock_prefixes_[size] = prefixes;
+  hash_prefix_map_[size] = base::StrCat(prefixes);
 }
 
 TestV4Database::TestV4Database(
diff --git a/components/safe_browsing/db/v4_test_util.h b/components/safe_browsing/db/v4_test_util.h
index 693f988..ddf1327 100644
--- a/components/safe_browsing/db/v4_test_util.h
+++ b/components/safe_browsing/db/v4_test_util.h
@@ -7,8 +7,10 @@
 
 // Contains classes and methods useful for tests.
 
+#include <map>
 #include <memory>
 #include <ostream>
+#include <vector>
 
 #include "components/safe_browsing/db/v4_database.h"
 #include "components/safe_browsing/db/v4_get_hash_protocol_manager.h"
@@ -31,6 +33,14 @@
   bool HasValidData() const override;
 
   void MarkPrefixAsBad(HashPrefix prefix);
+
+  // |prefixes| does not need to be sorted.
+  void SetPrefixes(std::vector<HashPrefix> prefixes, PrefixSize size);
+
+ private:
+  // Holds mock prefixes from calls to MarkPrefixAsBad / SetPrefixes. Stored as
+  // a vector for simplicity.
+  std::map<PrefixSize, std::vector<HashPrefix>> mock_prefixes_;
 };
 
 class TestV4StoreFactory : public V4StoreFactory {
diff --git a/components/signin/core/browser/android/java/src/org/chromium/components/signin/SystemAccountManagerDelegate.java b/components/signin/core/browser/android/java/src/org/chromium/components/signin/SystemAccountManagerDelegate.java
index b4ddb9a..4604ac1 100644
--- a/components/signin/core/browser/android/java/src/org/chromium/components/signin/SystemAccountManagerDelegate.java
+++ b/components/signin/core/browser/android/java/src/org/chromium/components/signin/SystemAccountManagerDelegate.java
@@ -35,7 +35,6 @@
 import org.chromium.base.Log;
 import org.chromium.base.ObserverList;
 import org.chromium.base.ThreadUtils;
-import org.chromium.base.annotations.MainDex;
 import org.chromium.base.library_loader.LibraryLoader;
 import org.chromium.base.metrics.RecordHistogram;
 
@@ -46,7 +45,6 @@
  * Default implementation of {@link AccountManagerDelegate} which delegates all calls to the
  * Android account manager.
  */
-@MainDex
 public class SystemAccountManagerDelegate implements AccountManagerDelegate {
     private final AccountManager mAccountManager;
     private final ObserverList<AccountsChangeObserver> mObservers = new ObserverList<>();
diff --git a/components/sync/driver/about_sync_util.cc b/components/sync/driver/about_sync_util.cc
index f848f68..23921e0 100644
--- a/components/sync/driver/about_sync_util.cc
+++ b/components/sync/driver/about_sync_util.cc
@@ -6,12 +6,11 @@
 
 #include <string>
 #include <utility>
+#include <vector>
 
-#include "base/location.h"
 #include "base/logging.h"
-#include "base/memory/ptr_util.h"
-#include "base/strings/string16.h"
 #include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
 #include "components/signin/core/browser/signin_manager_base.h"
 #include "components/strings/grit/components_strings.h"
@@ -24,9 +23,6 @@
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/l10n/time_format.h"
 
-using base::DictionaryValue;
-using base::ListValue;
-
 namespace syncer {
 
 namespace sync_ui_util {
@@ -77,156 +73,112 @@
 
 namespace {
 
-// Creates a 'section' for display on about:sync, consisting of a title and a
-// list of fields.  Returns a pointer to the new section.  Note that
-// |parent_list|, not the caller, owns the newly added section.
-base::ListValue* AddSection(base::ListValue* parent_list,
-                            const std::string& title) {
-  auto section = std::make_unique<base::DictionaryValue>();
-  section->SetString("title", title);
-  base::ListValue* section_contents =
-      section->SetList("data", std::make_unique<base::ListValue>());
-  section->SetBoolean("is_sensitive", false);
-  // If the following |Append| results in a reallocation, pointers to the
-  // members of |parent_list| will be invalidated. This would result in
-  // use-after-free in |*SyncStat::SetValue|. This is why the following DCHECK
-  // is necessary to ensure no reallocation takes place.
-  // TODO(crbug.com/702230): Remove the usages of raw pointers in this file.
-  DCHECK_LT(parent_list->GetSize(), parent_list->GetList().capacity());
-  parent_list->Append(std::move(section));
-  return section_contents;
-}
+const char kUninitialized[] = "Uninitialized";
 
-// Same as AddSection, but for data that should be elided when dumped into text
-// form and posted in a public forum (e.g. unique identifiers).
-base::ListValue* AddSensitiveSection(base::ListValue* parent_list,
-                                     const std::string& title) {
-  auto section = std::make_unique<base::DictionaryValue>();
-  section->SetString("title", title);
-  base::ListValue* section_contents =
-      section->SetList("data", std::make_unique<base::ListValue>());
-  section->SetBoolean("is_sensitive", true);
-  // If the following |Append| results in a reallocation, pointers to
-  // |parent_list| and its members will be invalidated. This would result in
-  // use-after-free in |*SyncStat::SetValue|. This is why the following DCHECK
-  // is necessary to ensure no reallocation takes place.
-  DCHECK_LT(parent_list->GetSize(), parent_list->GetList().capacity());
-  // TODO(crbug.com/702230): Remove the usages of raw pointers in this file.
-  parent_list->Append(std::move(section));
-  return section_contents;
-}
-
-// The following helper classes help manage the about:sync fields which will be
-// populated in method in ConstructAboutInformation.
-//
-// Each instance of one of thse classes indicates a field in about:sync.  Each
-// field will be serialized to a DictionaryValue with entries for 'stat_name',
-// 'stat_value' and 'is_valid'.
-
-class StringSyncStat {
+// This class represents one field in about:sync. It gets serialized into a
+// dictionary with entries for 'stat_name', 'stat_value' and 'is_valid'.
+class StatBase {
  public:
-  StringSyncStat(base::ListValue* section, const std::string& key);
-  void SetValue(const std::string& value);
-  void SetValue(const base::string16& value);
+  base::Value ToValue() const {
+    base::Value result(base::Value::Type::DICTIONARY);
+    result.SetKey("stat_name", base::Value(key_));
+    result.SetKey("stat_value", value_.Clone());
+    result.SetKey("is_valid", base::Value(is_valid_));
+    return result;
+  }
+
+ protected:
+  StatBase(const std::string& key, base::Value default_value)
+      : key_(key), value_(std::move(default_value)) {}
+
+  void SetFromValue(base::Value value) {
+    value_ = std::move(value);
+    is_valid_ = true;
+  }
 
  private:
-  // Owned by the |section| passed in during construction.
-  base::DictionaryValue* stat_;
+  std::string key_;
+  base::Value value_;
+  bool is_valid_ = false;
 };
 
-StringSyncStat::StringSyncStat(base::ListValue* section,
-                               const std::string& key) {
-  stat_ = new base::DictionaryValue();
-  stat_->SetString("stat_name", key);
-  stat_->SetString("stat_value", "Uninitialized");
-  stat_->SetBoolean("is_valid", false);
-  // |stat_| will be invalidated by |Append|, so it needs to be reset.
-  // Furthermore, if |Append| results in a reallocation, |stat_| members of
-  // other SyncStats will be invalidated. This is why the following dcheck is
-  // necessary, so that it is guaranteed that a reallocation will not happen.
-  // TODO(crbug.com/702230): Remove the usages of raw pointers in this file.
-  DCHECK_LT(section->GetSize(), section->GetList().capacity());
-  section->Append(base::WrapUnique(stat_));
-  section->GetDictionary(section->GetSize() - 1, &stat_);
-}
-
-void StringSyncStat::SetValue(const std::string& value) {
-  stat_->SetString("stat_value", value);
-  stat_->SetBoolean("is_valid", true);
-}
-
-void StringSyncStat::SetValue(const base::string16& value) {
-  stat_->SetString("stat_value", value);
-  stat_->SetBoolean("is_valid", true);
-}
-
-class BoolSyncStat {
+template <typename T>
+class Stat : public StatBase {
  public:
-  BoolSyncStat(base::ListValue* section, const std::string& key);
-  void SetValue(bool value);
+  Stat(const std::string& key, const T& default_value)
+      : StatBase(key, base::Value(default_value)) {}
+
+  void Set(const T& value) { SetFromValue(base::Value(value)); }
+};
+
+// A section for display on about:sync, consisting of a title and a list of
+// fields.
+class Section {
+ public:
+  explicit Section(const std::string& title) : title_(title) {}
+
+  void MarkSensitive() { is_sensitive_ = true; }
+
+  Stat<bool>* AddBoolStat(const std::string& key) {
+    return AddStat(key, false);
+  }
+  Stat<int>* AddIntStat(const std::string& key) { return AddStat(key, 0); }
+  Stat<std::string>* AddStringStat(const std::string& key) {
+    return AddStat(key, std::string(kUninitialized));
+  }
+
+  base::Value ToValue() const {
+    base::Value result(base::Value::Type::DICTIONARY);
+    result.SetKey("title", base::Value(title_));
+    base::Value stats(base::Value::Type::LIST);
+    for (const std::unique_ptr<StatBase>& stat : stats_)
+      stats.GetList().push_back(stat->ToValue());
+    result.SetKey("data", std::move(stats));
+    result.SetKey("is_sensitive", base::Value(is_sensitive_));
+    return result;
+  }
 
  private:
-  // Owned by the |section| passed in during construction.
-  base::DictionaryValue* stat_;
+  template <typename T>
+  Stat<T>* AddStat(const std::string& key, const T& default_value) {
+    auto stat = std::make_unique<Stat<T>>(key, default_value);
+    Stat<T>* result = stat.get();
+    stats_.push_back(std::move(stat));
+    return result;
+  }
+
+  std::string title_;
+  std::vector<std::unique_ptr<StatBase>> stats_;
+  bool is_sensitive_ = false;
 };
 
-BoolSyncStat::BoolSyncStat(base::ListValue* section, const std::string& key) {
-  stat_ = new base::DictionaryValue();
-  stat_->SetString("stat_name", key);
-  stat_->SetBoolean("stat_value", false);
-  stat_->SetBoolean("is_valid", false);
-  // |stat_| will be invalidated by |Append|, so it needs to be reset.
-  // Furthermore, if |Append| results in a reallocation, |stat_| members of
-  // other SyncStats will be invalidated. This is why the following dcheck is
-  // necessary, so that it is guaranteed that a reallocation will not happen.
-  // TODO(crbug.com/702230): Remove the usages of raw pointers in this file.
-  DCHECK_LT(section->GetSize(), section->GetList().capacity());
-  section->Append(base::WrapUnique(stat_));
-  section->GetDictionary(section->GetSize() - 1, &stat_);
-}
-
-void BoolSyncStat::SetValue(bool value) {
-  stat_->SetBoolean("stat_value", value);
-  stat_->SetBoolean("is_valid", true);
-}
-
-class IntSyncStat {
+class SectionList {
  public:
-  IntSyncStat(base::ListValue* section, const std::string& key);
-  void SetValue(int value);
+  SectionList() = default;
+
+  Section* AddSection(const std::string& title) {
+    sections_.push_back(std::make_unique<Section>(title));
+    return sections_.back().get();
+  }
+
+  base::Value ToValue() const {
+    base::Value result(base::Value::Type::LIST);
+    for (const std::unique_ptr<Section>& section : sections_)
+      result.GetList().push_back(section->ToValue());
+    return result;
+  }
 
  private:
-  // Owned by the |section| passed in during construction.
-  base::DictionaryValue* stat_;
+  std::vector<std::unique_ptr<Section>> sections_;
 };
 
-IntSyncStat::IntSyncStat(base::ListValue* section, const std::string& key) {
-  stat_ = new base::DictionaryValue();
-  stat_->SetString("stat_name", key);
-  stat_->SetInteger("stat_value", 0);
-  stat_->SetBoolean("is_valid", false);
-  // |stat_| will be invalidated by |Append|, so it needs to be reset.
-  // Furthermore, if |Append| results in a reallocation, |stat_| members of
-  // other SyncStats will be invalidated. This is why the following dcheck is
-  // necessary, so that it is guaranteed that a reallocation will not happen.
-  // TODO(crbug.com/702230): Remove the usages of raw pointers in this file.
-  DCHECK_LT(section->GetSize(), section->GetList().capacity());
-  section->Append(base::WrapUnique(stat_));
-  section->GetDictionary(section->GetSize() - 1, &stat_);
-}
-
-void IntSyncStat::SetValue(int value) {
-  stat_->SetInteger("stat_value", value);
-  stat_->SetBoolean("is_valid", true);
-}
-
 // Returns a string describing the chrome version environment. Version format:
 // <Build Info> <OS> <Version number> (<Last change>)<channel or "-devel">
 // If version information is unavailable, returns "invalid."
-// TODO(zea): this approximately matches MakeUserAgentForSyncApi in
-// sync_backend_host.cc. Unify the two if possible.
+// TODO(zea): this approximately matches syncer::MakeUserAgentForSync in
+// sync_util.h. Unify the two if possible.
 std::string GetVersionString(version_info::Channel channel) {
-  // Build a version string that matches MakeUserAgentForSyncApi with the
+  // Build a version string that matches syncer::MakeUserAgentForSync with the
   // addition of channel info and proper OS names.
   // chrome::GetChannelString() returns empty string for stable channel or
   // unofficial builds, the channel string otherwise. We want to have "-devel"
@@ -253,45 +205,39 @@
   return time_str;
 }
 
-base::string16 GetLastSyncedTimeString(base::Time last_synced_time) {
+std::string GetLastSyncedTimeString(base::Time last_synced_time) {
   if (last_synced_time.is_null())
-    return l10n_util::GetStringUTF16(IDS_SYNC_TIME_NEVER);
+    return l10n_util::GetStringUTF8(IDS_SYNC_TIME_NEVER);
 
   base::TimeDelta time_since_last_sync = base::Time::Now() - last_synced_time;
 
   if (time_since_last_sync < base::TimeDelta::FromMinutes(1))
-    return l10n_util::GetStringUTF16(IDS_SYNC_TIME_JUST_NOW);
+    return l10n_util::GetStringUTF8(IDS_SYNC_TIME_JUST_NOW);
 
-  return ui::TimeFormat::Simple(ui::TimeFormat::FORMAT_ELAPSED,
-                                ui::TimeFormat::LENGTH_SHORT,
-                                time_since_last_sync);
+  return base::UTF16ToUTF8(ui::TimeFormat::Simple(
+      ui::TimeFormat::FORMAT_ELAPSED, ui::TimeFormat::LENGTH_SHORT,
+      time_since_last_sync));
 }
 
 std::string GetConnectionStatus(const SyncService::SyncTokenStatus& status) {
-  std::string message;
   switch (status.connection_status) {
     case CONNECTION_NOT_ATTEMPTED:
-      base::StringAppendF(&message, "not attempted");
-      break;
+      return "not attempted";
     case CONNECTION_OK:
-      base::StringAppendF(
-          &message, "OK since %s",
+      return base::StringPrintf(
+          "OK since %s",
           GetTimeStr(status.connection_status_update_time, "n/a").c_str());
-      break;
     case CONNECTION_AUTH_ERROR:
-      base::StringAppendF(
-          &message, "auth error since %s",
+      return base::StringPrintf(
+          "auth error since %s",
           GetTimeStr(status.connection_status_update_time, "n/a").c_str());
-      break;
     case CONNECTION_SERVER_ERROR:
-      base::StringAppendF(
-          &message, "server error since %s",
+      return base::StringPrintf(
+          "server error since %s",
           GetTimeStr(status.connection_status_update_time, "n/a").c_str());
-      break;
-    default:
-      NOTREACHED();
   }
-  return message;
+  NOTREACHED();
+  return std::string();
 }
 
 }  // namespace
@@ -316,261 +262,258 @@
     version_info::Channel channel) {
   auto about_info = std::make_unique<base::DictionaryValue>();
 
-  // 'details': A list of sections.
-  auto stats_list = std::make_unique<base::ListValue>();
-  // TODO(crbug.com/702230): Remove the usages of raw pointers in this file.
-  stats_list->Reserve(12);
+  SectionList section_list;
 
-  // The following lines define the sections and their fields.  For each field,
-  // a class is instantiated, which allows us to reference the fields in
-  // 'setter' code later on in this function.
-  base::ListValue* section_summary = AddSection(stats_list.get(), "Summary");
-  // TODO(crbug.com/702230): Remove the usages of raw pointers in this file.
-  section_summary->Reserve(1);
-  StringSyncStat summary_string(section_summary, "Summary");
+  Section* section_summary = section_list.AddSection("Summary");
+  Stat<std::string>* summary_string = section_summary->AddStringStat("Summary");
 
-  base::ListValue* section_version =
-      AddSection(stats_list.get(), "Version Info");
-  // TODO(crbug.com/702230): Remove the usages of raw pointers in this file.
-  section_version->Reserve(2);
-  StringSyncStat client_version(section_version, "Client Version");
-  StringSyncStat server_url(section_version, "Server URL");
+  Section* section_version = section_list.AddSection("Version Info");
+  Stat<std::string>* client_version =
+      section_version->AddStringStat("Client Version");
+  Stat<std::string>* server_url = section_version->AddStringStat("Server URL");
 
-  base::ListValue* section_identity =
-      AddSensitiveSection(stats_list.get(), kIdentityTitle);
-  // TODO(crbug.com/702230): Remove the usages of raw pointers in this file.
-  section_identity->Reserve(3);
-  StringSyncStat sync_id(section_identity, "Sync Client ID");
-  StringSyncStat invalidator_id(section_identity, "Invalidator Client ID");
-  StringSyncStat username(section_identity, "Username");
+  Section* section_identity = section_list.AddSection(kIdentityTitle);
+  section_identity->MarkSensitive();
+  Stat<std::string>* sync_id =
+      section_identity->AddStringStat("Sync Client ID");
+  Stat<std::string>* invalidator_id =
+      section_identity->AddStringStat("Invalidator Client ID");
+  Stat<std::string>* username = section_identity->AddStringStat("Username");
 
-  base::ListValue* section_credentials =
-      AddSection(stats_list.get(), "Credentials");
-  // TODO(crbug.com/702230): Remove the usages of raw pointers in this file.
-  section_credentials->Reserve(4);
-  StringSyncStat request_token_time(section_credentials, "Requested Token");
-  StringSyncStat receive_token_time(section_credentials, "Received Token");
-  StringSyncStat token_request_status(section_credentials,
-                                      "Token Request Status");
-  StringSyncStat next_token_request(section_credentials, "Next Token Request");
+  Section* section_credentials = section_list.AddSection("Credentials");
+  Stat<std::string>* request_token_time =
+      section_credentials->AddStringStat("Requested Token");
+  Stat<std::string>* receive_token_time =
+      section_credentials->AddStringStat("Received Token");
+  Stat<std::string>* token_request_status =
+      section_credentials->AddStringStat("Token Request Status");
+  Stat<std::string>* next_token_request =
+      section_credentials->AddStringStat("Next Token Request");
 
-  base::ListValue* section_local = AddSection(stats_list.get(), "Local State");
-  // TODO(crbug.com/702230): Remove the usages of raw pointers in this file.
-  section_local->Reserve(7);
-  StringSyncStat server_connection(section_local, "Server Connection");
-  StringSyncStat last_synced(section_local, "Last Synced");
-  BoolSyncStat is_setup_complete(section_local,
-                                 "Sync First-Time Setup Complete");
-  StringSyncStat backend_initialization(section_local,
-                                        "Sync Backend Initialization");
-  BoolSyncStat is_syncing(section_local, "Syncing");
-  BoolSyncStat is_local_sync_enabled(section_local,
-                                     "Local Sync Backend Enabled");
-  StringSyncStat local_backend_path(section_local, "Local Backend Path");
+  Section* section_local = section_list.AddSection("Local State");
+  Stat<std::string>* server_connection =
+      section_local->AddStringStat("Server Connection");
+  Stat<std::string>* last_synced = section_local->AddStringStat("Last Synced");
+  Stat<bool>* is_setup_complete =
+      section_local->AddBoolStat("Sync First-Time Setup Complete");
+  Stat<std::string>* backend_initialization =
+      section_local->AddStringStat("Sync Backend Initialization");
+  Stat<bool>* is_syncing = section_local->AddBoolStat("Syncing");
+  Stat<bool>* is_local_sync_enabled =
+      section_local->AddBoolStat("Local Sync Backend Enabled");
+  Stat<std::string>* local_backend_path =
+      section_local->AddStringStat("Local Backend Path");
 
-  base::ListValue* section_network = AddSection(stats_list.get(), "Network");
-  // TODO(crbug.com/702230): Remove the usages of raw pointers in this file.
-  section_network->Reserve(3);
-  BoolSyncStat is_any_throttled_or_backoff(section_network,
-                                           "Throttled or Backoff");
-  StringSyncStat retry_time(section_network, "Retry Time");
-  BoolSyncStat are_notifications_enabled(section_network,
-                                         "Notifications Enabled");
+  Section* section_network = section_list.AddSection("Network");
+  Stat<bool>* is_any_throttled_or_backoff =
+      section_network->AddBoolStat("Throttled or Backoff");
+  Stat<std::string>* retry_time = section_network->AddStringStat("Retry Time");
+  Stat<bool>* are_notifications_enabled =
+      section_network->AddBoolStat("Notifications Enabled");
 
-  base::ListValue* section_encryption =
-      AddSection(stats_list.get(), "Encryption");
-  // TODO(crbug.com/702230): Remove the usages of raw pointers in this file.
-  section_encryption->Reserve(9);
-  BoolSyncStat is_using_explicit_passphrase(section_encryption,
-                                            "Explicit Passphrase");
-  BoolSyncStat is_passphrase_required(section_encryption,
-                                      "Passphrase Required");
-  BoolSyncStat is_cryptographer_ready(section_encryption,
-                                      "Cryptographer Ready");
-  BoolSyncStat has_pending_keys(section_encryption,
-                                "Cryptographer Has Pending Keys");
-  StringSyncStat encrypted_types(section_encryption, "Encrypted Types");
-  BoolSyncStat has_keystore_key(section_encryption, "Has Keystore Key");
-  StringSyncStat keystore_migration_time(section_encryption,
-                                         "Keystore Migration Time");
-  StringSyncStat passphrase_type(section_encryption, "Passphrase Type");
-  StringSyncStat passphrase_time(section_encryption, "Passphrase Time");
+  Section* section_encryption = section_list.AddSection("Encryption");
+  Stat<bool>* is_using_explicit_passphrase =
+      section_encryption->AddBoolStat("Explicit Passphrase");
+  Stat<bool>* is_passphrase_required =
+      section_encryption->AddBoolStat("Passphrase Required");
+  Stat<bool>* is_cryptographer_ready =
+      section_encryption->AddBoolStat("Cryptographer Ready");
+  Stat<bool>* has_pending_keys =
+      section_encryption->AddBoolStat("Cryptographer Has Pending Keys");
+  Stat<std::string>* encrypted_types =
+      section_encryption->AddStringStat("Encrypted Types");
+  Stat<bool>* has_keystore_key =
+      section_encryption->AddBoolStat("Has Keystore Key");
+  Stat<std::string>* keystore_migration_time =
+      section_encryption->AddStringStat("Keystore Migration Time");
+  Stat<std::string>* passphrase_type =
+      section_encryption->AddStringStat("Passphrase Type");
+  Stat<std::string>* passphrase_time =
+      section_encryption->AddStringStat("Passphrase Time");
 
-  base::ListValue* section_last_session =
-      AddSection(stats_list.get(), "Status from Last Completed Session");
-  // TODO(crbug.com/702230): Remove the usages of raw pointers in this file.
-  section_last_session->Reserve(4);
-  StringSyncStat session_source(section_last_session, "Sync Source");
-  StringSyncStat get_key_result(section_last_session, "GetKey Step Result");
-  StringSyncStat download_result(section_last_session, "Download Step Result");
-  StringSyncStat commit_result(section_last_session, "Commit Step Result");
+  Section* section_last_session =
+      section_list.AddSection("Status from Last Completed Session");
+  Stat<std::string>* session_source =
+      section_last_session->AddStringStat("Sync Source");
+  Stat<std::string>* get_key_result =
+      section_last_session->AddStringStat("GetKey Step Result");
+  Stat<std::string>* download_result =
+      section_last_session->AddStringStat("Download Step Result");
+  Stat<std::string>* commit_result =
+      section_last_session->AddStringStat("Commit Step Result");
 
-  base::ListValue* section_counters =
-      AddSection(stats_list.get(), "Running Totals");
-  // TODO(crbug.com/702230): Remove the usages of raw pointers in this file.
-  section_counters->Reserve(7);
-  IntSyncStat notifications_received(section_counters,
-                                     "Notifications Received");
-  IntSyncStat updates_received(section_counters, "Updates Downloaded");
-  IntSyncStat tombstone_updates(section_counters, "Tombstone Updates");
-  IntSyncStat reflected_updates(section_counters, "Reflected Updates");
-  IntSyncStat successful_commits(section_counters, "Successful Commits");
-  IntSyncStat conflicts_resolved_local_wins(section_counters,
-                                            "Conflicts Resolved: Client Wins");
-  IntSyncStat conflicts_resolved_server_wins(section_counters,
-                                             "Conflicts Resolved: Server Wins");
+  Section* section_counters = section_list.AddSection("Running Totals");
+  Stat<int>* notifications_received =
+      section_counters->AddIntStat("Notifications Received");
+  Stat<int>* updates_received =
+      section_counters->AddIntStat("Updates Downloaded");
+  Stat<int>* tombstone_updates =
+      section_counters->AddIntStat("Tombstone Updates");
+  Stat<int>* reflected_updates =
+      section_counters->AddIntStat("Reflected Updates");
+  Stat<int>* successful_commits =
+      section_counters->AddIntStat("Successful Commits");
+  Stat<int>* conflicts_resolved_local_wins =
+      section_counters->AddIntStat("Conflicts Resolved: Client Wins");
+  Stat<int>* conflicts_resolved_server_wins =
+      section_counters->AddIntStat("Conflicts Resolved: Server Wins");
 
-  base::ListValue* section_this_cycle =
-      AddSection(stats_list.get(), "Transient Counters (this cycle)");
-  // TODO(crbug.com/702230): Remove the usages of raw pointers in this file.
-  section_this_cycle->Reserve(4);
-  IntSyncStat encryption_conflicts(section_this_cycle, "Encryption Conflicts");
-  IntSyncStat hierarchy_conflicts(section_this_cycle, "Hierarchy Conflicts");
-  IntSyncStat server_conflicts(section_this_cycle, "Server Conflicts");
-  IntSyncStat committed_items(section_this_cycle, "Committed Items");
+  Section* section_this_cycle =
+      section_list.AddSection("Transient Counters (this cycle)");
+  Stat<int>* encryption_conflicts =
+      section_this_cycle->AddIntStat("Encryption Conflicts");
+  Stat<int>* hierarchy_conflicts =
+      section_this_cycle->AddIntStat("Hierarchy Conflicts");
+  Stat<int>* server_conflicts =
+      section_this_cycle->AddIntStat("Server Conflicts");
+  Stat<int>* committed_items =
+      section_this_cycle->AddIntStat("Committed Items");
 
-  base::ListValue* section_that_cycle =
-      AddSection(stats_list.get(),
-                 "Transient Counters (last cycle of last completed session)");
-  // TODO(crbug.com/702230): Remove the usages of raw pointers in this file.
-  section_that_cycle->Reserve(3);
-  IntSyncStat updates_downloaded(section_that_cycle, "Updates Downloaded");
-  IntSyncStat committed_count(section_that_cycle, "Committed Count");
-  IntSyncStat entries(section_that_cycle, "Entries");
+  Section* section_that_cycle = section_list.AddSection(
+      "Transient Counters (last cycle of last completed session)");
+  Stat<int>* updates_downloaded =
+      section_that_cycle->AddIntStat("Updates Downloaded");
+  Stat<int>* committed_count =
+      section_that_cycle->AddIntStat("Committed Count");
+  Stat<int>* entries = section_that_cycle->AddIntStat("Entries");
 
-  base::ListValue* section_nudge_info =
-      AddSection(stats_list.get(), "Nudge Source Counters");
-  // TODO(crbug.com/702230): Remove the usages of raw pointers in this file.
-  section_nudge_info->Reserve(3);
-  IntSyncStat nudge_source_notification(section_nudge_info,
-                                        "Server Invalidations");
-  IntSyncStat nudge_source_local(section_nudge_info, "Local Changes");
-  IntSyncStat nudge_source_local_refresh(section_nudge_info, "Local Refreshes");
-
-  // This list of sections belongs in the 'details' field of the returned
-  // message.
-  about_info->Set(kDetailsKey, std::move(stats_list));
+  Section* section_nudge_info =
+      section_list.AddSection("Nudge Source Counters");
+  Stat<int>* nudge_source_notification =
+      section_nudge_info->AddIntStat("Server Invalidations");
+  Stat<int>* nudge_source_local =
+      section_nudge_info->AddIntStat("Local Changes");
+  Stat<int>* nudge_source_local_refresh =
+      section_nudge_info->AddIntStat("Local Refreshes");
 
   // Populate all the fields we declared above.
-  client_version.SetValue(GetVersionString(channel));
+  client_version->Set(GetVersionString(channel));
 
   if (!service) {
-    summary_string.SetValue("Sync service does not exist");
+    summary_string->Set("Sync service does not exist");
+    about_info->SetKey(kDetailsKey, section_list.ToValue());
     return about_info;
   }
 
   SyncStatus full_status;
   bool is_status_valid = service->QueryDetailedSyncStatus(&full_status);
-  bool sync_active = service->IsSyncActive();
   const SyncCycleSnapshot& snapshot = service->GetLastCycleSnapshot();
-
-  if (is_status_valid)
-    summary_string.SetValue(service->QuerySyncStatusSummaryString());
-
-  server_url.SetValue(service->sync_service_url().spec());
-
-  if (is_status_valid && !full_status.sync_id.empty())
-    sync_id.SetValue(full_status.sync_id);
-  if (is_status_valid && !full_status.invalidator_client_id.empty())
-    invalidator_id.SetValue(full_status.invalidator_client_id);
-
-  username.SetValue(primary_account_info.email);
-
   const SyncService::SyncTokenStatus& token_status =
       service->GetSyncTokenStatus();
-  server_connection.SetValue(GetConnectionStatus(token_status));
-  request_token_time.SetValue(
-      GetTimeStr(token_status.token_request_time, "n/a"));
-  receive_token_time.SetValue(
-      GetTimeStr(token_status.token_receive_time, "n/a"));
+
+  // Summary.
+  if (is_status_valid)
+    summary_string->Set(service->QuerySyncStatusSummaryString());
+
+  // Version Info.
+  // |client_version| was already set above.
+  server_url->Set(service->sync_service_url().spec());
+
+  // Identity.
+  if (is_status_valid && !full_status.sync_id.empty())
+    sync_id->Set(full_status.sync_id);
+  if (is_status_valid && !full_status.invalidator_client_id.empty())
+    invalidator_id->Set(full_status.invalidator_client_id);
+  username->Set(primary_account_info.email);
+
+  // Credentials.
+  request_token_time->Set(GetTimeStr(token_status.token_request_time, "n/a"));
+  receive_token_time->Set(GetTimeStr(token_status.token_receive_time, "n/a"));
   std::string err = token_status.last_get_token_error.error_message();
-  token_request_status.SetValue(err.empty() ? "OK" : err);
-  next_token_request.SetValue(
+  token_request_status->Set(err.empty() ? "OK" : err);
+  next_token_request->Set(
       GetTimeStr(token_status.next_token_request_time, "not scheduled"));
 
-  last_synced.SetValue(GetLastSyncedTimeString(service->GetLastSyncedTime()));
-  is_setup_complete.SetValue(service->IsFirstSetupComplete());
-  is_local_sync_enabled.SetValue(service->IsLocalSyncEnabled());
-  if (service->IsLocalSyncEnabled() && is_status_valid) {
-    local_backend_path.SetValue(full_status.local_sync_folder);
-  }
-  backend_initialization.SetValue(
-      service->GetEngineInitializationStateString());
-  if (is_status_valid) {
-    is_syncing.SetValue(full_status.syncing);
-    retry_time.SetValue(GetTimeStr(full_status.retry_time,
-                                   "Scheduler is not in backoff or throttled"));
-  }
+  // Local State.
+  server_connection->Set(GetConnectionStatus(token_status));
+  last_synced->Set(GetLastSyncedTimeString(service->GetLastSyncedTime()));
+  is_setup_complete->Set(service->IsFirstSetupComplete());
+  backend_initialization->Set(service->GetEngineInitializationStateString());
+  if (is_status_valid)
+    is_syncing->Set(full_status.syncing);
+  is_local_sync_enabled->Set(service->IsLocalSyncEnabled());
+  if (service->IsLocalSyncEnabled() && is_status_valid)
+    local_backend_path->Set(full_status.local_sync_folder);
 
+  // Network.
   if (snapshot.is_initialized())
-    is_any_throttled_or_backoff.SetValue(snapshot.is_silenced());
+    is_any_throttled_or_backoff->Set(snapshot.is_silenced());
   if (is_status_valid) {
-    are_notifications_enabled.SetValue(full_status.notifications_enabled);
+    retry_time->Set(GetTimeStr(full_status.retry_time,
+                               "Scheduler is not in backoff or throttled"));
   }
+  if (is_status_valid)
+    are_notifications_enabled->Set(full_status.notifications_enabled);
 
-  if (sync_active) {
-    is_using_explicit_passphrase.SetValue(
-        service->IsUsingSecondaryPassphrase());
-    is_passphrase_required.SetValue(service->IsPassphraseRequired());
-    passphrase_time.SetValue(
+  // Encryption.
+  if (service->IsSyncActive()) {
+    is_using_explicit_passphrase->Set(service->IsUsingSecondaryPassphrase());
+    is_passphrase_required->Set(service->IsPassphraseRequired());
+    passphrase_time->Set(
         GetTimeStr(service->GetExplicitPassphraseTime(), "No Passphrase Time"));
   }
   if (is_status_valid) {
-    is_cryptographer_ready.SetValue(full_status.cryptographer_ready);
-    has_pending_keys.SetValue(full_status.crypto_has_pending_keys);
-    encrypted_types.SetValue(ModelTypeSetToString(full_status.encrypted_types));
-    has_keystore_key.SetValue(full_status.has_keystore_key);
-    keystore_migration_time.SetValue(
+    is_cryptographer_ready->Set(full_status.cryptographer_ready);
+    has_pending_keys->Set(full_status.crypto_has_pending_keys);
+    encrypted_types->Set(ModelTypeSetToString(full_status.encrypted_types));
+    has_keystore_key->Set(full_status.has_keystore_key);
+    keystore_migration_time->Set(
         GetTimeStr(full_status.keystore_migration_time, "Not Migrated"));
-    passphrase_type.SetValue(
-        PassphraseTypeToString(full_status.passphrase_type));
+    passphrase_type->Set(PassphraseTypeToString(full_status.passphrase_type));
   }
 
+  // Status from Last Completed Session.
   if (snapshot.is_initialized()) {
     if (snapshot.get_updates_origin() != sync_pb::SyncEnums::UNKNOWN_ORIGIN) {
-      session_source.SetValue(ProtoEnumToString(snapshot.get_updates_origin()));
+      session_source->Set(ProtoEnumToString(snapshot.get_updates_origin()));
     }
-    get_key_result.SetValue(GetSyncerErrorString(
+    get_key_result->Set(GetSyncerErrorString(
         snapshot.model_neutral_state().last_get_key_result));
-    download_result.SetValue(GetSyncerErrorString(
+    download_result->Set(GetSyncerErrorString(
         snapshot.model_neutral_state().last_download_updates_result));
-    commit_result.SetValue(
+    commit_result->Set(
         GetSyncerErrorString(snapshot.model_neutral_state().commit_result));
   }
 
+  // Running Totals.
   if (is_status_valid) {
-    notifications_received.SetValue(full_status.notifications_received);
-    updates_received.SetValue(full_status.updates_received);
-    tombstone_updates.SetValue(full_status.tombstone_updates_received);
-    reflected_updates.SetValue(full_status.reflected_updates_received);
-    successful_commits.SetValue(full_status.num_commits_total);
-    conflicts_resolved_local_wins.SetValue(
-        full_status.num_local_overwrites_total);
-    conflicts_resolved_server_wins.SetValue(
+    notifications_received->Set(full_status.notifications_received);
+    updates_received->Set(full_status.updates_received);
+    tombstone_updates->Set(full_status.tombstone_updates_received);
+    reflected_updates->Set(full_status.reflected_updates_received);
+    successful_commits->Set(full_status.num_commits_total);
+    conflicts_resolved_local_wins->Set(full_status.num_local_overwrites_total);
+    conflicts_resolved_server_wins->Set(
         full_status.num_server_overwrites_total);
   }
 
+  // Transient Counters (this cycle).
   if (is_status_valid) {
-    encryption_conflicts.SetValue(full_status.encryption_conflicts);
-    hierarchy_conflicts.SetValue(full_status.hierarchy_conflicts);
-    server_conflicts.SetValue(full_status.server_conflicts);
-    committed_items.SetValue(full_status.committed_count);
+    encryption_conflicts->Set(full_status.encryption_conflicts);
+    hierarchy_conflicts->Set(full_status.hierarchy_conflicts);
+    server_conflicts->Set(full_status.server_conflicts);
+    committed_items->Set(full_status.committed_count);
   }
 
-  if (is_status_valid) {
-    nudge_source_notification.SetValue(full_status.nudge_source_notification);
-    nudge_source_local.SetValue(full_status.nudge_source_local);
-    nudge_source_local_refresh.SetValue(full_status.nudge_source_local_refresh);
-  }
-
+  // Transient Counters (last cycle of last completed session).
   if (snapshot.is_initialized()) {
-    updates_downloaded.SetValue(
+    updates_downloaded->Set(
         snapshot.model_neutral_state().num_updates_downloaded_total);
-    committed_count.SetValue(
-        snapshot.model_neutral_state().num_successful_commits);
-    entries.SetValue(snapshot.num_entries());
+    committed_count->Set(snapshot.model_neutral_state().num_successful_commits);
+    entries->Set(static_cast<int>(snapshot.num_entries()));
   }
 
+  // Nudge Source Counters.
+  if (is_status_valid) {
+    nudge_source_notification->Set(full_status.nudge_source_notification);
+    nudge_source_local->Set(full_status.nudge_source_local);
+    nudge_source_local_refresh->Set(full_status.nudge_source_local_refresh);
+  }
+
+  // This list of sections belongs in the 'details' field of the returned
+  // message.
+  about_info->SetKey(kDetailsKey, section_list.ToValue());
+
   // The values set from this point onwards do not belong in the
   // details list.
 
@@ -581,44 +524,46 @@
       full_status.sync_protocol_error.error_type != UNKNOWN_ERROR &&
       full_status.sync_protocol_error.error_type != SYNC_SUCCESS;
 
-  about_info->SetBoolean("actionable_error_detected",
-                         actionable_error_detected);
+  about_info->SetKey("actionable_error_detected",
+                     base::Value(actionable_error_detected));
 
   // NOTE: We won't bother showing any of the following values unless
   // actionable_error_detected is set.
 
-  auto actionable_error = std::make_unique<base::ListValue>();
-  // TODO(crbug.com/702230): Remove the usages of raw pointers in this file.
-  actionable_error->Reserve(4);
-
-  StringSyncStat error_type(actionable_error.get(), "Error Type");
-  StringSyncStat action(actionable_error.get(), "Action");
-  StringSyncStat url(actionable_error.get(), "URL");
-  StringSyncStat description(actionable_error.get(), "Error Description");
-  about_info->Set("actionable_error", std::move(actionable_error));
+  base::Value actionable_error(base::Value::Type::LIST);
+  Stat<std::string> error_type("Error Type", kUninitialized);
+  Stat<std::string> action("Action", kUninitialized);
+  Stat<std::string> url("URL", kUninitialized);
+  Stat<std::string> description("Error Description", kUninitialized);
 
   if (actionable_error_detected) {
-    error_type.SetValue(
+    error_type.Set(
         GetSyncErrorTypeString(full_status.sync_protocol_error.error_type));
-    action.SetValue(
-        GetClientActionString(full_status.sync_protocol_error.action));
-    url.SetValue(full_status.sync_protocol_error.url);
-    description.SetValue(full_status.sync_protocol_error.error_description);
+    action.Set(GetClientActionString(full_status.sync_protocol_error.action));
+    url.Set(full_status.sync_protocol_error.url);
+    description.Set(full_status.sync_protocol_error.error_description);
   }
 
-  about_info->SetBoolean("unrecoverable_error_detected",
-                         service->HasUnrecoverableError());
+  actionable_error.GetList().push_back(error_type.ToValue());
+  actionable_error.GetList().push_back(action.ToValue());
+  actionable_error.GetList().push_back(url.ToValue());
+  actionable_error.GetList().push_back(description.ToValue());
+  about_info->SetKey("actionable_error", std::move(actionable_error));
+
+  about_info->SetKey("unrecoverable_error_detected",
+                     base::Value(service->HasUnrecoverableError()));
 
   if (service->HasUnrecoverableError()) {
     std::string unrecoverable_error_message =
         "Unrecoverable error detected at " +
         service->unrecoverable_error_location().ToString() + ": " +
         service->unrecoverable_error_message();
-    about_info->SetString("unrecoverable_error_message",
-                          unrecoverable_error_message);
+    about_info->SetKey("unrecoverable_error_message",
+                       base::Value(unrecoverable_error_message));
   }
 
-  about_info->Set("type_status", service->GetTypeStatusMap());
+  about_info->SetKey("type_status", base::Value::FromUniquePtrValue(
+                                        service->GetTypeStatusMap()));
 
   return about_info;
 }
diff --git a/components/test/android/browsertests_apk/src/org/chromium/components_browsertests_apk/ComponentsBrowserTestsApplication.java b/components/test/android/browsertests_apk/src/org/chromium/components_browsertests_apk/ComponentsBrowserTestsApplication.java
index 014298a..8f12285 100644
--- a/components/test/android/browsertests_apk/src/org/chromium/components_browsertests_apk/ComponentsBrowserTestsApplication.java
+++ b/components/test/android/browsertests_apk/src/org/chromium/components_browsertests_apk/ComponentsBrowserTestsApplication.java
@@ -22,7 +22,7 @@
     @Override
     protected void attachBaseContext(Context base) {
         super.attachBaseContext(base);
-        if (BuildConfig.isMultidexEnabled()) {
+        if (BuildConfig.IS_MULTIDEX_ENABLED) {
             ChromiumMultiDexInstaller.install(this);
         }
         ContextUtils.initApplicationContext(this);
diff --git a/components/test/data/payments/bobpay.com/app1/app.js b/components/test/data/payments/bobpay.com/app1/app.js
new file mode 100644
index 0000000..856a895
--- /dev/null
+++ b/components/test/data/payments/bobpay.com/app1/app.js
@@ -0,0 +1,16 @@
+/*
+ * 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.
+ */
+
+self.addEventListener('canmakepayment', (evt) => {
+  evt.respondWith(true);
+});
+
+self.addEventListener('paymentrequest', (evt) => {
+  evt.respondWith({
+    methodName: evt.methodData[0].supportedMethods,
+    details: {transactionId: '123'},
+  });
+});
diff --git a/components/test/data/payments/bobpay.com/app1/index.html b/components/test/data/payments/bobpay.com/app1/index.html
new file mode 100644
index 0000000..d171174e
--- /dev/null
+++ b/components/test/data/payments/bobpay.com/app1/index.html
@@ -0,0 +1,16 @@
+<!doctype html>
+<!--
+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.
+-->
+<html lang="en">
+  <head>
+    <meta charset="utf-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1">
+    <title>Bob Pay 1</title>
+  </head>
+  <body>
+    <script src="index.js"></script>
+  </body>
+</html>
diff --git a/components/test/data/payments/bobpay.com/app1/index.js b/components/test/data/payments/bobpay.com/app1/index.js
new file mode 100644
index 0000000..10af3f9
--- /dev/null
+++ b/components/test/data/payments/bobpay.com/app1/index.js
@@ -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.
+ */
+
+/**
+ * Prints output.
+ * @param {String} src - Where the message is coming from.
+ * @param {String} txt - The text to print.
+ */
+function output(src, txt) {
+  // Handle DOMException:
+  if (txt.message) {
+    txt = txt.message;
+  }
+  txt = src + ': ' + txt;
+  if (!domAutomationController) {
+    txt += ' window.domAutomationController not found.';
+  } else {
+    domAutomationController.send(txt);
+  }
+  console.log(txt);
+}
+
+/**
+ * Installs a payment app.
+ * @param {String} method - The payment method name that this app supports.
+ */
+function install(method) {  // eslint-disable-line no-unused-vars
+  if (!navigator.serviceWorker) {
+    output('install()', 'ServiceWorker API not found.');
+    return;
+  }
+
+  navigator.serviceWorker.getRegistration('app.js')
+      .then((registration) => {
+        if (registration) {
+          output(
+              'serviceWorker.getRegistration()',
+              'The ServiceWorker is already installed.');
+          return;
+        }
+        navigator.serviceWorker.register('app.js')
+            .then(() => {
+              return navigator.serviceWorker.ready;
+            })
+            .then((registration) => {
+              if (!registration.paymentManager) {
+                output(
+                    'serviceWorker.register()',
+                    'PaymentManager API not found.');
+                return;
+              }
+
+              registration.paymentManager.instruments
+                  .set('123456', {name: 'Bob Pay', enabledMethods: [method]})
+                  .then(() => {
+                    output(
+                        'instruments.set()',
+                        'Payment app for "' + method + '" method installed.');
+                  })
+                  .catch((error) => {
+                    output('instruments.set()', error);
+                  });
+            })
+            .catch((error) => {
+              output('serviceWorker.register()', error);
+            });
+      })
+      .catch((error) => {
+        output('serviceWorker.getRegistration()', error);
+      });
+}
diff --git a/components/test/data/payments/bobpay_ui_skip.js b/components/test/data/payments/bobpay_ui_skip.js
index 8bce925..4ade364 100644
--- a/components/test/data/payments/bobpay_ui_skip.js
+++ b/components/test/data/payments/bobpay_ui_skip.js
@@ -29,6 +29,36 @@
               })
               .catch(function(error) {
                 print('complete() rejected<br>' + error);
+            });
+        })
+        .catch(function(error) {
+          print('show() rejected<br>' + error);
+        });
+  } catch (error) {
+    print('exception thrown<br>' + error);
+  }
+}
+
+/**
+ * Launches the PaymentRequest UI with Bob Pay as the only payment method but
+ * requesting the payer's email as to disable skip ui.
+ */
+function buyWithRequestedEmail() {  // eslint-disable-line no-unused-vars
+  try {
+    new PaymentRequest(
+        [{supportedMethods: ['https://bobpay.com']}],
+        {total: {label: 'Total', amount: {currency: 'USD', value: '5.00'}}},
+        {requestPayerEmail: true})
+        .show()
+        .then(function(resp) {
+          resp.complete('success')
+              .then(function() {
+                print(
+                    resp.methodName + '<br>' +
+                    JSON.stringify(resp.details, undefined, 2));
+              })
+              .catch(function(error) {
+                print('complete() rejected<br>' + error);
               });
         })
         .catch(function(error) {
diff --git a/components/test/data/payments/payment_request_bobpay_ui_skip_test.html b/components/test/data/payments/payment_request_bobpay_ui_skip_test.html
index 9dfed6d..d4bd9d3 100644
--- a/components/test/data/payments/payment_request_bobpay_ui_skip_test.html
+++ b/components/test/data/payments/payment_request_bobpay_ui_skip_test.html
@@ -13,6 +13,7 @@
 </head>
 <body>
 <div><button onclick="buy()" id="buy">Bob Pay Test</button></div>
+<div><button onclick="buyWithRequestedEmail()" id="buyWithRequestedEmail">Bob Pay Test</button></div>
 <pre id="result"></pre>
 <script src="util.js"></script>
 <script src="bobpay_ui_skip.js"></script>
diff --git a/components/toolbar/vector_icons/find_in_page.icon b/components/toolbar/vector_icons/find_in_page.icon
index 15ecfda..41f4dc9 100644
--- a/components/toolbar/vector_icons/find_in_page.icon
+++ b/components/toolbar/vector_icons/find_in_page.icon
@@ -26,5 +26,4 @@
 R_CUBIC_TO, 1.66f, 0, 3, -1.34f, 3, -3,
 R_CUBIC_TO, 0, -1.66f, -1.34f, -3, -3, -3,
 R_CUBIC_TO, -1.66f, 0, -3, 1.34f, -3, 3,
-CLOSE,
-END
+CLOSE
diff --git a/components/toolbar/vector_icons/http.1x.icon b/components/toolbar/vector_icons/http.1x.icon
index 636b4f6..de63149 100644
--- a/components/toolbar/vector_icons/http.1x.icon
+++ b/components/toolbar/vector_icons/http.1x.icon
@@ -23,5 +23,4 @@
 LINE_TO, 9, 4,
 LINE_TO, 7, 4,
 LINE_TO, 7, 6,
-CLOSE,
-END
+CLOSE
diff --git a/components/toolbar/vector_icons/http.icon b/components/toolbar/vector_icons/http.icon
index c8a6695..2ab6355 100644
--- a/components/toolbar/vector_icons/http.icon
+++ b/components/toolbar/vector_icons/http.icon
@@ -23,5 +23,4 @@
 LINE_TO, 18, 10,
 LINE_TO, 15, 10,
 LINE_TO, 15, 13,
-CLOSE,
-END
+CLOSE
diff --git a/components/toolbar/vector_icons/https_invalid.1x.icon b/components/toolbar/vector_icons/https_invalid.1x.icon
index 9ccc1af9a..dabd65b8 100644
--- a/components/toolbar/vector_icons/https_invalid.1x.icon
+++ b/components/toolbar/vector_icons/https_invalid.1x.icon
@@ -19,5 +19,4 @@
 V_LINE_TO, 6,
 R_H_LINE_TO, 2,
 R_V_LINE_TO, 3,
-CLOSE,
-END
+CLOSE
diff --git a/components/toolbar/vector_icons/https_invalid.icon b/components/toolbar/vector_icons/https_invalid.icon
index 880493c..9d17d46 100644
--- a/components/toolbar/vector_icons/https_invalid.icon
+++ b/components/toolbar/vector_icons/https_invalid.icon
@@ -19,5 +19,4 @@
 R_V_LINE_TO, -6,
 R_H_LINE_TO, 3,
 R_V_LINE_TO, 6,
-CLOSE,
-END
+CLOSE
diff --git a/components/toolbar/vector_icons/https_valid.1x.icon b/components/toolbar/vector_icons/https_valid.1x.icon
index 6e2c372a..c6ba83a 100644
--- a/components/toolbar/vector_icons/https_valid.1x.icon
+++ b/components/toolbar/vector_icons/https_valid.1x.icon
@@ -22,5 +22,4 @@
 R_CUBIC_TO, 1.1f, 0, 2, 0.89f, 2, 2,
 V_LINE_TO, 6.01f,
 H_LINE_TO, 6,
-CLOSE,
-END
+CLOSE
diff --git a/components/toolbar/vector_icons/https_valid.icon b/components/toolbar/vector_icons/https_valid.icon
index e374e83..2c4612d 100644
--- a/components/toolbar/vector_icons/https_valid.icon
+++ b/components/toolbar/vector_icons/https_valid.icon
@@ -24,5 +24,4 @@
 R_CUBIC_TO, 1.66f, 0, 3, 1.34f, 3, 3,
 R_V_LINE_TO, 2.02f,
 R_H_LINE_TO, -6,
-CLOSE,
-END
+CLOSE
diff --git a/components/toolbar/vector_icons/https_valid_in_chip.1x.icon b/components/toolbar/vector_icons/https_valid_in_chip.1x.icon
index 60bad86..3c7a0e31 100644
--- a/components/toolbar/vector_icons/https_valid_in_chip.1x.icon
+++ b/components/toolbar/vector_icons/https_valid_in_chip.1x.icon
@@ -23,5 +23,4 @@
 CUBIC_TO, 8.33f, 4, 9, 4.67f, 9, 5.5f,
 LINE_TO, 9, 6,
 LINE_TO, 6, 6,
-CLOSE,
-END
+CLOSE
diff --git a/components/toolbar/vector_icons/https_valid_in_chip.icon b/components/toolbar/vector_icons/https_valid_in_chip.icon
index 49c00e64..0ecae4ec 100644
--- a/components/toolbar/vector_icons/https_valid_in_chip.icon
+++ b/components/toolbar/vector_icons/https_valid_in_chip.icon
@@ -24,5 +24,4 @@
 R_CUBIC_TO, 1.66f, 0, 3, 1.34f, 3, 3,
 R_V_LINE_TO, 2.02f,
 R_H_LINE_TO, -6,
-CLOSE,
-END
+CLOSE
diff --git a/components/toolbar/vector_icons/offline_pin.icon b/components/toolbar/vector_icons/offline_pin.icon
index 935b7332..39813c0 100644
--- a/components/toolbar/vector_icons/offline_pin.icon
+++ b/components/toolbar/vector_icons/offline_pin.icon
@@ -22,5 +22,4 @@
 R_LINE_TO, 5.3f, -5.3f,
 LINE_TO, 17, 7.3f,
 LINE_TO, 10.3f, 14,
-CLOSE,
-END
+CLOSE
diff --git a/components/toolbar/vector_icons/open_in_new.icon b/components/toolbar/vector_icons/open_in_new.icon
index f998ec7f..df7eee1 100644
--- a/components/toolbar/vector_icons/open_in_new.icon
+++ b/components/toolbar/vector_icons/open_in_new.icon
@@ -27,5 +27,4 @@
 R_H_LINE_TO, 4,
 V_LINE_TO, 6,
 H_LINE_TO, 28,
-CLOSE,
-END
+CLOSE
diff --git a/components/toolbar/vector_icons/product.1x.icon b/components/toolbar/vector_icons/product.1x.icon
index 4997801..1565657 100644
--- a/components/toolbar/vector_icons/product.1x.icon
+++ b/components/toolbar/vector_icons/product.1x.icon
@@ -34,5 +34,4 @@
 CUBIC_TO, 10.1f, 6.84f, 9.16f, 5.9f, 8, 5.9f,
 CUBIC_TO, 6.84f, 5.9f, 5.9f, 6.84f, 5.9f, 8,
 CUBIC_TO, 5.9f, 9.16f, 6.84f, 10.1f, 8, 10.1f,
-CLOSE,
-END
+CLOSE
diff --git a/components/toolbar/vector_icons/product.icon b/components/toolbar/vector_icons/product.icon
index 98ce8d51..9b741ca 100644
--- a/components/toolbar/vector_icons/product.icon
+++ b/components/toolbar/vector_icons/product.icon
@@ -34,5 +34,4 @@
 CUBIC_TO, 20.2f, 13.68f, 18.32f, 11.8f, 16, 11.8f,
 CUBIC_TO, 13.68f, 11.8f, 11.8f, 13.68f, 11.8f, 16,
 CUBIC_TO, 11.8f, 18.32f, 13.68f, 20.2f, 16, 20.2f,
-CLOSE,
-END
+CLOSE
diff --git a/components/toolbar/vector_icons/star.icon b/components/toolbar/vector_icons/star.icon
index 1d471bcb..39a86741 100644
--- a/components/toolbar/vector_icons/star.icon
+++ b/components/toolbar/vector_icons/star.icon
@@ -25,5 +25,4 @@
 LINE_TO, 15.5f, 6.03f,
 LINE_TO, 10.11f, 5.56f,
 LINE_TO, 8, 0.5f,
-CLOSE,
-END
+CLOSE
diff --git a/components/toolbar/vector_icons/star_active.icon b/components/toolbar/vector_icons/star_active.icon
index 484e082..d7a9241c 100644
--- a/components/toolbar/vector_icons/star_active.icon
+++ b/components/toolbar/vector_icons/star_active.icon
@@ -14,5 +14,4 @@
 LINE_TO, 15.5f, 6.03f,
 LINE_TO, 10.11f, 5.56f,
 LINE_TO, 8, 0.5f,
-CLOSE,
-END
+CLOSE
diff --git a/components/ui_devtools/views/ui_element.cc b/components/ui_devtools/views/ui_element.cc
index 1a48248..e3f0239 100644
--- a/components/ui_devtools/views/ui_element.cc
+++ b/components/ui_devtools/views/ui_element.cc
@@ -8,9 +8,6 @@
 
 #include "components/ui_devtools/Protocol.h"
 #include "components/ui_devtools/views/ui_element_delegate.h"
-#include "components/ui_devtools/views/view_element.h"
-#include "components/ui_devtools/views/widget_element.h"
-#include "components/ui_devtools/views/window_element.h"
 
 namespace ui_devtools {
 namespace {
@@ -80,37 +77,6 @@
   return 0;
 }
 
-template <>
-int UIElement::FindUIElementIdForBackendElement<aura::Window>(
-    aura::Window* element) const {
-  if (type_ == UIElementType::WINDOW &&
-      UIElement::GetBackingElement<aura::Window, WindowElement>(this) ==
-          element) {
-    return node_id_;
-  }
-  for (auto* child : children_) {
-    int ui_element_id = child->FindUIElementIdForBackendElement(element);
-    if (ui_element_id)
-      return ui_element_id;
-  }
-  return 0;
-}
-
-template <>
-int UIElement::FindUIElementIdForBackendElement<views::View>(
-    views::View* element) const {
-  if (type_ == UIElementType::VIEW &&
-      UIElement::GetBackingElement<views::View, ViewElement>(this) == element) {
-    return node_id_;
-  }
-  for (auto* child : children_) {
-    int ui_element_id = child->FindUIElementIdForBackendElement(element);
-    if (ui_element_id)
-      return ui_element_id;
-  }
-  return 0;
-}
-
 UIElement::UIElement(const UIElementType type,
                      UIElementDelegate* delegate,
                      UIElement* parent)
diff --git a/components/ui_devtools/views/view_element.cc b/components/ui_devtools/views/view_element.cc
index 33bae48..bdb42573 100644
--- a/components/ui_devtools/views/view_element.cc
+++ b/components/ui_devtools/views/view_element.cc
@@ -105,4 +105,19 @@
   return static_cast<const ViewElement*>(element)->view_;
 }
 
+template <>
+int UIElement::FindUIElementIdForBackendElement<views::View>(
+    views::View* element) const {
+  if (type_ == UIElementType::VIEW &&
+      UIElement::GetBackingElement<views::View, ViewElement>(this) == element) {
+    return node_id_;
+  }
+  for (auto* child : children_) {
+    int ui_element_id = child->FindUIElementIdForBackendElement(element);
+    if (ui_element_id)
+      return ui_element_id;
+  }
+  return 0;
+}
+
 }  // namespace ui_devtools
diff --git a/components/ui_devtools/views/window_element.cc b/components/ui_devtools/views/window_element.cc
index bb5fabe..f6592de 100644
--- a/components/ui_devtools/views/window_element.cc
+++ b/components/ui_devtools/views/window_element.cc
@@ -112,4 +112,20 @@
   return static_cast<const WindowElement*>(element)->window_;
 }
 
+template <>
+int UIElement::FindUIElementIdForBackendElement<aura::Window>(
+    aura::Window* element) const {
+  if (type_ == UIElementType::WINDOW &&
+      UIElement::GetBackingElement<aura::Window, WindowElement>(this) ==
+          element) {
+    return node_id_;
+  }
+  for (auto* child : children_) {
+    int ui_element_id = child->FindUIElementIdForBackendElement(element);
+    if (ui_element_id)
+      return ui_element_id;
+  }
+  return 0;
+}
+
 }  // namespace ui_devtools
diff --git a/components/vector_icons/accessibility.icon b/components/vector_icons/accessibility.icon
index 62b8b71c..34b2ce37 100644
--- a/components/vector_icons/accessibility.icon
+++ b/components/vector_icons/accessibility.icon
@@ -21,5 +21,4 @@
 R_MOVE_TO, 0, -1.94f,
 R_ARC_TO, 2.5f, 2.5f, 0, 1, 0, 0, -5,
 R_ARC_TO, 2.5f, 2.5f, 0, 0, 0, 0, 5,
-CLOSE,
-END
+CLOSE
diff --git a/components/vector_icons/back_arrow.1x.icon b/components/vector_icons/back_arrow.1x.icon
index 219193f..3b8ee7a 100644
--- a/components/vector_icons/back_arrow.1x.icon
+++ b/components/vector_icons/back_arrow.1x.icon
@@ -22,5 +22,4 @@
 CUBIC_TO, 7.72f, 14.97f, 7.86f, 15, 8, 15,
 CUBIC_TO, 8.55f, 15, 9, 14.55f, 9, 14,
 CUBIC_TO, 9, 13.86f, 8.97f, 13.72f, 8.91f, 13.59f,
-CLOSE,
-END
+CLOSE
diff --git a/components/vector_icons/back_arrow.icon b/components/vector_icons/back_arrow.icon
index 4b76b7ed..4bc93db1 100644
--- a/components/vector_icons/back_arrow.icon
+++ b/components/vector_icons/back_arrow.icon
@@ -23,5 +23,4 @@
 CUBIC_TO, 15.06f, 3, 14.66f, 3.2f, 14.39f, 3.5f,
 LINE_TO, 14.36f, 3.47f,
 LINE_TO, 4, 13.81f,
-CLOSE,
-END
+CLOSE
diff --git a/components/vector_icons/bluetooth_connected.icon b/components/vector_icons/bluetooth_connected.icon
index ea01302..721b972e 100644
--- a/components/vector_icons/bluetooth_connected.icon
+++ b/components/vector_icons/bluetooth_connected.icon
@@ -39,5 +39,4 @@
 R_LINE_TO, 4, 4,
 R_LINE_TO, 4, -4,
 R_LINE_TO, -4, -4,
-CLOSE,
-END
+CLOSE
diff --git a/components/vector_icons/business.icon b/components/vector_icons/business.icon
index bfefb7b4..afab687 100644
--- a/components/vector_icons/business.icon
+++ b/components/vector_icons/business.icon
@@ -83,5 +83,4 @@
 R_V_LINE_TO, 4,
 R_H_LINE_TO, 4,
 R_V_LINE_TO, -4,
-CLOSE,
-END
+CLOSE
diff --git a/components/vector_icons/check_circle.icon b/components/vector_icons/check_circle.icon
index cd24bbd..8806a0c7 100644
--- a/components/vector_icons/check_circle.icon
+++ b/components/vector_icons/check_circle.icon
@@ -9,5 +9,4 @@
 LINE_TO, 20, 28.34f,
 R_LINE_TO, 15.17f, -15.17f,
 LINE_TO, 38, 16,
-LINE_TO, 20, 34,
-END
+LINE_TO, 20, 34
diff --git a/components/vector_icons/close.1x.icon b/components/vector_icons/close.1x.icon
index a7267fd..6033fcb 100644
--- a/components/vector_icons/close.1x.icon
+++ b/components/vector_icons/close.1x.icon
@@ -9,5 +9,4 @@
 MOVE_TO, 4, 4,
 R_LINE_TO, 8, 8,
 MOVE_TO, 4, 12,
-R_LINE_TO, 8, -8,
-END
+R_LINE_TO, 8, -8
diff --git a/components/vector_icons/close.icon b/components/vector_icons/close.icon
index 3a5801a..55c4b63 100644
--- a/components/vector_icons/close.icon
+++ b/components/vector_icons/close.icon
@@ -15,5 +15,4 @@
 LINE_TO, 17.59f, 19,
 LINE_TO, 19, 17.59f,
 LINE_TO, 13.41f, 12,
-CLOSE,
-END
+CLOSE
diff --git a/components/vector_icons/close_16.1x.icon b/components/vector_icons/close_16.1x.icon
index a7267fd..6033fcb 100644
--- a/components/vector_icons/close_16.1x.icon
+++ b/components/vector_icons/close_16.1x.icon
@@ -9,5 +9,4 @@
 MOVE_TO, 4, 4,
 R_LINE_TO, 8, 8,
 MOVE_TO, 4, 12,
-R_LINE_TO, 8, -8,
-END
+R_LINE_TO, 8, -8
diff --git a/components/vector_icons/close_16.icon b/components/vector_icons/close_16.icon
index cfbabc1..425aa3b 100644
--- a/components/vector_icons/close_16.icon
+++ b/components/vector_icons/close_16.icon
@@ -8,5 +8,4 @@
 MOVE_TO, 8.75f, 8.75f,
 R_LINE_TO, 14.5f, 14.5f,
 MOVE_TO, 8.75f, 23.25f,
-R_LINE_TO, 14.5f, -14.5f,
-END
+R_LINE_TO, 14.5f, -14.5f
diff --git a/components/vector_icons/edit.icon b/components/vector_icons/edit.icon
index 0cbb1f7..d915a7a 100644
--- a/components/vector_icons/edit.icon
+++ b/components/vector_icons/edit.icon
@@ -17,5 +17,4 @@
 LINE_TO, 30.26f, 10.25f,
 LINE_TO, 37.76f, 17.75f,
 LINE_TO, 41.42f, 14.09f,
-CLOSE,
-END
+CLOSE
diff --git a/components/vector_icons/folder.1x.icon b/components/vector_icons/folder.1x.icon
index 6173e2f..d8057ec4 100644
--- a/components/vector_icons/folder.1x.icon
+++ b/components/vector_icons/folder.1x.icon
@@ -14,5 +14,4 @@
 LINE_TO, 9, 4,
 LINE_TO, 7, 2,
 LINE_TO, 2.5f, 2,
-CLOSE,
-END
+CLOSE
diff --git a/components/vector_icons/folder.icon b/components/vector_icons/folder.icon
index 7c56c7c..3d375b15 100644
--- a/components/vector_icons/folder.icon
+++ b/components/vector_icons/folder.icon
@@ -14,5 +14,4 @@
 LINE_TO, 16, 8,
 LINE_TO, 13.2f, 5,
 LINE_TO, 4.8f, 5,
-CLOSE,
-END
+CLOSE
diff --git a/components/vector_icons/folder_managed.1x.icon b/components/vector_icons/folder_managed.1x.icon
index f5dda5d..8786abf 100644
--- a/components/vector_icons/folder_managed.1x.icon
+++ b/components/vector_icons/folder_managed.1x.icon
@@ -74,5 +74,4 @@
 LINE_TO, 11, 10,
 LINE_TO, 11, 9,
 LINE_TO, 10, 9,
-CLOSE,
-END
+CLOSE
diff --git a/components/vector_icons/folder_managed.icon b/components/vector_icons/folder_managed.icon
index e8a6d8b4..9ffb4653 100644
--- a/components/vector_icons/folder_managed.icon
+++ b/components/vector_icons/folder_managed.icon
@@ -77,5 +77,4 @@
 LINE_TO, 23, 21,
 LINE_TO, 23, 19,
 LINE_TO, 21, 19,
-CLOSE,
-END
+CLOSE
diff --git a/components/vector_icons/folder_managed_touch.icon b/components/vector_icons/folder_managed_touch.icon
index 637009f..a31ffef 100644
--- a/components/vector_icons/folder_managed_touch.icon
+++ b/components/vector_icons/folder_managed_touch.icon
@@ -68,5 +68,4 @@
 R_V_LINE_TO, 1,
 R_H_LINE_TO, -1,
 R_V_LINE_TO, -1,
-CLOSE,
-END
+CLOSE
diff --git a/components/vector_icons/folder_touch.icon b/components/vector_icons/folder_touch.icon
index a1ad2a3..32c849f 100644
--- a/components/vector_icons/folder_touch.icon
+++ b/components/vector_icons/folder_touch.icon
@@ -14,5 +14,4 @@
 R_CUBIC_TO, 0, -1.1f, -0.9f, -2, -2, -2,
 R_H_LINE_TO, -8,
 R_LINE_TO, -2, -2,
-CLOSE,
-END
+CLOSE
diff --git a/components/vector_icons/forward_arrow.1x.icon b/components/vector_icons/forward_arrow.1x.icon
index 60b2c9c..1337e43 100644
--- a/components/vector_icons/forward_arrow.1x.icon
+++ b/components/vector_icons/forward_arrow.1x.icon
@@ -23,5 +23,4 @@
 CUBIC_TO, 8.28f, 14.97f, 8.14f, 15, 8, 15,
 CUBIC_TO, 7.45f, 15, 7, 14.55f, 7, 14,
 CUBIC_TO, 7, 13.86f, 7.03f, 13.72f, 7.09f, 13.59f,
-CLOSE,
-END
+CLOSE
diff --git a/components/vector_icons/forward_arrow.icon b/components/vector_icons/forward_arrow.icon
index 77363e01..aebc27f 100644
--- a/components/vector_icons/forward_arrow.icon
+++ b/components/vector_icons/forward_arrow.icon
@@ -23,5 +23,4 @@
 CUBIC_TO, 16.94f, 3, 17.34f, 3.2f, 17.61f, 3.5f,
 LINE_TO, 17.64f, 3.47f,
 LINE_TO, 28, 13.81f,
-CLOSE,
-END
+CLOSE
diff --git a/components/vector_icons/help_outline.icon b/components/vector_icons/help_outline.icon
index 9f07e95..a6148ffa 100644
--- a/components/vector_icons/help_outline.icon
+++ b/components/vector_icons/help_outline.icon
@@ -30,5 +30,4 @@
 R_H_LINE_TO, 2,
 R_CUBIC_TO, 0, -2.25f, 3, -2.5f, 3, -5,
 R_CUBIC_TO, 0, -2.21f, -1.79f, -4, -4, -4,
-CLOSE,
-END
+CLOSE
diff --git a/components/vector_icons/info_outline.icon b/components/vector_icons/info_outline.icon
index 049fba9b..052e290 100644
--- a/components/vector_icons/info_outline.icon
+++ b/components/vector_icons/info_outline.icon
@@ -26,5 +26,4 @@
 LINE_TO, 17.4f, 9,
 LINE_TO, 14.6f, 9,
 LINE_TO, 14.6f, 11.8f,
-CLOSE,
-END
+CLOSE
diff --git a/components/vector_icons/location_on.icon b/components/vector_icons/location_on.icon
index 49f18a4..5e1228d 100644
--- a/components/vector_icons/location_on.icon
+++ b/components/vector_icons/location_on.icon
@@ -8,5 +8,4 @@
 R_CUBIC_TO, 0, 0, 14, -15.5f, 14, -26,
 R_CUBIC_TO, 0, -7.73f, -6.27f, -14, -14, -14,
 CLOSE,
-CIRCLE, 24, 18, 5,
-END
+CIRCLE, 24, 18, 5
diff --git a/components/vector_icons/lock.icon b/components/vector_icons/lock.icon
index df4b8eb..f12b6943 100644
--- a/components/vector_icons/lock.icon
+++ b/components/vector_icons/lock.icon
@@ -29,5 +29,4 @@
 R_CUBIC_TO, 0, -3.42f, 2.78f, -6.2f, 6.2f, -6.2f,
 R_CUBIC_TO, 3.42f, 0, 6.2f, 2.78f, 6.2f, 6.2f,
 R_V_LINE_TO, 4,
-CLOSE,
-END
+CLOSE
diff --git a/components/vector_icons/media_router_active.icon b/components/vector_icons/media_router_active.icon
index 74899b02..f8f11a9 100644
--- a/components/vector_icons/media_router_active.icon
+++ b/components/vector_icons/media_router_active.icon
@@ -53,5 +53,4 @@
 R_CUBIC_TO, 2.88f, 0.92f, 5.19f, 3.25f, 6.12f, 6.11f,
 R_LINE_TO, 4.13f, 0.01f,
 V_LINE_TO, 4.38f,
-CLOSE,
-END
+CLOSE
diff --git a/components/vector_icons/media_router_error.icon b/components/vector_icons/media_router_error.icon
index eb1fccd..45fa96c 100644
--- a/components/vector_icons/media_router_error.icon
+++ b/components/vector_icons/media_router_error.icon
@@ -59,5 +59,4 @@
 R_LINE_TO, 1.06f, -1.06f,
 R_LINE_TO, -1.69f, -1.69f,
 R_LINE_TO, 1.69f, -1.69f,
-CLOSE,
-END
+CLOSE
diff --git a/components/vector_icons/media_router_idle.icon b/components/vector_icons/media_router_idle.icon
index d320062e..7976ba8 100644
--- a/components/vector_icons/media_router_idle.icon
+++ b/components/vector_icons/media_router_idle.icon
@@ -46,5 +46,4 @@
 R_CUBIC_TO, 3.61f, 0, 6.5f, 2.91f, 6.5f, 6.5f,
 H_LINE_TO, 8,
 R_CUBIC_TO, 0, -4.39f, -3.59f, -7.94f, -8, -7.94f,
-CLOSE,
-END
+CLOSE
diff --git a/components/vector_icons/media_router_warning.icon b/components/vector_icons/media_router_warning.icon
index 4cbd535b..b94dcd7 100644
--- a/components/vector_icons/media_router_warning.icon
+++ b/components/vector_icons/media_router_warning.icon
@@ -56,5 +56,4 @@
 R_H_LINE_TO, 1.38f,
 R_V_LINE_TO, 1.38f,
 R_H_LINE_TO, -1.38f,
-CLOSE,
-END
+CLOSE
diff --git a/components/vector_icons/mic.icon b/components/vector_icons/mic.icon
index 9a5fecdc..fedd7fc 100644
--- a/components/vector_icons/mic.icon
+++ b/components/vector_icons/mic.icon
@@ -20,5 +20,4 @@
 R_V_LINE_TO, -6.56f,
 R_CUBIC_TO, 6.56f, -0.97f, 12, -6.61f, 12, -13.44f,
 R_H_LINE_TO, -3.4f,
-CLOSE,
-END
+CLOSE
diff --git a/components/vector_icons/midi.icon b/components/vector_icons/midi.icon
index 10c73a8..970fd2c 100644
--- a/components/vector_icons/midi.icon
+++ b/components/vector_icons/midi.icon
@@ -37,5 +37,4 @@
 LINE_TO, 41, 41,
 LINE_TO, 7, 41,
 LINE_TO, 7, 7,
-CLOSE,
-END
+CLOSE
diff --git a/components/vector_icons/notifications.icon b/components/vector_icons/notifications.icon
index 8240b82..3bd7a8a 100644
--- a/components/vector_icons/notifications.icon
+++ b/components/vector_icons/notifications.icon
@@ -20,5 +20,4 @@
 R_V_LINE_TO, 2,
 R_H_LINE_TO, 32,
 R_V_LINE_TO, -2,
-R_LINE_TO, -4, -4,
-END
+R_LINE_TO, -4, -4
diff --git a/components/vector_icons/protocol_handler.icon b/components/vector_icons/protocol_handler.icon
index 3ded270d1e..6429320 100644
--- a/components/vector_icons/protocol_handler.icon
+++ b/components/vector_icons/protocol_handler.icon
@@ -44,5 +44,4 @@
 LINE_TO, 39.29f, 23.71f,
 LINE_TO, 28.59f, 34.46f,
 LINE_TO, 28.59f, 34.46f,
-CLOSE,
-END
+CLOSE
diff --git a/components/vector_icons/reload.1x.icon b/components/vector_icons/reload.1x.icon
index 77d5c53..b3017e7 100644
--- a/components/vector_icons/reload.1x.icon
+++ b/components/vector_icons/reload.1x.icon
@@ -19,5 +19,4 @@
 CUBIC_TO, 4.15f, 15, 1, 11.87f, 1, 8,
 CUBIC_TO, 1, 4.13f, 4.15f, 1, 8.03f, 1,
 CUBIC_TO, 9.96f, 1, 11.7f, 1.77f, 12.97f, 3.03f,
-CLOSE,
-END
+CLOSE
diff --git a/components/vector_icons/reload.icon b/components/vector_icons/reload.icon
index 3d72758..3292497 100644
--- a/components/vector_icons/reload.icon
+++ b/components/vector_icons/reload.icon
@@ -23,5 +23,4 @@
 CUBIC_TO, 27.96f, 21.13f, 28.03f, 20.88f, 28.03f, 20.61f,
 CUBIC_TO, 28.03f, 19.78f, 27.36f, 19.11f, 26.53f, 19.11f,
 CUBIC_TO, 25.87f, 19.11f, 25.3f, 19.55f, 25.1f, 20.15f,
-CLOSE,
-END
+CLOSE
diff --git a/components/vector_icons/screen_share.icon b/components/vector_icons/screen_share.icon
index 517fac6..32b8cfc 100644
--- a/components/vector_icons/screen_share.icon
+++ b/components/vector_icons/screen_share.icon
@@ -26,5 +26,4 @@
 R_LINE_TO, 5.5f, 4.5f,
 LINE_TO, 17, 20,
 R_V_LINE_TO, -3,
-CLOSE,
-END
+CLOSE
diff --git a/components/vector_icons/search.icon b/components/vector_icons/search.icon
index c1e5f08..715ab9f 100644
--- a/components/vector_icons/search.icon
+++ b/components/vector_icons/search.icon
@@ -23,5 +23,4 @@
 CUBIC_TO, 16.64f, 6.56f, 19.54f, 9.43f, 19.54f, 12.96f,
 CUBIC_TO, 19.54f, 16.5f, 16.64f, 19.36f, 13.07f, 19.36f,
 LINE_TO, 13.07f, 19.36f,
-CLOSE,
-END
+CLOSE
diff --git a/components/vector_icons/usb.icon b/components/vector_icons/usb.icon
index 61d9679..6dd7a5c 100644
--- a/components/vector_icons/usb.icon
+++ b/components/vector_icons/usb.icon
@@ -34,5 +34,4 @@
 R_H_LINE_TO, 2,
 R_V_LINE_TO, -8,
 R_H_LINE_TO, -8,
-CLOSE,
-END
+CLOSE
diff --git a/components/vector_icons/videocam.icon b/components/vector_icons/videocam.icon
index 994e07ed..0ff8a27 100644
--- a/components/vector_icons/videocam.icon
+++ b/components/vector_icons/videocam.icon
@@ -15,5 +15,4 @@
 R_LINE_TO, 8, 8,
 V_LINE_TO, 13,
 R_LINE_TO, -8, 8,
-CLOSE,
-END
+CLOSE
diff --git a/components/vector_icons/warning.icon b/components/vector_icons/warning.icon
index 7a5f4256..ffb28b8 100644
--- a/components/vector_icons/warning.icon
+++ b/components/vector_icons/warning.icon
@@ -21,5 +21,4 @@
 R_V_LINE_TO, -8,
 R_H_LINE_TO, 4,
 R_V_LINE_TO, 8,
-CLOSE,
-END
+CLOSE
diff --git a/components/visitedlink/test/visitedlink_perftest.cc b/components/visitedlink/test/visitedlink_perftest.cc
index 82de5587..74d858a 100644
--- a/components/visitedlink/test/visitedlink_perftest.cc
+++ b/components/visitedlink/test/visitedlink_perftest.cc
@@ -140,7 +140,8 @@
 }
 
 // Tests how long it takes to write and read a large database to and from disk.
-TEST_F(VisitedLink, TestLoad) {
+// Flaky, see crbug.com/822308.
+TEST_F(VisitedLink, DISABLED_TestLoad) {
   // create a big DB
   {
     TimeLogger table_initialization_timer("Table_initialization");
diff --git a/components/viz/service/display_embedder/gpu_display_provider.cc b/components/viz/service/display_embedder/gpu_display_provider.cc
index e8b9673..d812980e 100644
--- a/components/viz/service/display_embedder/gpu_display_provider.cc
+++ b/components/viz/service/display_embedder/gpu_display_provider.cc
@@ -65,7 +65,9 @@
 GpuDisplayProvider::GpuDisplayProvider(
     uint32_t restart_id,
     scoped_refptr<gpu::InProcessCommandBuffer::Service> gpu_service,
-    gpu::GpuChannelManager* gpu_channel_manager)
+    gpu::GpuChannelManager* gpu_channel_manager,
+    bool headless,
+    bool wait_for_all_pipeline_stages_before_draw)
     : restart_id_(restart_id),
       gpu_service_(std::move(gpu_service)),
       gpu_channel_manager_delegate_(gpu_channel_manager->delegate()),
@@ -73,7 +75,10 @@
           std::make_unique<InProcessGpuMemoryBufferManager>(
               gpu_channel_manager)),
       image_factory_(GetImageFactory(gpu_channel_manager)),
-      task_runner_(base::ThreadTaskRunnerHandle::Get()) {
+      task_runner_(base::ThreadTaskRunnerHandle::Get()),
+      headless_(headless),
+      wait_for_all_pipeline_stages_before_draw_(
+          wait_for_all_pipeline_stages_before_draw) {
   DCHECK_NE(restart_id_, BeginFrameSource::kNotRestartableId);
 }
 
@@ -153,7 +158,8 @@
   DCHECK_GT(max_frames_pending, 0);
 
   auto scheduler = std::make_unique<DisplayScheduler>(
-      display_begin_frame_source, task_runner_.get(), max_frames_pending);
+      display_begin_frame_source, task_runner_.get(), max_frames_pending,
+      wait_for_all_pipeline_stages_before_draw_);
 
   // The ownership of the BeginFrameSource is transferred to the caller.
   *out_begin_frame_source = std::move(synthetic_begin_frame_source);
@@ -166,6 +172,9 @@
 std::unique_ptr<SoftwareOutputDevice>
 GpuDisplayProvider::CreateSoftwareOutputDeviceForPlatform(
     gpu::SurfaceHandle surface_handle) {
+  if (headless_)
+    return std::make_unique<SoftwareOutputDevice>();
+
 #if defined(GPU_SURFACE_HANDLE_IS_ACCELERATED_WINDOW)
   gfx::AcceleratedWidget widget = surface_handle;
 #endif
diff --git a/components/viz/service/display_embedder/gpu_display_provider.h b/components/viz/service/display_embedder/gpu_display_provider.h
index 728b21f..0a4c19bb 100644
--- a/components/viz/service/display_embedder/gpu_display_provider.h
+++ b/components/viz/service/display_embedder/gpu_display_provider.h
@@ -36,7 +36,9 @@
   GpuDisplayProvider(
       uint32_t restart_id,
       scoped_refptr<gpu::InProcessCommandBuffer::Service> gpu_service,
-      gpu::GpuChannelManager* gpu_channel_manager);
+      gpu::GpuChannelManager* gpu_channel_manager,
+      bool headless,
+      bool wait_for_all_pipeline_stages_before_draw);
   ~GpuDisplayProvider() override;
 
   // DisplayProvider implementation.
@@ -66,6 +68,9 @@
 
   scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
 
+  const bool headless_;
+  const bool wait_for_all_pipeline_stages_before_draw_;
+
   DISALLOW_COPY_AND_ASSIGN(GpuDisplayProvider);
 };
 
diff --git a/components/viz/service/main/DEPS b/components/viz/service/main/DEPS
index 0b4f0cf..d3510c0 100644
--- a/components/viz/service/main/DEPS
+++ b/components/viz/service/main/DEPS
@@ -2,6 +2,7 @@
 
 include_rules = [
   "+components/discardable_memory/client",
+  "+components/viz/common/switches.h",
   "+components/viz/service",
   "+gpu/command_buffer",
   "+gpu/config",
diff --git a/components/viz/service/main/viz_main_impl.cc b/components/viz/service/main/viz_main_impl.cc
index ced48bb1..45ea1ea 100644
--- a/components/viz/service/main/viz_main_impl.cc
+++ b/components/viz/service/main/viz_main_impl.cc
@@ -13,6 +13,7 @@
 #include "base/single_thread_task_runner.h"
 #include "base/threading/sequenced_task_runner_handle.h"
 #include "build/build_config.h"
+#include "components/viz/common/switches.h"
 #include "components/viz/service/display_embedder/gpu_display_provider.h"
 #include "components/viz/service/frame_sinks/frame_sink_manager_impl.h"
 #include "components/viz/service/gl/gpu_service_impl.h"
@@ -28,6 +29,7 @@
 #include "services/metrics/public/cpp/mojo_ukm_recorder.h"
 #include "services/metrics/public/mojom/constants.mojom.h"
 #include "services/service_manager/public/cpp/connector.h"
+#include "ui/gfx/switches.h"
 
 #if defined(OS_CHROMEOS) && BUILDFLAG(USE_VAAPI)
 #include "media/gpu/vaapi/vaapi_wrapper.h"
@@ -274,9 +276,13 @@
     mojom::FrameSinkManagerParamsPtr params) {
   DCHECK(!frame_sink_manager_);
 
+  base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+
   display_provider_ = std::make_unique<GpuDisplayProvider>(
       params->restart_id, gpu_command_service_,
-      gpu_service_->gpu_channel_manager());
+      gpu_service_->gpu_channel_manager(),
+      command_line->HasSwitch(switches::kHeadless),
+      command_line->HasSwitch(switches::kRunAllCompositorStagesBeforeDraw));
 
   mojom::FrameSinkManagerClientPtr client(
       std::move(params->frame_sink_manager_client));
diff --git a/components/viz/service/surfaces/surface.cc b/components/viz/service/surfaces/surface.cc
index 2ea2ea7b..d9d92126 100644
--- a/components/viz/service/surfaces/surface.cc
+++ b/components/viz/service/surfaces/surface.cc
@@ -57,13 +57,13 @@
   active_frame_data_.reset();
 }
 
-bool Surface::InheritActivationDeadlineFrom(Surface* surface) {
+void Surface::InheritActivationDeadlineFrom(Surface* surface) {
   TRACE_EVENT1("viz", "Surface::InheritActivationDeadlineFrom", "FrameSinkId",
                surface_id().frame_sink_id().ToString());
   if (!deadline_ || !surface->deadline_)
-    return false;
+    return;
 
-  return deadline_->InheritFrom(*surface->deadline_);
+  deadline_->InheritFrom(*surface->deadline_);
 }
 
 void Surface::SetPreviousFrameSurface(Surface* surface) {
diff --git a/components/viz/service/surfaces/surface.h b/components/viz/service/surfaces/surface.h
index 13a37537..f3c6522 100644
--- a/components/viz/service/surfaces/surface.h
+++ b/components/viz/service/surfaces/surface.h
@@ -102,7 +102,12 @@
 
   bool has_deadline() const { return deadline_ && deadline_->has_deadline(); }
 
-  bool InheritActivationDeadlineFrom(Surface* surface);
+  // Inherits the same deadline as the one specified by |surface|. A deadline
+  // may be set further out in order to avoid doing unnecessary work while a
+  // parent surface is blocked on dependencies. A deadline may be shortened
+  // in order to minimize guttering (by unblocking children blocked on their
+  // grandchildren sooner).
+  void InheritActivationDeadlineFrom(Surface* surface);
 
   void SetPreviousFrameSurface(Surface* surface);
 
diff --git a/components/viz/service/surfaces/surface_dependency_deadline.cc b/components/viz/service/surfaces/surface_dependency_deadline.cc
index bd28f50..14678e8 100644
--- a/components/viz/service/surfaces/surface_dependency_deadline.cc
+++ b/components/viz/service/surfaces/surface_dependency_deadline.cc
@@ -42,20 +42,20 @@
   return CancelInternal(false);
 }
 
-bool SurfaceDependencyDeadline::InheritFrom(
+void SurfaceDependencyDeadline::InheritFrom(
     const SurfaceDependencyDeadline& other) {
   if (*this == other)
-    return false;
+    return;
 
-  DCHECK(has_deadline());
-
-  CancelInternal(false);
+  base::Optional<base::TimeDelta> duration = CancelInternal(false);
   last_begin_frame_args_ = other.last_begin_frame_args_;
   begin_frame_source_ = other.begin_frame_source_;
   deadline_ = other.deadline_;
-  if (deadline_)
+  if (deadline_) {
+    if (!duration)
+      start_time_ = tick_clock_->NowTicks();
     begin_frame_source_->AddObserver(this);
-  return true;
+  }
 }
 
 bool SurfaceDependencyDeadline::operator==(
diff --git a/components/viz/service/surfaces/surface_dependency_deadline.h b/components/viz/service/surfaces/surface_dependency_deadline.h
index a2be092..6bc6902 100644
--- a/components/viz/service/surfaces/surface_dependency_deadline.h
+++ b/components/viz/service/surfaces/surface_dependency_deadline.h
@@ -38,9 +38,12 @@
 
   bool has_deadline() const { return deadline_.has_value(); }
 
-  // Takes on the same BeginFrameSource and deadline as |other|. Returns
-  // false if they're already the same, and true otherwise.
-  bool InheritFrom(const SurfaceDependencyDeadline& other);
+  base::Optional<base::TimeTicks> deadline_for_testing() const {
+    return deadline_;
+  }
+
+  // Takes on the same BeginFrameSource and deadline as |other|.
+  void InheritFrom(const SurfaceDependencyDeadline& other);
 
   bool operator==(const SurfaceDependencyDeadline& other);
   bool operator!=(const SurfaceDependencyDeadline& other) {
diff --git a/components/viz/service/surfaces/surface_dependency_deadline_unittest.cc b/components/viz/service/surfaces/surface_dependency_deadline_unittest.cc
index ce631b2..98bb7b39 100644
--- a/components/viz/service/surfaces/surface_dependency_deadline_unittest.cc
+++ b/components/viz/service/surfaces/surface_dependency_deadline_unittest.cc
@@ -64,6 +64,8 @@
 
   SurfaceDependencyDeadline* deadline() { return deadline_.get(); }
 
+  SurfaceDependencyDeadline* deadline2() { return deadline2_.get(); }
+
   void SendLateBeginFrame(uint32_t frames_late) {
     // Creep the time forward so that any BeginFrameArgs is not equal to the
     // last one otherwise we violate the BeginFrameSource contract.
@@ -83,9 +85,14 @@
 
     deadline_ = std::make_unique<SurfaceDependencyDeadline>(
         &client_, begin_frame_source_.get(), now_src_.get());
+
+    deadline2_ = std::make_unique<SurfaceDependencyDeadline>(
+        &client_, begin_frame_source_.get(), now_src_.get());
   }
 
   void TearDown() override {
+    deadline2_->Cancel();
+    deadline2_.reset();
     deadline_->Cancel();
     deadline_.reset();
     begin_frame_source_.reset();
@@ -97,6 +104,7 @@
   std::unique_ptr<FakeSlowBeginFrameSource> begin_frame_source_;
   FakeSurfaceDeadlineClient client_;
   std::unique_ptr<SurfaceDependencyDeadline> deadline_;
+  std::unique_ptr<SurfaceDependencyDeadline> deadline2_;
 
   DISALLOW_COPY_AND_ASSIGN(SurfaceDependencyDeadlineTest);
 };
@@ -128,5 +136,65 @@
   EXPECT_TRUE(deadline()->has_deadline());
 }
 
+// This test verifies that inheriting a deadline with no pre-existing deadline
+// sets up the start time of the event to the time of inheritance.
+TEST_F(SurfaceDependencyDeadlineTest, InheritDeadline) {
+  FrameDeadline frame_deadline = MakeDefaultDeadline();
+  SendLateBeginFrame(1u);
+  EXPECT_TRUE(deadline()->Set(frame_deadline));
+  EXPECT_TRUE(deadline()->has_deadline());
+
+  SendLateBeginFrame(1u);
+  EXPECT_FALSE(deadline2()->has_deadline());
+  deadline2()->InheritFrom(*deadline());
+  EXPECT_TRUE(deadline()->has_deadline());
+  EXPECT_EQ(deadline()->deadline_for_testing(),
+            deadline2()->deadline_for_testing());
+
+  base::Optional<base::TimeDelta> duration1 = deadline()->Cancel();
+  base::Optional<base::TimeDelta> duration2 = deadline2()->Cancel();
+  ASSERT_TRUE(duration1.has_value());
+  ASSERT_TRUE(duration2.has_value());
+
+  // We inject time on BeginFrameSource::AddObserver and in practice we cannot
+  // know the exact difference in duration between two events a priori so we
+  // just verify that the first event was longer than the second.
+  EXPECT_GT(duration1, duration2);
+}
+
+// This test verifies that if an active deadline object inherits a deadline
+// from another object, it does not inherit the start time of the event.
+TEST_F(SurfaceDependencyDeadlineTest, InheritDeadlineWithActiveDeadline) {
+  {
+    FrameDeadline frame_deadline = MakeDefaultDeadline();
+    SendLateBeginFrame(1u);
+    EXPECT_TRUE(deadline()->Set(frame_deadline));
+    EXPECT_TRUE(deadline()->has_deadline());
+  }
+
+  {
+    FrameDeadline frame_deadline = MakeDefaultDeadline();
+    SendLateBeginFrame(1u);
+    // deadline2's start time is later than deadline2.
+    EXPECT_TRUE(deadline2()->Set(frame_deadline));
+    EXPECT_TRUE(deadline2()->has_deadline());
+  }
+
+  deadline()->InheritFrom(*deadline2());
+  EXPECT_TRUE(deadline()->has_deadline());
+  EXPECT_EQ(deadline()->deadline_for_testing(),
+            deadline2()->deadline_for_testing());
+
+  base::Optional<base::TimeDelta> duration1 = deadline()->Cancel();
+  base::Optional<base::TimeDelta> duration2 = deadline2()->Cancel();
+  ASSERT_TRUE(duration1.has_value());
+  ASSERT_TRUE(duration2.has_value());
+
+  // We inject time on BeginFrameSource::AddObserver and in practice we cannot
+  // know the exact difference in duration between two events a priori so we
+  // just verify that the first event was longer than the second.
+  EXPECT_GT(duration1, duration2);
+}
+
 }  // namespace test
 }  // namespace viz
diff --git a/components/viz/service/surfaces/surface_dependency_tracker.cc b/components/viz/service/surfaces/surface_dependency_tracker.cc
index a419397..74942f2 100644
--- a/components/viz/service/surfaces/surface_dependency_tracker.cc
+++ b/components/viz/service/surfaces/surface_dependency_tracker.cc
@@ -121,9 +121,6 @@
 
   const CompositorFrame& pending_frame = surface->GetPendingFrame();
 
-  // Determine an activation deadline for the pending CompositorFrame.
-  bool deadline_changed = false;
-
   // Inherit the deadline from the first parent blocked on this surface.
   auto it = blocked_surfaces_from_dependency_.find(
       surface->surface_id().frame_sink_id());
@@ -133,7 +130,7 @@
       Surface* parent = surface_manager_->GetSurfaceForId(parent_id);
       if (parent && parent->has_deadline() &&
           parent->activation_dependencies().count(surface->surface_id())) {
-        deadline_changed = surface->InheritActivationDeadlineFrom(parent);
+        surface->InheritActivationDeadlineFrom(parent);
         break;
       }
     }
diff --git a/content/browser/appcache/appcache_url_loader_job.cc b/content/browser/appcache/appcache_url_loader_job.cc
index 109992c..7add0b0 100644
--- a/content/browser/appcache/appcache_url_loader_job.cc
+++ b/content/browser/appcache/appcache_url_loader_job.cc
@@ -327,6 +327,10 @@
 
   network::URLLoaderCompletionStatus status(error_code);
   if (!error_code) {
+    const net::HttpResponseInfo* http_info =
+        is_range_request() ? range_response_info_.get()
+                           : (info_ ? info_->http_response_info() : nullptr);
+    status.exists_in_cache = http_info->was_cached;
     status.completion_time = base::TimeTicks::Now();
     status.encoded_body_length =
         is_range_request() ? range_response_info_->headers->GetContentLength()
diff --git a/content/browser/download/download_item_impl.cc b/content/browser/download/download_item_impl.cc
index 52068e0..6e5f66d 100644
--- a/content/browser/download/download_item_impl.cc
+++ b/content/browser/download/download_item_impl.cc
@@ -55,12 +55,12 @@
 #include "content/browser/download/download_utils.h"
 #include "content/browser/download/parallel_download_utils.h"
 #include "content/browser/renderer_host/render_view_host_impl.h"
+#include "content/browser/storage_partition_impl.h"
 #include "content/browser/web_contents/web_contents_impl.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/content_browser_client.h"
 #include "content/public/browser/download_item_utils.h"
-#include "content/public/browser/storage_partition.h"
 #include "content/public/common/content_features.h"
 #include "content/public/common/referrer.h"
 #include "net/http/http_response_headers.h"
@@ -2355,9 +2355,9 @@
     received_slices_.clear();
   }
 
-  StoragePartition* storage_partition =
+  StoragePartitionImpl* storage_partition = static_cast<StoragePartitionImpl*>(
       BrowserContext::GetStoragePartitionForSite(GetBrowserContext(),
-                                                 request_info_.site_url);
+                                                 request_info_.site_url));
 
   net::NetworkTrafficAnnotationTag traffic_annotation =
       net::DefineNetworkTrafficAnnotation("download_manager_resume", R"(
@@ -2429,7 +2429,8 @@
         in_progress_entry->ukm_download_id, GetResumeMode(), time_since_start);
   }
 
-  delegate_->ResumeInterruptedDownload(std::move(download_params), GetId());
+  delegate_->ResumeInterruptedDownload(std::move(download_params), GetId(),
+                                       storage_partition);
 
   if (job_)
     job_->Resume(false);
diff --git a/content/browser/download/download_item_impl_delegate.cc b/content/browser/download/download_item_impl_delegate.cc
index 0c03780e..cb30d4c2 100644
--- a/content/browser/download/download_item_impl_delegate.cc
+++ b/content/browser/download/download_item_impl_delegate.cc
@@ -64,7 +64,8 @@
 
 void DownloadItemImplDelegate::ResumeInterruptedDownload(
     std::unique_ptr<download::DownloadUrlParameters> params,
-    uint32_t id) {}
+    uint32_t id,
+    StoragePartitionImpl* storage_partition) {}
 
 BrowserContext* DownloadItemImplDelegate::GetBrowserContext() const {
   return nullptr;
diff --git a/content/browser/download/download_item_impl_delegate.h b/content/browser/download/download_item_impl_delegate.h
index f919d5d..ddc8b25 100644
--- a/content/browser/download/download_item_impl_delegate.h
+++ b/content/browser/download/download_item_impl_delegate.h
@@ -16,8 +16,9 @@
 #include "content/public/browser/download_manager_delegate.h"
 
 namespace content {
-class DownloadItemImpl;
 class BrowserContext;
+class DownloadItemImpl;
+class StoragePartitionImpl;
 
 // Delegate for operations that a DownloadItemImpl can't do for itself.
 // The base implementation of this class does nothing (returning false
@@ -73,7 +74,8 @@
   // Called when an interrupted download is resumed.
   virtual void ResumeInterruptedDownload(
       std::unique_ptr<download::DownloadUrlParameters> params,
-      uint32_t id);
+      uint32_t id,
+      StoragePartitionImpl* storage_partition);
 
   // For contextual issues like language and prefs.
   virtual BrowserContext* GetBrowserContext() const;
diff --git a/content/browser/download/download_item_impl_unittest.cc b/content/browser/download/download_item_impl_unittest.cc
index f593211..ca77584 100644
--- a/content/browser/download/download_item_impl_unittest.cc
+++ b/content/browser/download/download_item_impl_unittest.cc
@@ -90,7 +90,8 @@
 
   void ResumeInterruptedDownload(
       std::unique_ptr<download::DownloadUrlParameters> params,
-      uint32_t id) override {
+      uint32_t id,
+      StoragePartitionImpl* storage_partition) override {
     MockResumeInterruptedDownload(params.get(), id);
   }
   MOCK_METHOD2(MockResumeInterruptedDownload,
diff --git a/content/browser/download/download_manager_impl.cc b/content/browser/download/download_manager_impl.cc
index 873d197f..13e5756 100644
--- a/content/browser/download/download_manager_impl.cc
+++ b/content/browser/download/download_manager_impl.cc
@@ -786,8 +786,9 @@
 // download.
 void DownloadManagerImpl::ResumeInterruptedDownload(
     std::unique_ptr<download::DownloadUrlParameters> params,
-    uint32_t id) {
-  BeginDownloadInternal(std::move(params), nullptr, id);
+    uint32_t id,
+    StoragePartitionImpl* storage_partition) {
+  BeginDownloadInternal(std::move(params), nullptr, id, storage_partition);
 }
 
 
@@ -951,8 +952,11 @@
   download::RecordDownloadCountWithSource(
       download::DownloadCountTypes::DOWNLOAD_TRIGGERED_COUNT,
       params->download_source());
+  StoragePartitionImpl* storage_partition =
+      GetStoragePartition(browser_context_, params->render_process_host_id(),
+                          params->render_frame_host_routing_id());
   BeginDownloadInternal(std::move(params), std::move(blob_data_handle),
-                        download::DownloadItem::kInvalidId);
+                        download::DownloadItem::kInvalidId, storage_partition);
 }
 
 void DownloadManagerImpl::AddObserver(Observer* observer) {
@@ -1146,21 +1150,28 @@
 
   int render_process_id = -1;
   int render_frame_id = -1;
+  GURL site_url, tab_url, tab_referrer_url;
   WebContents* web_contents = web_contents_getter.Run();
   if (web_contents) {
     RenderFrameHost* render_frame_host = web_contents->GetMainFrame();
     if (render_frame_host) {
       render_process_id = render_frame_host->GetProcess()->GetID();
       render_frame_id = render_frame_host->GetRoutingID();
+      site_url = render_frame_host->GetSiteInstance()->GetSiteURL();
+    }
+    NavigationEntry* entry = web_contents->GetController().GetVisibleEntry();
+    if (entry) {
+      tab_url = entry->GetURL();
+      tab_referrer_url = entry->GetReferrer().url;
     }
   }
   BrowserThread::PostTask(
       BrowserThread::IO, FROM_HERE,
       base::BindOnce(&DownloadManagerImpl::CreateDownloadHandlerForNavigation,
                      weak_factory_.GetWeakPtr(), std::move(resource_request),
-                     render_process_id, render_frame_id, std::move(url_chain),
-                     suggested_filename, std::move(response),
-                     std::move(cert_status),
+                     render_process_id, render_frame_id, site_url, tab_url,
+                     tab_referrer_url, std::move(url_chain), suggested_filename,
+                     std::move(response), std::move(cert_status),
                      std::move(url_loader_client_endpoints),
                      base::MessageLoop::current()->task_runner()));
 }
@@ -1171,6 +1182,9 @@
     std::unique_ptr<network::ResourceRequest> resource_request,
     int render_process_id,
     int render_frame_id,
+    const GURL& site_url,
+    const GURL& tab_url,
+    const GURL& tab_referrer_url,
     std::vector<GURL> url_chain,
     const base::Optional<std::string>& suggested_filename,
     scoped_refptr<network::ResourceResponse> response,
@@ -1182,9 +1196,10 @@
   std::unique_ptr<ResourceDownloader> resource_downloader =
       ResourceDownloader::InterceptNavigationResponse(
           download_manager, std::move(resource_request), render_process_id,
-          render_frame_id, std::move(url_chain), suggested_filename,
-          std::move(response), std::move(cert_status),
-          std::move(url_loader_client_endpoints), task_runner);
+          render_frame_id, site_url, tab_url, tab_referrer_url,
+          std::move(url_chain), suggested_filename, std::move(response),
+          std::move(cert_status), std::move(url_loader_client_endpoints),
+          task_runner);
 
   BrowserThread::PostTask(
       BrowserThread::UI, FROM_HERE,
@@ -1197,14 +1212,11 @@
 void DownloadManagerImpl::BeginDownloadInternal(
     std::unique_ptr<download::DownloadUrlParameters> params,
     std::unique_ptr<storage::BlobDataHandle> blob_data_handle,
-    uint32_t id) {
+    uint32_t id,
+    StoragePartitionImpl* storage_partition) {
   if (base::FeatureList::IsEnabled(network::features::kNetworkService)) {
     std::unique_ptr<network::ResourceRequest> request =
         CreateResourceRequest(params.get());
-    StoragePartitionImpl* storage_partition =
-        GetStoragePartition(browser_context_, params->render_process_host_id(),
-                            params->render_frame_host_routing_id());
-
     GURL site_url, tab_url, tab_referrer_url;
     auto* rfh = RenderFrameHost::FromID(params->render_process_host_id(),
                                         params->render_frame_host_routing_id());
diff --git a/content/browser/download/download_manager_impl.h b/content/browser/download/download_manager_impl.h
index 9bc80c1..f6d1b61 100644
--- a/content/browser/download/download_manager_impl.h
+++ b/content/browser/download/download_manager_impl.h
@@ -221,7 +221,8 @@
   std::string GetApplicationClientIdForFileScanning() const override;
   void ResumeInterruptedDownload(
       std::unique_ptr<download::DownloadUrlParameters> params,
-      uint32_t id) override;
+      uint32_t id,
+      StoragePartitionImpl* storage_partition) override;
   void OpenDownload(DownloadItemImpl* download) override;
   bool IsMostRecentDownloadItemAtFilePath(DownloadItemImpl* download) override;
   void ShowDownloadInShell(DownloadItemImpl* download) override;
@@ -233,7 +234,8 @@
   void BeginDownloadInternal(
       std::unique_ptr<download::DownloadUrlParameters> params,
       std::unique_ptr<storage::BlobDataHandle> blob_data_handle,
-      uint32_t id);
+      uint32_t id,
+      StoragePartitionImpl* storage_partition);
 
   void InterceptNavigationOnChecksComplete(
       ResourceRequestInfo::WebContentsGetter web_contents_getter,
@@ -253,6 +255,9 @@
       std::unique_ptr<network::ResourceRequest> resource_request,
       int render_process_id,
       int render_frame_id,
+      const GURL& site_url,
+      const GURL& tab_url,
+      const GURL& tab_referrer_url,
       std::vector<GURL> url_chain,
       const base::Optional<std::string>& suggested_filename,
       scoped_refptr<network::ResourceResponse> response,
diff --git a/content/browser/download/resource_downloader.cc b/content/browser/download/resource_downloader.cc
index b2d4766..7f6ca04 100644
--- a/content/browser/download/resource_downloader.cc
+++ b/content/browser/download/resource_downloader.cc
@@ -85,6 +85,9 @@
     std::unique_ptr<network::ResourceRequest> resource_request,
     int render_process_id,
     int render_frame_id,
+    const GURL& site_url,
+    const GURL& tab_url,
+    const GURL& tab_referrer_url,
     std::vector<GURL> url_chain,
     const base::Optional<std::string>& suggested_filename,
     const scoped_refptr<network::ResourceResponse>& response,
@@ -93,7 +96,8 @@
     const scoped_refptr<base::SingleThreadTaskRunner>& task_runner) {
   auto downloader = std::make_unique<ResourceDownloader>(
       delegate, std::move(resource_request), render_process_id, render_frame_id,
-      GURL(), GURL(), GURL(), download::DownloadItem::kInvalidId, task_runner);
+      site_url, tab_url, tab_referrer_url, download::DownloadItem::kInvalidId,
+      task_runner);
   downloader->InterceptResponse(std::move(response), std::move(url_chain),
                                 suggested_filename, cert_status,
                                 std::move(url_loader_client_endpoints));
diff --git a/content/browser/download/resource_downloader.h b/content/browser/download/resource_downloader.h
index 633fe2e..a22250a 100644
--- a/content/browser/download/resource_downloader.h
+++ b/content/browser/download/resource_downloader.h
@@ -43,6 +43,9 @@
       std::unique_ptr<network::ResourceRequest> resource_request,
       int render_process_id,
       int render_frame_id,
+      const GURL& site_url,
+      const GURL& tab_url,
+      const GURL& tab_referrer_url,
       std::vector<GURL> url_chain,
       const base::Optional<std::string>& suggested_filename,
       const scoped_refptr<network::ResourceResponse>& response,
diff --git a/content/browser/frame_host/navigation_handle_impl.cc b/content/browser/frame_host/navigation_handle_impl.cc
index 4ce79a4..cfddc12 100644
--- a/content/browser/frame_host/navigation_handle_impl.cc
+++ b/content/browser/frame_host/navigation_handle_impl.cc
@@ -570,11 +570,6 @@
     request->RegisterSubresourceOverride(std::move(transferrable_loader));
 }
 
-void NavigationHandleImpl::SetOnDeferCallbackForTesting(
-    const base::Closure& on_defer_callback) {
-  on_defer_callback_for_testing_ = on_defer_callback;
-}
-
 const GlobalRequestID& NavigationHandleImpl::GetGlobalRequestID() {
   DCHECK(state_ >= WILL_PROCESS_RESPONSE);
   return request_id_;
@@ -632,11 +627,8 @@
     navigation_ui_data_ = GetDelegate()->GetNavigationUIData(this);
 
   // Notify each throttle of the request.
-  base::Closure on_defer_callback_copy = on_defer_callback_for_testing_;
   NavigationThrottle::ThrottleCheckResult result = CheckWillStartRequest();
   if (result.action() == NavigationThrottle::DEFER) {
-    if (!on_defer_callback_copy.is_null())
-      on_defer_callback_copy.Run();
     // DO NOT ADD CODE: the NavigationHandle might have been destroyed during
     // one of the NavigationThrottle checks.
     return;
@@ -709,11 +701,8 @@
   }
 
   // Notify each throttle of the request.
-  base::Closure on_defer_callback_copy = on_defer_callback_for_testing_;
   NavigationThrottle::ThrottleCheckResult result = CheckWillRedirectRequest();
   if (result.action() == NavigationThrottle::DEFER) {
-    if (!on_defer_callback_copy.is_null())
-      on_defer_callback_copy.Run();
     // DO NOT ADD CODE: the NavigationHandle might have been destroyed during
     // one of the NavigationThrottle checks.
     return;
@@ -736,11 +725,8 @@
   state_ = WILL_FAIL_REQUEST;
 
   // Notify each throttle of the request.
-  base::Closure on_defer_callback_copy = on_defer_callback_for_testing_;
   NavigationThrottle::ThrottleCheckResult result = CheckWillFailRequest();
   if (result.action() == NavigationThrottle::DEFER) {
-    if (!on_defer_callback_copy.is_null())
-      on_defer_callback_copy.Run();
     // DO NOT ADD CODE: the NavigationHandle might have been destroyed during
     // one of the NavigationThrottle checks.
     return;
@@ -779,11 +765,8 @@
   complete_callback_ = callback;
 
   // Notify each throttle of the response.
-  base::Closure on_defer_callback_copy = on_defer_callback_for_testing_;
   NavigationThrottle::ThrottleCheckResult result = CheckWillProcessResponse();
   if (result.action() == NavigationThrottle::DEFER) {
-    if (!on_defer_callback_copy.is_null())
-      on_defer_callback_copy.Run();
     // DO NOT ADD CODE: the NavigationHandle might have been destroyed during
     // one of the NavigationThrottle checks.
     return;
@@ -1131,12 +1114,9 @@
                                "Resume");
 
   NavigationThrottle::ThrottleCheckResult result = NavigationThrottle::DEFER;
-  base::Closure on_defer_callback_copy = on_defer_callback_for_testing_;
   if (state_ == DEFERRING_START) {
     result = CheckWillStartRequest();
     if (result.action() == NavigationThrottle::DEFER) {
-      if (!on_defer_callback_copy.is_null())
-        on_defer_callback_copy.Run();
       // DO NOT ADD CODE: the NavigationHandle might have been destroyed during
       // one of the NavigationThrottle checks.
       return;
@@ -1144,8 +1124,6 @@
   } else if (state_ == DEFERRING_REDIRECT) {
     result = CheckWillRedirectRequest();
     if (result.action() == NavigationThrottle::DEFER) {
-      if (!on_defer_callback_copy.is_null())
-        on_defer_callback_copy.Run();
       // DO NOT ADD CODE: the NavigationHandle might have been destroyed during
       // one of the NavigationThrottle checks.
       return;
@@ -1153,8 +1131,6 @@
   } else if (state_ == DEFERRING_FAILURE) {
     result = CheckWillFailRequest();
     if (result.action() == NavigationThrottle::DEFER) {
-      if (!on_defer_callback_copy.is_null())
-        on_defer_callback_copy.Run();
       // DO NOT ADD CODE: the NavigationHandle might have been destroyed during
       // one of the NavigationThrottle checks.
       return;
@@ -1162,8 +1138,6 @@
   } else {
     result = CheckWillProcessResponse();
     if (result.action() == NavigationThrottle::DEFER) {
-      if (!on_defer_callback_copy.is_null())
-        on_defer_callback_copy.Run();
       // DO NOT ADD CODE: the NavigationHandle might have been destroyed during
       // one of the NavigationThrottle checks.
       return;
diff --git a/content/browser/frame_host/navigation_handle_impl.h b/content/browser/frame_host/navigation_handle_impl.h
index 90c11ed..63fc835b 100644
--- a/content/browser/frame_host/navigation_handle_impl.h
+++ b/content/browser/frame_host/navigation_handle_impl.h
@@ -173,7 +173,6 @@
 
   // Used in tests.
   State state_for_testing() const { return state_; }
-  void SetOnDeferCallbackForTesting(const base::Closure& on_defer_callback);
 
   // The NavigatorDelegate to notify/query for various navigation events.
   // Normally this is the WebContents, except if this NavigationHandle was
@@ -569,10 +568,6 @@
   // in it.
   int expected_render_process_host_id_;
 
-  // Used in tests. Called when the navigation is deferred by one of the
-  // NavigationThrottles.
-  base::Closure on_defer_callback_for_testing_;
-
   // If this navigation was triggered by an anchor element with a download
   // attribute, the |suggested_filename_| contains the attribute's (possibly
   // empty) value.
diff --git a/content/browser/gpu/gpu_process_host.cc b/content/browser/gpu/gpu_process_host.cc
index d593d87d..f780c04 100644
--- a/content/browser/gpu/gpu_process_host.cc
+++ b/content/browser/gpu/gpu_process_host.cc
@@ -148,6 +148,7 @@
     switches::kEnableLowEndDeviceMode,
     switches::kDisableLowEndDeviceMode,
     switches::kNoSandbox,
+    switches::kRunAllCompositorStagesBeforeDraw,
     switches::kTestGLLib,
     switches::kTraceConfigFile,
     switches::kTraceStartup,
diff --git a/content/browser/linux_ipc_browsertest.cc b/content/browser/linux_ipc_browsertest.cc
index 8f917df..0654dff 100644
--- a/content/browser/linux_ipc_browsertest.cc
+++ b/content/browser/linux_ipc_browsertest.cc
@@ -16,7 +16,6 @@
 #include "testing/gmock/include/gmock/gmock-matchers.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "ui/gfx/test/fontconfig_util_linux.h"
 
 namespace content {
 
@@ -25,7 +24,6 @@
                             public testing::WithParamInterface<std::string> {
  public:
   LinuxIPCBrowserTest() {
-    SetUpFontConfigForTest();
     SandboxIPCHandler::SetObserverForTests(this);
   }
   ~LinuxIPCBrowserTest() override {}
@@ -39,16 +37,6 @@
     }
   }
 
-  // Override the system fontconfig configuration with a test configuration so
-  // that the tested font fallback will work the same across systems.
-  void SetUpFontConfigForTest() {
-    gfx::SetUpFontconfig();
-    for (size_t i = 0; i < gfx::kNumSystemFontsForFontconfig; ++i) {
-      gfx::LoadFontIntoFontconfig(
-          base::FilePath(gfx::kSystemFontsForFontconfig[i]));
-    }
-  }
-
   void OnFontOpen(int id) override {
     base::AutoLock lock(lock_);
     opened_fonts_.insert(font_names_[id]);
diff --git a/content/browser/loader/mojo_async_resource_handler.cc b/content/browser/loader/mojo_async_resource_handler.cc
index 3be55fa6..8ad8f67a 100644
--- a/content/browser/loader/mojo_async_resource_handler.cc
+++ b/content/browser/loader/mojo_async_resource_handler.cc
@@ -486,6 +486,7 @@
 
   network::URLLoaderCompletionStatus loader_status;
   loader_status.error_code = error_code;
+  loader_status.exists_in_cache = request()->response_info().was_cached;
   loader_status.completion_time = base::TimeTicks::Now();
   loader_status.encoded_data_length = request()->GetTotalReceivedBytes();
   loader_status.encoded_body_length = request()->GetRawBodyBytes();
diff --git a/content/browser/loader/navigation_url_loader_network_service.cc b/content/browser/loader/navigation_url_loader_network_service.cc
index 56aa2f7..7ce141a 100644
--- a/content/browser/loader/navigation_url_loader_network_service.cc
+++ b/content/browser/loader/navigation_url_loader_network_service.cc
@@ -972,7 +972,6 @@
     std::vector<std::unique_ptr<URLLoaderRequestHandler>> initial_handlers)
     : delegate_(delegate),
       allow_download_(request_info->common_params.allow_download),
-      response_was_cached_(false),
       weak_factory_(this) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   int frame_tree_node_id = request_info->frame_tree_node_id;
@@ -1119,7 +1118,6 @@
   net::SSLInfo ssl_info;
   if (maybe_ssl_info.has_value())
     ssl_info = maybe_ssl_info.value();
-  response_was_cached_ = response->head.was_cached;
 
   delegate_->OnResponseStarted(
       std::move(response), std::move(url_loader_client_endpoints), nullptr,
@@ -1144,7 +1142,7 @@
                          "&NavigationURLLoaderNetworkService", this, "success",
                          false);
 
-  delegate_->OnRequestFailed(response_was_cached_, status.error_code,
+  delegate_->OnRequestFailed(status.exists_in_cache, status.error_code,
                              status.ssl_info);
 }
 
diff --git a/content/browser/loader/navigation_url_loader_network_service.h b/content/browser/loader/navigation_url_loader_network_service.h
index 0b96b8a..4247377 100644
--- a/content/browser/loader/navigation_url_loader_network_service.h
+++ b/content/browser/loader/navigation_url_loader_network_service.h
@@ -78,7 +78,6 @@
   std::unique_ptr<URLLoaderRequestController> request_controller_;
 
   bool allow_download_;
-  bool response_was_cached_;
 
   // Factories to handle navigation requests for non-network resources.
   ContentBrowserClient::NonNetworkURLLoaderFactoryMap
diff --git a/content/browser/loader/resource_dispatcher_host_impl.cc b/content/browser/loader/resource_dispatcher_host_impl.cc
index 54624e8..54b5b29 100644
--- a/content/browser/loader/resource_dispatcher_host_impl.cc
+++ b/content/browser/loader/resource_dispatcher_host_impl.cc
@@ -168,6 +168,7 @@
   // Tell the renderer that this request was disallowed.
   network::URLLoaderCompletionStatus status;
   status.error_code = net::ERR_ABORTED;
+  status.exists_in_cache = false;
   // No security info needed, connection not established.
   status.completion_time = base::TimeTicks();
   status.encoded_data_length = 0;
diff --git a/content/browser/loader/resource_loader.cc b/content/browser/loader/resource_loader.cc
index 44a09aec..547488f 100644
--- a/content/browser/loader/resource_loader.cc
+++ b/content/browser/loader/resource_loader.cc
@@ -64,7 +64,6 @@
   response->head.headers = request->response_headers();
   request->GetCharset(&response->head.charset);
   response->head.content_length = request->GetExpectedContentSize();
-  response->head.was_cached = request->was_cached();
   request->GetMimeType(&response->head.mime_type);
   net::HttpResponseInfo response_info = request->response_info();
   response->head.was_fetched_via_spdy = response_info.was_fetched_via_spdy;
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 e286adb..a893ca2 100644
--- a/content/browser/renderer_host/p2p/socket_host_udp_unittest.cc
+++ b/content/browser/renderer_host/p2p/socket_host_udp_unittest.cc
@@ -126,6 +126,8 @@
 
   int SetDoNotFragment() override { return net::OK; }
 
+  void SetMsgConfirm(bool confirm) override {}
+
   void ReceivePacket(const net::IPEndPoint& address, std::vector<char> data) {
     if (!recv_callback_.is_null()) {
       int size = std::min(recv_size_, static_cast<int>(data.size()));
diff --git a/content/browser/web_contents/web_contents_impl_browsertest.cc b/content/browser/web_contents/web_contents_impl_browsertest.cc
index 0d2adec..6f4c8f2 100644
--- a/content/browser/web_contents/web_contents_impl_browsertest.cc
+++ b/content/browser/web_contents/web_contents_impl_browsertest.cc
@@ -523,40 +523,6 @@
   EXPECT_TRUE(new_web_contents_observer.RenderViewCreatedCalled());
 }
 
-// Observer class to track subresource loads.
-class SubresourceLoadObserver : public WebContentsObserver {
- public:
-  explicit SubresourceLoadObserver(Shell* shell)
-      : WebContentsObserver(shell->web_contents()) {}
-
-  void SubresourceResponseStarted(
-      const mojom::SubresourceLoadInfo& subresource_load_info) override {
-    last_subresource_load_info_ = subresource_load_info.Clone();
-  }
-
-  mojom::SubresourceLoadInfo* last_subresource_load_info() const {
-    return last_subresource_load_info_.get();
-  }
-
- private:
-  mojom::SubresourceLoadInfoPtr last_subresource_load_info_;
-
-  DISALLOW_COPY_AND_ASSIGN(SubresourceLoadObserver);
-};
-
-IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest,
-                       SubresourceLoadInfoReportsWasCached) {
-  SubresourceLoadObserver observer(shell());
-  ASSERT_TRUE(embedded_test_server()->Start());
-  GURL url(
-      embedded_test_server()->GetURL("/page_with_cached_subresource.html"));
-  NavigateToURL(shell(), url);
-  EXPECT_FALSE(observer.last_subresource_load_info()->was_cached);
-
-  NavigateToURL(shell(), url);
-  EXPECT_TRUE(observer.last_subresource_load_info()->was_cached);
-}
-
 struct LoadProgressDelegateAndObserver : public WebContentsDelegate,
                                          public WebContentsObserver {
   explicit LoadProgressDelegateAndObserver(Shell* shell)
diff --git a/content/common/manifest_share_target_util_unittest.cc b/content/common/manifest_share_target_util_unittest.cc
new file mode 100644
index 0000000..ff256e1b
--- /dev/null
+++ b/content/common/manifest_share_target_util_unittest.cc
@@ -0,0 +1,258 @@
+// 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 <map>
+#include <utility>
+
+#include "content/public/common/manifest_share_target_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+namespace content {
+namespace {
+
+constexpr char kTitle[] = "My title";
+constexpr char kText[] = "My text";
+constexpr char kUrlSpec[] = "https://www.google.com/";
+
+}  // namespace
+
+TEST(ManifestShareTargetUtilTest,
+     ReplaceWebShareUrlPlaceholdersInvalidTemplate) {
+  const GURL kUrl(kUrlSpec);
+  GURL url_template_filled;
+
+  // Badly nested placeholders.
+  GURL url_template = GURL("http://example.com/?q={");
+  bool succeeded = ReplaceWebShareUrlPlaceholders(url_template, kTitle, kText,
+                                                  kUrl, &url_template_filled);
+  EXPECT_FALSE(succeeded);
+
+  url_template = GURL("http://example.com/?q={title");
+  succeeded = ReplaceWebShareUrlPlaceholders(url_template, kTitle, kText, kUrl,
+                                             &url_template_filled);
+  EXPECT_FALSE(succeeded);
+
+  url_template = GURL("http://example.com/?q={title{text}}");
+  succeeded = ReplaceWebShareUrlPlaceholders(url_template, kTitle, kText, kUrl,
+                                             &url_template_filled);
+  EXPECT_FALSE(succeeded);
+
+  url_template = GURL("http://example.com/?q={title{}");
+  succeeded = ReplaceWebShareUrlPlaceholders(url_template, kTitle, kText, kUrl,
+                                             &url_template_filled);
+  EXPECT_FALSE(succeeded);
+
+  url_template = GURL("http://example.com/?q={{title}}");
+  succeeded = ReplaceWebShareUrlPlaceholders(url_template, kTitle, kText, kUrl,
+                                             &url_template_filled);
+  EXPECT_FALSE(succeeded);
+
+  // Placeholder with non-identifier character.
+  url_template = GURL("http://example.com/?q={title?}");
+  succeeded = ReplaceWebShareUrlPlaceholders(url_template, kTitle, kText, kUrl,
+                                             &url_template_filled);
+  EXPECT_FALSE(succeeded);
+
+  // Invalid placeholder in URL fragment.
+  url_template = GURL("http://example.com/#{title?}");
+  succeeded = ReplaceWebShareUrlPlaceholders(url_template, kTitle, kText, kUrl,
+                                             &url_template_filled);
+  EXPECT_FALSE(succeeded);
+}
+
+TEST(ManifestShareTargetUtilTest, ReplaceWebShareUrlPlaceholders) {
+  const GURL kUrl(kUrlSpec);
+
+  // No placeholders.
+  GURL url_template = GURL("http://example.com/?q=a#a");
+  GURL url_template_filled;
+  bool succeeded = ReplaceWebShareUrlPlaceholders(url_template, kTitle, kText,
+                                                  kUrl, &url_template_filled);
+  EXPECT_TRUE(succeeded);
+  EXPECT_EQ(url_template, url_template_filled);
+
+  // Empty |url_template|
+  url_template = GURL();
+  succeeded = ReplaceWebShareUrlPlaceholders(url_template, kTitle, kText, kUrl,
+                                             &url_template_filled);
+  EXPECT_TRUE(succeeded);
+  EXPECT_EQ(GURL(), url_template_filled);
+
+  // One title placeholder.
+  url_template = GURL("http://example.com/#{title}");
+  succeeded = ReplaceWebShareUrlPlaceholders(url_template, kTitle, kText, kUrl,
+                                             &url_template_filled);
+  EXPECT_TRUE(succeeded);
+  EXPECT_EQ("http://example.com/#My%20title", url_template_filled.spec());
+
+  // One text placeholder.
+  url_template = GURL("http://example.com/#{text}");
+  succeeded = ReplaceWebShareUrlPlaceholders(url_template, kTitle, kText, kUrl,
+                                             &url_template_filled);
+  EXPECT_TRUE(succeeded);
+  EXPECT_EQ("http://example.com/#My%20text", url_template_filled.spec());
+
+  // One url placeholder.
+  url_template = GURL("http://example.com/#{url}");
+  succeeded = ReplaceWebShareUrlPlaceholders(url_template, kTitle, kText, kUrl,
+                                             &url_template_filled);
+  EXPECT_TRUE(succeeded);
+  EXPECT_EQ("http://example.com/#https%3A%2F%2Fwww.google.com%2F",
+            url_template_filled.spec());
+
+  // One of each placeholder, in title, text, url order.
+  url_template = GURL("http://example.com/#{title}{text}{url}");
+  succeeded = ReplaceWebShareUrlPlaceholders(url_template, kTitle, kText, kUrl,
+                                             &url_template_filled);
+  EXPECT_TRUE(succeeded);
+  EXPECT_EQ(
+      "http://example.com/#My%20titleMy%20texthttps%3A%2F%2Fwww.google.com%2F",
+      url_template_filled.spec());
+
+  // One of each placeholder, in url, text, title order.
+  url_template = GURL("http://example.com/#{url}{text}{title}");
+  succeeded = ReplaceWebShareUrlPlaceholders(url_template, kTitle, kText, kUrl,
+                                             &url_template_filled);
+  EXPECT_TRUE(succeeded);
+  EXPECT_EQ(
+      "http://example.com/#https%3A%2F%2Fwww.google.com%2FMy%20textMy%20title",
+      url_template_filled.spec());
+
+  // Two of each placeholder, some next to each other, others not.
+  url_template =
+      GURL("http://example.com/#{title}{url}{text}{text}{title}{url}");
+  succeeded = ReplaceWebShareUrlPlaceholders(url_template, kTitle, kText, kUrl,
+                                             &url_template_filled);
+  EXPECT_TRUE(succeeded);
+  EXPECT_EQ(
+      "http://example.com/"
+      "#My%20titlehttps%3A%2F%2Fwww.google.com%2FMy%20textMy%20textMy%"
+      "20titlehttps%3A%2F%2Fwww.google.com%2F",
+      url_template_filled.spec());
+
+  // Placeholders are in a query string, as values. The expected use case.
+  // Two of each placeholder, some next to each other, others not.
+  url_template = GURL(
+      "http://example.com?title={title}&url={url}&text={text}&text={text}&"
+      "title={title}&url={url}");
+  succeeded = ReplaceWebShareUrlPlaceholders(url_template, kTitle, kText, kUrl,
+                                             &url_template_filled);
+  EXPECT_TRUE(succeeded);
+  EXPECT_EQ(
+      "http://"
+      "example.com/?title=My%20title&url=https%3A%2F%2Fwww.google.com%2F&"
+      "text=My%20text&"
+      "text=My%20text&title=My%20title&url=https%3A%2F%2Fwww.google.com%2F",
+      url_template_filled.spec());
+
+  // Placeholder with digit character.
+  url_template = GURL("http://example.com/#{title1}");
+  succeeded = ReplaceWebShareUrlPlaceholders(url_template, kTitle, kText, kUrl,
+                                             &url_template_filled);
+  EXPECT_TRUE(succeeded);
+  EXPECT_EQ("http://example.com/#", url_template_filled.spec());
+
+  // Empty placeholder.
+  url_template = GURL("http://example.com/#{}");
+  succeeded = ReplaceWebShareUrlPlaceholders(url_template, kTitle, kText, kUrl,
+                                             &url_template_filled);
+  EXPECT_TRUE(succeeded);
+  EXPECT_EQ("http://example.com/#", url_template_filled.spec());
+
+  // Unexpected placeholders.
+  url_template = GURL("http://example.com/#{nonexistentplaceholder}");
+  succeeded = ReplaceWebShareUrlPlaceholders(url_template, kTitle, kText, kUrl,
+                                             &url_template_filled);
+  EXPECT_TRUE(succeeded);
+  EXPECT_EQ("http://example.com/#", url_template_filled.spec());
+
+  // Placeholders should only be replaced in query and fragment.
+  url_template = GURL("http://example.com/subpath{title}/?q={title}#{title}");
+  succeeded = ReplaceWebShareUrlPlaceholders(url_template, kTitle, kText, kUrl,
+                                             &url_template_filled);
+  EXPECT_TRUE(succeeded);
+  EXPECT_EQ("http://example.com/subpath%7Btitle%7D/?q=My%20title#My%20title",
+            url_template_filled.spec());
+
+  // Braces in the path, which would be invalid, but should parse fine as they
+  // are escaped.
+  url_template = GURL("http://example.com/subpath{/?q={title}");
+  succeeded = ReplaceWebShareUrlPlaceholders(url_template, kTitle, kText, kUrl,
+                                             &url_template_filled);
+  EXPECT_TRUE(succeeded);
+  EXPECT_EQ("http://example.com/subpath%7B/?q=My%20title",
+            url_template_filled.spec());
+
+  // |url_template| with % escapes.
+  url_template = GURL("http://example.com#%20{title}%20");
+  succeeded = ReplaceWebShareUrlPlaceholders(url_template, kTitle, kText, kUrl,
+                                             &url_template_filled);
+  EXPECT_TRUE(succeeded);
+  EXPECT_EQ("http://example.com/#%20My%20title%20", url_template_filled.spec());
+}
+
+// Test URL escaping done by ReplaceWebShareUrlPlaceholders().
+TEST(ManifestShareTargetUtilTest, ReplaceWebShareUrlPlaceholders_Escaping) {
+  const GURL kUrl(kUrlSpec);
+  const GURL kUrlTemplate("http://example.com/#{title}");
+
+  // Share data that contains percent escapes.
+  GURL url_template_filled;
+  bool succeeded = ReplaceWebShareUrlPlaceholders(
+      kUrlTemplate, "My%20title", kText, kUrl, &url_template_filled);
+  EXPECT_TRUE(succeeded);
+  EXPECT_EQ("http://example.com/#My%2520title", url_template_filled.spec());
+
+  // Share data that contains placeholders. These should not be replaced.
+  succeeded = ReplaceWebShareUrlPlaceholders(kUrlTemplate, "{title}", kText,
+                                             kUrl, &url_template_filled);
+  EXPECT_TRUE(succeeded);
+  EXPECT_EQ("http://example.com/#%7Btitle%7D", url_template_filled.spec());
+
+  // All characters that shouldn't be escaped.
+  succeeded = ReplaceWebShareUrlPlaceholders(kUrlTemplate,
+                                             "-_.!~*'()0123456789"
+                                             "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+                                             "abcdefghijklmnopqrstuvwxyz",
+                                             kText, kUrl, &url_template_filled);
+  EXPECT_TRUE(succeeded);
+  EXPECT_EQ(
+      "http://example.com/#-_.!~*'()0123456789"
+      "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+      "abcdefghijklmnopqrstuvwxyz",
+      url_template_filled.spec());
+
+  // All characters that should be escaped.
+  succeeded =
+      ReplaceWebShareUrlPlaceholders(kUrlTemplate, " \"#$%&+,/:;<=>?@[\\]^`{|}",
+                                     kText, kUrl, &url_template_filled);
+  EXPECT_TRUE(succeeded);
+  EXPECT_EQ(
+      "http://example.com/"
+      "#%20%22%23%24%25%26%2B%2C%2F%3A%3B%3C%3D%3E%3F%40%5B%5C%5D%5E%60%7B%7C%"
+      "7D",
+      url_template_filled.spec());
+
+  // Unicode chars.
+  // U+263B
+  succeeded = ReplaceWebShareUrlPlaceholders(kUrlTemplate, "\xe2\x98\xbb",
+                                             kText, kUrl, &url_template_filled);
+  EXPECT_TRUE(succeeded);
+  EXPECT_EQ("http://example.com/#%E2%98%BB", url_template_filled.spec());
+
+  // U+00E9
+  succeeded = ReplaceWebShareUrlPlaceholders(kUrlTemplate, "\xc3\xa9", kText,
+                                             kUrl, &url_template_filled);
+  EXPECT_TRUE(succeeded);
+  EXPECT_EQ("http://example.com/#%C3%A9", url_template_filled.spec());
+
+  // U+1F4A9
+  succeeded = ReplaceWebShareUrlPlaceholders(kUrlTemplate, "\xf0\x9f\x92\xa9",
+                                             kText, kUrl, &url_template_filled);
+  EXPECT_TRUE(succeeded);
+  EXPECT_EQ("http://example.com/#%F0%9F%92%A9", url_template_filled.spec());
+}
+
+}  // namespace content
diff --git a/content/common/page_state_serialization.cc b/content/common/page_state_serialization.cc
index c6bb8f0..f4e8d254 100644
--- a/content/common/page_state_serialization.cc
+++ b/content/common/page_state_serialization.cc
@@ -706,8 +706,10 @@
       case network::DataElement::TYPE_BLOB:
         data_element->set_blob_uuid(element.blob_uuid());
         break;
-      case network::DataElement::TYPE_RAW_FILE:
       case network::DataElement::TYPE_DATA_PIPE:
+        NOTIMPLEMENTED();
+        break;
+      case network::DataElement::TYPE_RAW_FILE:
       case network::DataElement::TYPE_CHUNKED_DATA_PIPE:
       case network::DataElement::TYPE_UNKNOWN:
         NOTREACHED();
diff --git a/content/public/common/BUILD.gn b/content/public/common/BUILD.gn
index 384255e..8b8f389 100644
--- a/content/public/common/BUILD.gn
+++ b/content/public/common/BUILD.gn
@@ -158,6 +158,8 @@
     "main_function_params.h",
     "manifest.cc",
     "manifest.h",
+    "manifest_share_target_util.cc",
+    "manifest_share_target_util.h",
     "manifest_util.cc",
     "manifest_util.h",
     "media_metadata.cc",
diff --git a/content/public/common/manifest_share_target_util.cc b/content/public/common/manifest_share_target_util.cc
new file mode 100644
index 0000000..5be23648
--- /dev/null
+++ b/content/public/common/manifest_share_target_util.cc
@@ -0,0 +1,113 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/public/common/manifest_share_target_util.h"
+
+#include <map>
+
+#include "base/strings/strcat.h"
+#include "base/strings/string_util.h"
+#include "net/base/escape.h"
+#include "url/gurl.h"
+
+namespace content {
+namespace {
+
+// Determines whether a character is allowed in a URL template placeholder.
+bool IsIdentifier(char c) {
+  return base::IsAsciiAlpha(c) || base::IsAsciiDigit(c) || c == '-' || c == '_';
+}
+
+// Returns to |out| the result of running the "replace placeholders" algorithm
+// on |template_string|. The algorithm is specified at
+// https://wicg.github.io/web-share-target/#dfn-replace-placeholders
+bool ReplacePlaceholders(base::StringPiece template_string,
+                         base::StringPiece title,
+                         base::StringPiece text,
+                         const GURL& share_url,
+                         std::string* out) {
+  constexpr char kTitlePlaceholder[] = "title";
+  constexpr char kTextPlaceholder[] = "text";
+  constexpr char kUrlPlaceholder[] = "url";
+
+  std::map<base::StringPiece, std::string> placeholder_to_data;
+  placeholder_to_data[kTitlePlaceholder] =
+      net::EscapeQueryParamValue(title, false);
+  placeholder_to_data[kTextPlaceholder] =
+      net::EscapeQueryParamValue(text, false);
+  placeholder_to_data[kUrlPlaceholder] =
+      net::EscapeQueryParamValue(share_url.spec(), false);
+
+  std::vector<base::StringPiece> split_template;
+  bool last_saw_open = false;
+  size_t start_index_to_copy = 0;
+  for (size_t i = 0; i < template_string.size(); ++i) {
+    if (last_saw_open) {
+      if (template_string[i] == '}') {
+        base::StringPiece placeholder = template_string.substr(
+            start_index_to_copy + 1, i - 1 - start_index_to_copy);
+        auto it = placeholder_to_data.find(placeholder);
+        if (it != placeholder_to_data.end()) {
+          // Replace the placeholder text with the parameter value.
+          split_template.push_back(it->second);
+        }
+
+        last_saw_open = false;
+        start_index_to_copy = i + 1;
+      } else if (!IsIdentifier(template_string[i])) {
+        // Error: Non-identifier character seen after open.
+        return false;
+      }
+    } else {
+      if (template_string[i] == '}') {
+        // Error: Saw close, with no corresponding open.
+        return false;
+      } else if (template_string[i] == '{') {
+        split_template.push_back(template_string.substr(
+            start_index_to_copy, i - start_index_to_copy));
+
+        last_saw_open = true;
+        start_index_to_copy = i;
+      }
+    }
+  }
+  if (last_saw_open) {
+    // Error: Saw open that was never closed.
+    return false;
+  }
+  split_template.push_back(template_string.substr(
+      start_index_to_copy, template_string.size() - start_index_to_copy));
+
+  *out = base::StrCat(split_template);
+  return true;
+}
+
+}  // namespace
+
+bool ReplaceWebShareUrlPlaceholders(const GURL& url_template,
+                                    base::StringPiece title,
+                                    base::StringPiece text,
+                                    const GURL& share_url,
+                                    GURL* url_template_filled) {
+  std::string new_query;
+  std::string new_ref;
+  if (!ReplacePlaceholders(url_template.query_piece(), title, text, share_url,
+                           &new_query) ||
+      !ReplacePlaceholders(url_template.ref_piece(), title, text, share_url,
+                           &new_ref)) {
+    return false;
+  }
+
+  // Check whether |url_template| has a query in order to preserve the '?' in a
+  // URL with an empty query. e.g. http://www.google.com/?
+  GURL::Replacements url_replacements;
+  if (url_template.has_query())
+    url_replacements.SetQueryStr(new_query);
+  if (url_template.has_ref())
+    url_replacements.SetRefStr(new_ref);
+  *url_template_filled = url_template.ReplaceComponents(url_replacements);
+  return true;
+}
+
+}  // namespace content
diff --git a/content/public/common/manifest_share_target_util.h b/content/public/common/manifest_share_target_util.h
new file mode 100644
index 0000000..dd7f441c
--- /dev/null
+++ b/content/public/common/manifest_share_target_util.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 CONTENT_PUBLIC_COMMON_MANIFEST_SHARE_TARGET_UTIL_H_
+#define CONTENT_PUBLIC_COMMON_MANIFEST_SHARE_TARGET_UTIL_H_
+
+#include <string>
+
+#include "base/strings/string_piece.h"
+#include "content/common/content_export.h"
+
+class GURL;
+
+namespace content {
+
+// Writes to |url_template_filled|, a copy of |url_template| with all
+// instances of "{title}", "{text}", and "{url}" in the query and fragment
+// parts of the URL replaced with |title|, |text|, and |url| respectively.
+// Replaces instances of "{X}" where "X" is any string besides "title",
+// "text", and "url", with an empty string, for forwards compatibility.
+// Returns false, if there are badly nested placeholders.
+// This includes any case in which two "{" occur before a "}", or a "}"
+// occurs with no preceding "{".
+CONTENT_EXPORT bool ReplaceWebShareUrlPlaceholders(const GURL& url_template,
+                                                   base::StringPiece title,
+                                                   base::StringPiece text,
+                                                   const GURL& share_url,
+                                                   GURL* url_template_filled);
+
+}  // namespace content
+
+#endif  // CONTENT_PUBLIC_COMMON_MANIFEST_SHARE_TARGET_UTIL_H_
diff --git a/content/public/common/subresource_load_info.mojom b/content/public/common/subresource_load_info.mojom
index 7d2f6b2..4f45ddb9 100644
--- a/content/public/common/subresource_load_info.mojom
+++ b/content/public/common/subresource_load_info.mojom
@@ -29,7 +29,4 @@
   // Bitmask of status info of the SSL certificate.
   // See net/cert/cert_status_flags.h
   uint32 cert_status;
-
-  // True if the response was fetched from the network cache.
-  bool was_cached;
 };
diff --git a/content/public/test/DEPS b/content/public/test/DEPS
index 788418f..01cbc06a 100644
--- a/content/public/test/DEPS
+++ b/content/public/test/DEPS
@@ -23,7 +23,4 @@
     "+third_party/iaccessible2",
     "+ui/base/resource/resource_bundle.h",
   ],
-  "content_browser_test.cc": [
-    "+ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
-  ],
 }
diff --git a/content/public/test/content_browser_test.cc b/content/public/test/content_browser_test.cc
index 1a04368f..8e4bd2f 100644
--- a/content/public/test/content_browser_test.cc
+++ b/content/public/test/content_browser_test.cc
@@ -30,10 +30,6 @@
 #include "ui/base/ime/input_method_initializer.h"
 #endif
 
-#if defined(USE_AURA)
-#include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"  // nogncheck
-#endif
-
 namespace content {
 
 ContentBrowserTest::ContentBrowserTest() {
@@ -85,13 +81,6 @@
                                  subprocess_path);
 #endif
 
-#if defined(USE_AURA)
-  // https://crbug.com/695054: Ignore window activation/deactivation to make
-  // the Chrome-internal focus unaffected by OS events caused by running tests
-  // in parallel.
-  views::DesktopNativeWidgetAura::DisableActivationChangeHandlingForTests();
-#endif
-
   // LinuxInputMethodContextFactory has to be initialized.
 #if !defined(OS_CHROMEOS) && defined(OS_LINUX)
   ui::InitializeInputMethodForTesting();
diff --git a/content/public/test/navigation_simulator.cc b/content/public/test/navigation_simulator.cc
index 298d64b0..206e595 100644
--- a/content/public/test/navigation_simulator.cc
+++ b/content/public/test/navigation_simulator.cc
@@ -674,20 +674,6 @@
   return request_id_;
 }
 
-void NavigationSimulator::SetOnDeferCallback(
-    const base::Closure& on_defer_callback) {
-  CHECK_LT(state_, FINISHED)
-      << "The callback should not be set after the navigation has finished";
-  if (handle_) {
-    handle_->SetOnDeferCallbackForTesting(on_defer_callback);
-    return;
-  }
-
-  // If there is no NavigationHandle for the navigation yet, store the callback
-  // until one has been created.
-  on_defer_callback_ = on_defer_callback;
-}
-
 void NavigationSimulator::DidStartNavigation(
     NavigationHandle* navigation_handle) {
   // Check if this navigation is the one we're simulating.
@@ -717,12 +703,6 @@
           base::Bind(&NavigationSimulator::OnWillProcessResponse,
                      weak_factory_.GetWeakPtr())));
 
-  // Pass the |on_defer_callback_| if it was registered.
-  if (!on_defer_callback_.is_null()) {
-    handle->SetOnDeferCallbackForTesting(on_defer_callback_);
-    on_defer_callback_.Reset();
-  }
-
   PrepareCompleteCallbackOnHandle();
 }
 
diff --git a/content/public/test/navigation_simulator.h b/content/public/test/navigation_simulator.h
index ec4fb53..77e745e 100644
--- a/content/public/test/navigation_simulator.h
+++ b/content/public/test/navigation_simulator.h
@@ -257,23 +257,6 @@
   // callback.
   content::GlobalRequestID GetGlobalRequestID() const;
 
-  // Allows the user of the NavigationSimulator to specify a callback that will
-  // be called if the navigation is deferred by a NavigationThrottle. This is
-  // used for testing deferring NavigationThrottles.
-  //
-  // Example usage:
-  //   void CheckThrottleStateAndResume() {
-  //     // Do some testing here.
-  //     deferring_navigation_throttle->Resume();
-  //   }
-  //   unique_ptr<NavigationSimulator> simulator =
-  //       NavigationSimulator::CreateRendererInitiated(
-  //           original_url, render_frame_host);
-  //   simulator->SetOnDeferCallback(base::Bind(&CheckThrottleStateAndResume));
-  //   simulator->Start();
-  //   simulator->Commit();
-  void SetOnDeferCallback(const base::Closure& on_defer_callback);
-
  private:
   NavigationSimulator(const GURL& original_url,
                       bool browser_initiated,
@@ -381,10 +364,6 @@
   // Closure that is set when WaitForThrottleChecksComplete is called.
   base::Closure throttle_checks_wait_closure_;
 
-  // Temporarily holds a closure that will be called on navigation deferral
-  // until the NavigationHandle for this navigation has been created.
-  base::Closure on_defer_callback_;
-
   base::WeakPtrFactory<NavigationSimulator> weak_factory_;
 };
 
diff --git a/content/renderer/loader/resource_dispatcher.cc b/content/renderer/loader/resource_dispatcher.cc
index 502355e..1cf9992 100644
--- a/content/renderer/loader/resource_dispatcher.cc
+++ b/content/renderer/loader/resource_dispatcher.cc
@@ -162,7 +162,6 @@
       }
     }
     subresource_load_info->cert_status = response_head.cert_status;
-    subresource_load_info->was_cached = response_head.was_cached;
     NotifySubresourceStarted(RenderThreadImpl::DeprecatedGetMainTaskRunner(),
                              request_info->render_frame_id,
                              std::move(subresource_load_info));
diff --git a/content/renderer/loader/resource_dispatcher_unittest.cc b/content/renderer/loader/resource_dispatcher_unittest.cc
index 8312725..5f1a87e6 100644
--- a/content/renderer/loader/resource_dispatcher_unittest.cc
+++ b/content/renderer/loader/resource_dispatcher_unittest.cc
@@ -246,6 +246,7 @@
   // peer at once.
   network::URLLoaderCompletionStatus status;
   status.error_code = net::OK;
+  status.exists_in_cache = false;
   status.encoded_data_length = strlen(kTestPageContents);
   client->OnComplete(status);
 
@@ -291,6 +292,7 @@
   // OnCompletedRequest, but it should not lead to crashes.)
   network::URLLoaderCompletionStatus status;
   status.error_code = net::OK;
+  status.exists_in_cache = false;
   status.encoded_data_length = strlen(kTestPageContents);
   client->OnComplete(status);
 
diff --git a/content/renderer/loader/web_url_loader_impl.cc b/content/renderer/loader/web_url_loader_impl.cc
index fc8d917..414a24f 100644
--- a/content/renderer/loader/web_url_loader_impl.cc
+++ b/content/renderer/loader/web_url_loader_impl.cc
@@ -462,7 +462,6 @@
   enum DeferState {NOT_DEFERRING, SHOULD_DEFER, DEFERRED_DATA};
   DeferState defers_loading_;
   int request_id_;
-  bool response_was_cached_;
 
   scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_;
 };
@@ -542,7 +541,6 @@
               : nullptr),
       defers_loading_(NOT_DEFERRING),
       request_id_(-1),
-      response_was_cached_(false),
       url_loader_factory_(std::move(url_loader_factory)) {
   DCHECK(url_loader_factory_ || !resource_dispatcher);
 }
@@ -879,7 +877,6 @@
     // TODO(yhirano): Support ftp listening and multipart
     return;
   }
-  response_was_cached_ = info.was_cached;
 
   client_->DidReceiveResponse(response);
 
@@ -966,8 +963,8 @@
 
     if (status.error_code != net::OK) {
       const WebURLError::HasCopyInCache has_copy_in_cache =
-          response_was_cached_ ? WebURLError::HasCopyInCache::kTrue
-                               : WebURLError::HasCopyInCache::kFalse;
+          status.exists_in_cache ? WebURLError::HasCopyInCache::kTrue
+                                 : WebURLError::HasCopyInCache::kFalse;
       client_->DidFail(
           status.cors_error_status
               ? WebURLError(*status.cors_error_status, has_copy_in_cache, url_)
diff --git a/content/renderer/media/webrtc/rtc_rtp_sender_unittest.cc b/content/renderer/media/webrtc/rtc_rtp_sender_unittest.cc
index 29659b7..1be22d6 100644
--- a/content/renderer/media/webrtc/rtc_rtp_sender_unittest.cc
+++ b/content/renderer/media/webrtc/rtc_rtp_sender_unittest.cc
@@ -162,7 +162,14 @@
   EXPECT_TRUE(sender_->Track().IsNull());
 }
 
-TEST_F(RTCRtpSenderTest, ReplaceTrackCanFail) {
+// This test is flaky on Android and Linux.
+// See crbug.com/800465 for detail.
+#if defined(OS_ANDROID) || defined(OS_LINUX)
+#define MAYBE_ReplaceTrackCanFail DISABLED_ReplaceTrackCanFail
+#else
+#define MAYBE_ReplaceTrackCanFail ReplaceTrackCanFail
+#endif
+TEST_F(RTCRtpSenderTest, MAYBE_ReplaceTrackCanFail) {
   auto web_track = CreateWebTrack("track_id");
   sender_ = CreateSender(web_track);
   ASSERT_FALSE(sender_->Track().IsNull());
@@ -177,7 +184,16 @@
   EXPECT_EQ(web_track.UniqueId(), sender_->Track().UniqueId());
 }
 
-TEST_F(RTCRtpSenderTest, ReplaceTrackIsNotSetSynchronously) {
+// This test is flaky on Android and Linux.
+// See crbug.com/800465 for detail.
+#if defined(OS_ANDROID) || defined(OS_LINUX)
+#define MAYBE_ReplaceTrackIsNotSetSynchronously \
+  DISABLED_ReplaceTrackIsNotSetSynchronously
+#else
+#define MAYBE_ReplaceTrackIsNotSetSynchronously \
+  ReplaceTrackIsNotSetSynchronously
+#endif
+TEST_F(RTCRtpSenderTest, MAYBE_ReplaceTrackIsNotSetSynchronously) {
   auto web_track1 = CreateWebTrack("track1");
   sender_ = CreateSender(web_track1);
 
diff --git a/content/shell/android/browsertests_apk/src/org/chromium/content_browsertests_apk/ContentBrowserTestsApplication.java b/content/shell/android/browsertests_apk/src/org/chromium/content_browsertests_apk/ContentBrowserTestsApplication.java
index 752627d9..7036686a 100644
--- a/content/shell/android/browsertests_apk/src/org/chromium/content_browsertests_apk/ContentBrowserTestsApplication.java
+++ b/content/shell/android/browsertests_apk/src/org/chromium/content_browsertests_apk/ContentBrowserTestsApplication.java
@@ -22,7 +22,7 @@
     @Override
     protected void attachBaseContext(Context base) {
         super.attachBaseContext(base);
-        if (BuildConfig.isMultidexEnabled()) {
+        if (BuildConfig.IS_MULTIDEX_ENABLED) {
             ChromiumMultiDexInstaller.install(this);
         }
         ContextUtils.initApplicationContext(this);
@@ -34,4 +34,4 @@
         PathUtils.setPrivateDataDirectorySuffix(PRIVATE_DATA_DIRECTORY_SUFFIX);
         ApplicationStatus.initialize(this);
     }
-}
\ No newline at end of file
+}
diff --git a/content/shell/android/linker_test_apk/src/org/chromium/chromium_linker_test_apk/ChromiumLinkerTestApplication.java b/content/shell/android/linker_test_apk/src/org/chromium/chromium_linker_test_apk/ChromiumLinkerTestApplication.java
index bf51d3e2..d6facb7 100644
--- a/content/shell/android/linker_test_apk/src/org/chromium/chromium_linker_test_apk/ChromiumLinkerTestApplication.java
+++ b/content/shell/android/linker_test_apk/src/org/chromium/chromium_linker_test_apk/ChromiumLinkerTestApplication.java
@@ -21,7 +21,7 @@
     @Override
     protected void attachBaseContext(Context base) {
         super.attachBaseContext(base);
-        if (BuildConfig.isMultidexEnabled()) {
+        if (BuildConfig.IS_MULTIDEX_ENABLED) {
             ChromiumMultiDexInstaller.install(this);
         }
         ContextUtils.initApplicationContext(this);
diff --git a/content/shell/android/shell_apk/src/org/chromium/content_shell_apk/ContentShellApplication.java b/content/shell/android/shell_apk/src/org/chromium/content_shell_apk/ContentShellApplication.java
index b41c605..54db34b 100644
--- a/content/shell/android/shell_apk/src/org/chromium/content_shell_apk/ContentShellApplication.java
+++ b/content/shell/android/shell_apk/src/org/chromium/content_shell_apk/ContentShellApplication.java
@@ -25,7 +25,7 @@
     @Override
     protected void attachBaseContext(Context base) {
         super.attachBaseContext(base);
-        if (BuildConfig.isMultidexEnabled()) {
+        if (BuildConfig.IS_MULTIDEX_ENABLED) {
             ChromiumMultiDexInstaller.install(this);
         }
         ContextUtils.initApplicationContext(this);
diff --git a/content/shell/app/blink_test_platform_support_linux.cc b/content/shell/app/blink_test_platform_support_linux.cc
index 8317845..19d4c71 100644
--- a/content/shell/app/blink_test_platform_support_linux.cc
+++ b/content/shell/app/blink_test_platform_support_linux.cc
@@ -11,7 +11,7 @@
 #include "base/logging.h"
 #include "base/macros.h"
 #include "base/path_service.h"
-#include "ui/gfx/test/fontconfig_util_linux.h"
+#include "base/test/fontconfig_util_linux.h"
 
 namespace content {
 
@@ -30,29 +30,12 @@
 }
 
 bool BlinkTestPlatformInitialize() {
-  gfx::SetUpFontconfig();
+  base::SetUpFontconfig();
 
   base::FilePath base_path;
   PathService::Get(base::DIR_MODULE, &base_path);
-  if (!gfx::LoadConfigFileIntoFontconfig(
-          base_path.Append(FILE_PATH_LITERAL("fonts.conf"))))
-    return false;
-
-  for (size_t i = 0; i < gfx::kNumSystemFontsForFontconfig; ++i) {
-    if (!gfx::LoadFontIntoFontconfig(
-            base::FilePath(gfx::kSystemFontsForFontconfig[i]))) {
-      return false;
-    }
-  }
-
-  for (size_t i = 0; i < gfx::kNumCloudStorageSyncedFonts; ++i) {
-    if (!gfx::LoadCloudStorageSyncedFontIntoFontConfig(
-            gfx::kCloudStorageSyncedFonts[i]))
-      return false;
-  }
-
   for (size_t i = 0; i < arraysize(kLocalFonts); ++i) {
-    if (!gfx::LoadFontIntoFontconfig(base_path.Append(kLocalFonts[i])))
+    if (!base::LoadFontIntoFontconfig(base_path.Append(kLocalFonts[i])))
       return false;
   }
 
diff --git a/content/shell/test_runner/BUILD.gn b/content/shell/test_runner/BUILD.gn
index bbad433..6456890 100644
--- a/content/shell/test_runner/BUILD.gn
+++ b/content/shell/test_runner/BUILD.gn
@@ -147,12 +147,11 @@
 }
 if (use_x11) {
   copy("copy_x11_fonts") {
-    # TODO(sergeyu): Move these fonts to third_party/content_shell_fonts .
+    # TODO(sergeyu): Move these fonts to third_party/test_fonts .
     visibility = [ ":*" ]
     sources = [
       "//third_party/gardiner_mod/GardinerModBug.ttf",
       "//third_party/gardiner_mod/GardinerModCat.ttf",
-      "resources/fonts/fonts.conf",
     ]
     outputs = [
       "$root_out_dir/{{source_file_part}}",
@@ -167,7 +166,7 @@
       "resources/fonts/android_main_fonts.xml",
     ]
     outputs = [
-      "$root_out_dir/content_shell_test_fonts/{{source_file_part}}",
+      "$root_out_dir/test_fonts/{{source_file_part}}",
     ]
   }
 }
@@ -205,7 +204,7 @@
     data_deps += [ ":copy_android_fonts_config" ]
   }
   if (is_android || is_linux || is_fuchsia) {
-    deps += [ "//third_party/content_shell_fonts" ]
-    data_deps += [ "//third_party/content_shell_fonts" ]
+    deps += [ "//third_party/test_fonts" ]
+    data_deps += [ "//third_party/test_fonts" ]
   }
 }
diff --git a/content/shell/test_runner/resources/fonts/fonts.conf b/content/shell/test_runner/resources/fonts/fonts.conf
deleted file mode 100644
index 7ed6e12..0000000
--- a/content/shell/test_runner/resources/fonts/fonts.conf
+++ /dev/null
@@ -1,277 +0,0 @@
-<?xml version="1.0"?>
-<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
-<!-- /etc/fonts/fonts.conf file to configure system font access -->
-<fontconfig>
-  <match target="font">
-    <edit name="embeddedbitmap" mode="assign"><bool>false</bool></edit>
-  </match>
-
-  <match target="pattern">
-    <test qual="any" name="family">
-      <string>Times</string>
-    </test>
-    <edit name="family" mode="assign">
-      <string>Times New Roman</string>
-    </edit>
-  </match>
-
-  <match target="pattern">
-    <test qual="any" name="family">
-      <string>sans</string>
-    </test>
-    <edit name="family" mode="assign">
-      <string>Arial</string>
-    </edit>
-  </match>
-
-  <match target="pattern">
-    <test qual="any" name="family">
-      <string>sans serif</string>
-    </test>
-    <edit name="family" mode="assign">
-      <string>Arial</string>
-    </edit>
-  </match>
-
-  <!-- Some layout tests specify Helvetica as a family and we need to make sure
-       that we don't fallback to Times New Roman for them -->
-  <match target="pattern">
-    <test qual="any" name="family">
-      <string>Helvetica</string>
-    </test>
-    <edit name="family" mode="assign">
-      <string>Arial</string>
-    </edit>
-  </match>
-
-  <match target="pattern">
-    <test qual="any" name="family">
-      <string>sans-serif</string>
-    </test>
-    <edit name="family" mode="assign">
-      <string>Arial</string>
-    </edit>
-  </match>
-
-  <match target="pattern">
-    <test qual="any" name="family">
-      <string>serif</string>
-    </test>
-    <edit name="family" mode="assign">
-      <string>Times New Roman</string>
-    </edit>
-  </match>
-
-  <match target="pattern">
-    <test qual="any" name="family">
-      <string>mono</string>
-    </test>
-    <edit name="family" mode="assign">
-      <string>Courier New</string>
-    </edit>
-  </match>
-
-  <match target="pattern">
-    <test qual="any" name="family">
-      <string>monospace</string>
-    </test>
-    <edit name="family" mode="assign">
-      <string>Courier New</string>
-    </edit>
-  </match>
-
-  <match target="pattern">
-    <test qual="any" name="family">
-      <string>Courier</string>
-    </test>
-    <edit name="family" mode="assign">
-      <string>Courier New</string>
-    </edit>
-  </match>
-
-  <match target="pattern">
-    <test qual="any" name="family">
-      <string>cursive</string>
-    </test>
-    <edit name="family" mode="assign">
-      <string>Comic Sans MS</string>
-    </edit>
-  </match>
-
-  <match target="pattern">
-    <test qual="any" name="family">
-      <string>fantasy</string>
-    </test>
-    <edit name="family" mode="assign">
-      <string>Impact</string>
-    </edit>
-  </match>
-
-  <match target="pattern">
-    <test qual="any" name="family">
-      <string>Monaco</string>
-    </test>
-    <edit name="family" mode="assign">
-      <string>Times New Roman</string>
-    </edit>
-  </match>
-
-  <match target="pattern">
-    <test name="family" compare="eq">
-      <string>NonAntiAliasedSans</string>
-    </test>
-    <edit name="family" mode="assign">
-      <string>Arial</string>
-    </edit>
-    <edit name="antialias" mode="assign">
-      <bool>false</bool>
-    </edit>
-  </match>
-
-  <match target="pattern">
-    <test name="family" compare="eq">
-      <string>SlightHintedGeorgia</string>
-    </test>
-    <edit name="family" mode="assign">
-      <string>Georgia</string>
-    </edit>
-    <edit name="hintstyle" mode="assign">
-      <const>hintslight</const>
-    </edit>
-  </match>
-
-  <match target="pattern">
-    <test name="family" compare="eq">
-      <string>NonHintedSans</string>
-    </test>
-    <edit name="family" mode="assign">
-      <string>Verdana</string>
-    </edit>
-    <!-- These deliberately contradict each other. The 'hinting' preference
-         should take priority -->
-    <edit name="hintstyle" mode="assign">
-      <const>hintfull</const>
-    </edit>
-   <edit name="hinting" mode="assign">
-      <bool>false</bool>
-    </edit>
-  </match>
-
-  <match target="pattern">
-    <test name="family" compare="eq">
-      <string>AutohintedSerif</string>
-    </test>
-    <edit name="family" mode="assign">
-      <string>Arial</string>
-    </edit>
-    <edit name="autohint" mode="assign">
-      <bool>true</bool>
-    </edit>
-    <edit name="hintstyle" mode="assign">
-      <const>hintmedium</const>
-    </edit>
-  </match>
-
-  <match target="pattern">
-    <test name="family" compare="eq">
-      <string>HintedSerif</string>
-    </test>
-    <edit name="family" mode="assign">
-      <string>Arial</string>
-    </edit>
-    <edit name="autohint" mode="assign">
-      <bool>false</bool>
-    </edit>
-    <edit name="hintstyle" mode="assign">
-      <const>hintmedium</const>
-    </edit>
-  </match>
-
-  <match target="pattern">
-    <test name="family" compare="eq">
-      <string>FullAndAutoHintedSerif</string>
-    </test>
-    <edit name="family" mode="assign">
-      <string>Arial</string>
-    </edit>
-    <edit name="autohint" mode="assign">
-      <bool>true</bool>
-    </edit>
-    <edit name="hintstyle" mode="assign">
-      <const>hintfull</const>
-    </edit>
-  </match>
-
-  <match target="pattern">
-    <test name="family" compare="eq">
-      <string>SubpixelEnabledArial</string>
-    </test>
-    <edit name="family" mode="assign">
-      <string>Arial</string>
-    </edit>
-    <edit name="rgba" mode="assign">
-      <const>rgb</const>
-    </edit>
-  </match>
-
-  <match target="pattern">
-    <test name="family" compare="eq">
-      <string>SubpixelDisabledArial</string>
-    </test>
-    <edit name="family" mode="assign">
-      <string>Arial</string>
-    </edit>
-    <edit name="rgba" mode="assign">
-      <const>none</const>
-    </edit>
-  </match>
-
-  <match target="pattern">
-    <!-- FontConfig doesn't currently provide a well-defined way to turn on
-         subpixel positioning.  This is just an arbitrary pattern to use after
-         turning subpixel positioning on globally to ensure that we don't have
-         issues with our style getting cached for other tests. -->
-    <test name="family" compare="eq">
-      <string>SubpixelPositioning</string>
-    </test>
-    <edit name="family" mode="assign">
-      <string>Times New Roman</string>
-    </edit>
-  </match>
-
-  <match target="pattern">
-    <!-- See comments above -->
-    <test name="family" compare="eq">
-      <string>SubpixelPositioningAhem</string>
-    </test>
-    <edit name="family" mode="assign">
-      <string>ahem</string>
-    </edit>
-  </match>
-
-  <!-- When we encounter a character that the current font doesn't
-       support, gfx::GetFallbackFontForChar() returns the first font
-       that does have a glyph for the character. The list of fonts is
-       sorted by a pattern that includes the current locale, but doesn't
-       include a font family (which means that the fallback font depends
-       on the locale but not on the current font).
-
-       DejaVu Sans is commonly the only font that supports some
-       characters, such as "⇧", and even when other candidates are
-       available, DejaVu Sans is commonly first among them, because of
-       the way Fontconfig is ordinarily configured. For example, the
-       configuration in the Fonconfig source lists DejaVu Sans under the
-       sans-serif generic family, and appends sans-serif to patterns
-       that don't already include a generic family (such as the pattern
-       in gfx::GetFallbackFontForChar()).
-
-       To get the same fallback font in the layout tests, we could
-       duplicate this configuration here, or more directly, simply
-       append DejaVu Sans to all patterns. -->
-  <match target="pattern">
-    <edit name="family" mode="append_last">
-      <string>DejaVu Sans</string>
-    </edit>
-  </match>
-
-</fontconfig>
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index 3c319a3..fac859d 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -538,10 +538,6 @@
     deps += [ "//content/public/browser" ]
   }
 
-  if (use_aura) {
-    deps += [ "//ui/views" ]
-  }
-
   configs += [ "//v8:external_startup_data" ]
 }
 
@@ -1532,6 +1528,7 @@
     "../common/input/touch_event_stream_validator_unittest.cc",
     "../common/inter_process_time_ticks_converter_unittest.cc",
     "../common/mac/attributed_string_coder_unittest.mm",
+    "../common/manifest_share_target_util_unittest.cc",
     "../common/manifest_util_unittest.cc",
     "../common/media/media_devices_unittest.cc",
     "../common/notifications/notification_struct_traits_unittest.cc",
diff --git a/content/test/data/accessibility/html/ins.html b/content/test/data/accessibility/html/ins.html
index 6f6da3c..ea96fa9 100644
--- a/content/test/data/accessibility/html/ins.html
+++ b/content/test/data/accessibility/html/ins.html
@@ -1,5 +1,11 @@
 <!DOCTYPE html>
 <html>
+<head>
+<style>
+  /* Make the text small so that it doesn't line-wrap. */
+  p { font-size: 8px; }
+</style>
+</head>
 <body>
 
 <p>My favorite browser is <del>ABC</del> <ins>Chrome</ins>!</p>
diff --git a/content/test/data/cross_site_iframe_factory.html b/content/test/data/cross_site_iframe_factory.html
index 9d09bc3..1472a5e 100644
--- a/content/test/data/cross_site_iframe_factory.html
+++ b/content/test/data/cross_site_iframe_factory.html
@@ -47,7 +47,7 @@
 <title>Cross-site iframe factory</title>
 <style>
 body {
-  font-family: Sans-Serif;
+  font-family: "DejaVu Sans", Sans-Serif;
   text-align: center;
 }
 iframe {
diff --git a/content/test/data/page_with_cached_subresource.html b/content/test/data/page_with_cached_subresource.html
deleted file mode 100644
index be5fc2d..0000000
--- a/content/test/data/page_with_cached_subresource.html
+++ /dev/null
@@ -1,6 +0,0 @@
-<html>
-<head></head>
-<body>
-  <img src="cachetime"/>
-</body>
-</html>
diff --git a/device/fido/BUILD.gn b/device/fido/BUILD.gn
index 4e9d7fc..41e1741 100644
--- a/device/fido/BUILD.gn
+++ b/device/fido/BUILD.gn
@@ -35,6 +35,8 @@
     "ec_public_key.h",
     "fido_attestation_statement.cc",
     "fido_attestation_statement.h",
+    "fido_ble_uuids.cc",
+    "fido_ble_uuids.h",
     "fido_constants.cc",
     "fido_constants.h",
     "fido_hid_message.cc",
@@ -67,9 +69,6 @@
     "u2f_ble_frames.h",
     "u2f_ble_transaction.cc",
     "u2f_ble_transaction.h",
-    "u2f_ble_uuids.cc",
-    "u2f_ble_uuids.h",
-    "u2f_command_type.h",
     "u2f_device.cc",
     "u2f_device.h",
     "u2f_discovery.cc",
diff --git a/device/fido/fido_ble_uuids.cc b/device/fido/fido_ble_uuids.cc
new file mode 100644
index 0000000..8fe32d09
--- /dev/null
+++ b/device/fido/fido_ble_uuids.cc
@@ -0,0 +1,18 @@
+// 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 "device/fido/fido_ble_uuids.h"
+
+namespace device {
+
+const char kFidoServiceUUID[] = "0000fffd-0000-1000-8000-00805f9b34fb";
+const char kFidoControlPointUUID[] = "f1d0fff1-deaa-ecee-b42f-c9ba7ed623bb";
+const char kFidoStatusUUID[] = "f1d0fff2-deaa-ecee-b42f-c9ba7ed623bb";
+const char kFidoControlPointLengthUUID[] =
+    "f1d0fff3-deaa-ecee-b42f-c9ba7ed623bb";
+const char kFidoServiceRevisionUUID[] = "00002a28-0000-1000-8000-00805f9b34fb";
+const char kFidoServiceRevisionBitfieldUUID[] =
+    "f1d0fff4-deaa-ecee-b42f-c9ba7ed623bb";
+
+}  // namespace device
diff --git a/device/fido/fido_ble_uuids.h b/device/fido/fido_ble_uuids.h
new file mode 100644
index 0000000..61c4a55
--- /dev/null
+++ b/device/fido/fido_ble_uuids.h
@@ -0,0 +1,28 @@
+// 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 DEVICE_FIDO_FIDO_BLE_UUIDS_H_
+#define DEVICE_FIDO_FIDO_BLE_UUIDS_H_
+
+#include "base/component_export.h"
+
+namespace device {
+
+// FIDO GATT Service's UUIDs as defined by the standard:
+// https://fidoalliance.org/specs/fido-v2.0-rd-20161004/fido-client-to-authenticator-protocol-v2.0-rd-20161004.html#gatt-service-description
+//
+// For details on how the short UUIDs for FIDO Service (0xFFFD) and FIDO Service
+// Revision (0x2A28) were converted to the long canonical ones, see
+// https://www.bluetooth.com/specifications/assigned-numbers/service-discovery
+COMPONENT_EXPORT(DEVICE_FIDO) extern const char kFidoServiceUUID[];
+COMPONENT_EXPORT(DEVICE_FIDO) extern const char kFidoControlPointUUID[];
+COMPONENT_EXPORT(DEVICE_FIDO) extern const char kFidoStatusUUID[];
+COMPONENT_EXPORT(DEVICE_FIDO) extern const char kFidoControlPointLengthUUID[];
+COMPONENT_EXPORT(DEVICE_FIDO) extern const char kFidoServiceRevisionUUID[];
+COMPONENT_EXPORT(DEVICE_FIDO)
+extern const char kFidoServiceRevisionBitfieldUUID[];
+
+}  // namespace device
+
+#endif  // DEVICE_FIDO_FIDO_BLE_UUIDS_H_
diff --git a/device/fido/fido_constants.cc b/device/fido/fido_constants.cc
index 538134d..c48cffe 100644
--- a/device/fido/fido_constants.cc
+++ b/device/fido/fido_constants.cc
@@ -43,4 +43,9 @@
 
 const std::array<uint8_t, 2> kLegacyVersionSuffix = {0x00, 0x00};
 
+const std::array<uint8_t, 6> kU2fVersionResponse = {'U', '2', 'F',
+                                                    '_', 'V', '2'};
+
+const base::TimeDelta kDeviceTimeout = base::TimeDelta::FromSeconds(3);
+
 }  // namespace device
diff --git a/device/fido/fido_constants.h b/device/fido/fido_constants.h
index 9fcdfab5..2b82355 100644
--- a/device/fido/fido_constants.h
+++ b/device/fido/fido_constants.h
@@ -11,9 +11,16 @@
 #include <vector>
 
 #include "base/component_export.h"
+#include "base/time/time.h"
 
 namespace device {
 
+enum class ProtocolVersion {
+  kCtap,
+  kU2f,
+  kUnknown,
+};
+
 // CTAP protocol device response code, as specified in
 // https://fidoalliance.org/specs/fido-v2.0-rd-20170927/fido-client-to-authenticator-protocol-v2.0-rd-20170927.html#authenticator-api
 enum class CtapDeviceResponseCode : uint8_t {
@@ -126,30 +133,37 @@
 
 // Commands supported by CTAPHID device as specified in
 // https://fidoalliance.org/specs/fido-v2.0-rd-20170927/fido-client-to-authenticator-protocol-v2.0-rd-20170927.html#ctaphid-commands
-enum class CtapHidDeviceCommand : uint8_t {
-  kCtapHidMsg = 0x03,
-  kCtapHidCBOR = 0x10,
-  kCtapHidInit = 0x06,
-  kCtapHidPing = 0x01,
-  kCtapHidCancel = 0x11,
-  kCtapHidError = 0x3F,
-  kCtapHidKeepAlive = 0x3B,
-  kCtapHidWink = 0x08,
-  kCtapHidLock = 0x04,
+enum class FidoHidDeviceCommand : uint8_t {
+  kMsg = 0x03,
+  kCbor = 0x10,
+  kInit = 0x06,
+  kPing = 0x01,
+  kCancel = 0x11,
+  kError = 0x3F,
+  kKeepAlive = 0x3B,
+  kWink = 0x08,
+  kLock = 0x04,
 };
 
-constexpr std::array<CtapHidDeviceCommand, 9> GetCtapHidDeviceCommandList() {
-  return {CtapHidDeviceCommand::kCtapHidMsg,
-          CtapHidDeviceCommand::kCtapHidCBOR,
-          CtapHidDeviceCommand::kCtapHidInit,
-          CtapHidDeviceCommand::kCtapHidPing,
-          CtapHidDeviceCommand::kCtapHidCancel,
-          CtapHidDeviceCommand::kCtapHidError,
-          CtapHidDeviceCommand::kCtapHidKeepAlive,
-          CtapHidDeviceCommand::kCtapHidWink,
-          CtapHidDeviceCommand::kCtapHidLock};
+constexpr std::array<FidoHidDeviceCommand, 9> GetFidoHidDeviceCommandList() {
+  return {FidoHidDeviceCommand::kMsg,       FidoHidDeviceCommand::kCbor,
+          FidoHidDeviceCommand::kInit,      FidoHidDeviceCommand::kPing,
+          FidoHidDeviceCommand::kCancel,    FidoHidDeviceCommand::kError,
+          FidoHidDeviceCommand::kKeepAlive, FidoHidDeviceCommand::kWink,
+          FidoHidDeviceCommand::kLock};
 }
 
+// BLE device command as specified in
+//  https://fidoalliance.org/specs/fido-v2.0-rd-20170927/fido-client-to-authenticator-protocol-v2.0-rd-20170927.html#command-status-and-error-constants
+// U2F BLE device does not support cancel command.
+enum class FidoBleDeviceCommand : uint8_t {
+  kPing = 0x81,
+  kKeepAlive = 0x82,
+  kMsg = 0x83,
+  kCancel = 0xBE,
+  kError = 0xBF,
+};
+
 // Authenticator API commands supported by CTAP devices, as specified in
 // https://fidoalliance.org/specs/fido-v2.0-rd-20170927/fido-client-to-authenticator-protocol-v2.0-rd-20170927.html#authenticator-api
 enum class CtapRequestCommand : uint8_t {
@@ -225,6 +239,14 @@
 COMPONENT_EXPORT(DEVICE_FIDO)
 extern const std::array<uint8_t, 2> kLegacyVersionSuffix;
 
+// Expected response data for version request from U2F device.
+// https://fidoalliance.org/specs/fido-u2f-v1.2-ps-20170411/fido-u2f-raw-message-formats-v1.2-ps-20170411.html#getversion-request-and-response---u2f_version
+COMPONENT_EXPORT(DEVICE_FIDO)
+extern const std::array<uint8_t, 6> kU2fVersionResponse;
+
+// Maximum wait time before client error outs on device.
+COMPONENT_EXPORT(DEVICE_FIDO) extern const base::TimeDelta kDeviceTimeout;
+
 }  // namespace device
 
 #endif  // DEVICE_FIDO_FIDO_CONSTANTS_H_
diff --git a/device/fido/fido_hid_message.cc b/device/fido/fido_hid_message.cc
index 25db86c..e2f2581 100644
--- a/device/fido/fido_hid_message.cc
+++ b/device/fido/fido_hid_message.cc
@@ -16,39 +16,39 @@
 // static
 std::unique_ptr<FidoHidMessage> FidoHidMessage::Create(
     uint32_t channel_id,
-    CtapHidDeviceCommand type,
+    FidoHidDeviceCommand type,
     base::span<const uint8_t> data) {
   if (data.size() > kHidMaxMessageSize)
     return nullptr;
 
   switch (type) {
-    case CtapHidDeviceCommand::kCtapHidPing:
+    case FidoHidDeviceCommand::kPing:
       break;
-    case CtapHidDeviceCommand::kCtapHidMsg:
-    case CtapHidDeviceCommand::kCtapHidCBOR: {
+    case FidoHidDeviceCommand::kMsg:
+    case FidoHidDeviceCommand::kCbor: {
       if (data.empty())
         return nullptr;
       break;
     }
 
-    case CtapHidDeviceCommand::kCtapHidCancel:
-    case CtapHidDeviceCommand::kCtapHidWink: {
+    case FidoHidDeviceCommand::kCancel:
+    case FidoHidDeviceCommand::kWink: {
       if (!data.empty())
         return nullptr;
       break;
     }
-    case CtapHidDeviceCommand::kCtapHidLock: {
+    case FidoHidDeviceCommand::kLock: {
       if (data.size() != 1 || data[0] > kHidMaxLockSeconds)
         return nullptr;
       break;
     }
-    case CtapHidDeviceCommand::kCtapHidInit: {
+    case FidoHidDeviceCommand::kInit: {
       if (data.size() != 8)
         return nullptr;
       break;
     }
-    case CtapHidDeviceCommand::kCtapHidKeepAlive:
-    case CtapHidDeviceCommand::kCtapHidError:
+    case FidoHidDeviceCommand::kKeepAlive:
+    case FidoHidDeviceCommand::kError:
       if (data.size() != 1)
         return nullptr;
   }
@@ -124,7 +124,7 @@
 }
 
 FidoHidMessage::FidoHidMessage(uint32_t channel_id,
-                               CtapHidDeviceCommand type,
+                               FidoHidDeviceCommand type,
                                base::span<const uint8_t> data)
     : channel_id_(channel_id) {
   uint8_t sequence = 0;
diff --git a/device/fido/fido_hid_message.h b/device/fido/fido_hid_message.h
index 4e431cf..529aa00 100644
--- a/device/fido/fido_hid_message.h
+++ b/device/fido/fido_hid_message.h
@@ -28,7 +28,7 @@
  public:
   // Static functions to create CTAP/U2F HID commands.
   static std::unique_ptr<FidoHidMessage> Create(uint32_t channel_id,
-                                                CtapHidDeviceCommand cmd,
+                                                FidoHidDeviceCommand cmd,
                                                 base::span<const uint8_t> data);
 
   // Reconstruct a message from serialized message data.
@@ -47,7 +47,7 @@
 
   size_t NumPackets() const;
   uint32_t channel_id() const { return channel_id_; }
-  CtapHidDeviceCommand cmd() const { return cmd_; }
+  FidoHidDeviceCommand cmd() const { return cmd_; }
   const base::circular_deque<std::unique_ptr<FidoHidPacket>>&
   GetPacketsForTesting() const {
     return packets_;
@@ -55,12 +55,12 @@
 
  private:
   FidoHidMessage(uint32_t channel_id,
-                 CtapHidDeviceCommand type,
+                 FidoHidDeviceCommand type,
                  base::span<const uint8_t> data);
   FidoHidMessage(std::unique_ptr<FidoHidInitPacket> init_packet,
                  size_t remaining_size);
   uint32_t channel_id_ = kHidBroadcastChannel;
-  CtapHidDeviceCommand cmd_ = CtapHidDeviceCommand::kCtapHidMsg;
+  FidoHidDeviceCommand cmd_ = FidoHidDeviceCommand::kMsg;
   base::circular_deque<std::unique_ptr<FidoHidPacket>> packets_;
   size_t remaining_size_ = 0;
 
diff --git a/device/fido/fido_hid_message_unittest.cc b/device/fido/fido_hid_message_unittest.cc
index b47c23c..cc7ab4f 100644
--- a/device/fido/fido_hid_message_unittest.cc
+++ b/device/fido/fido_hid_message_unittest.cc
@@ -19,7 +19,7 @@
   std::vector<uint8_t> data;
 
   auto init_packet = std::make_unique<FidoHidInitPacket>(
-      channel_id, CtapHidDeviceCommand::kCtapHidInit, data, data.size());
+      channel_id, FidoHidDeviceCommand::kInit, data, data.size());
   EXPECT_EQ(64u, init_packet->GetSerializedData().size());
 
   auto continuation_packet =
@@ -40,7 +40,7 @@
 TEST(FidoHidMessageTest, TestPacketData) {
   uint32_t channel_id = 0xF5060708;
   std::vector<uint8_t> data{10, 11};
-  CtapHidDeviceCommand cmd = CtapHidDeviceCommand::kCtapHidWink;
+  FidoHidDeviceCommand cmd = FidoHidDeviceCommand::kWink;
   auto init_packet =
       std::make_unique<FidoHidInitPacket>(channel_id, cmd, data, data.size());
   size_t index = 0;
@@ -63,7 +63,7 @@
 TEST(FidoHidMessageTest, TestPacketConstructors) {
   uint32_t channel_id = 0x05060708;
   std::vector<uint8_t> data{10, 11};
-  CtapHidDeviceCommand cmd = CtapHidDeviceCommand::kCtapHidWink;
+  FidoHidDeviceCommand cmd = FidoHidDeviceCommand::kWink;
   auto orig_packet =
       std::make_unique<FidoHidInitPacket>(channel_id, cmd, data, data.size());
 
@@ -96,8 +96,8 @@
   for (size_t i = 0; i < kHidMaxMessageSize; ++i)
     data.push_back(static_cast<uint8_t>(i % 0xff));
 
-  auto orig_msg = FidoHidMessage::Create(
-      channel_id, CtapHidDeviceCommand::kCtapHidMsg, data);
+  auto orig_msg =
+      FidoHidMessage::Create(channel_id, FidoHidDeviceCommand::kMsg, data);
   ASSERT_TRUE(orig_msg);
 
   const auto& original_msg_packets = orig_msg->GetPacketsForTesting();
@@ -137,20 +137,20 @@
 TEST(FidoHidMessageTest, TestMessagePartitoning) {
   uint32_t channel_id = 0x01010203;
   std::vector<uint8_t> data(kHidInitPacketDataSize + 1);
-  auto two_packet_message = FidoHidMessage::Create(
-      channel_id, CtapHidDeviceCommand::kCtapHidPing, data);
+  auto two_packet_message =
+      FidoHidMessage::Create(channel_id, FidoHidDeviceCommand::kPing, data);
   ASSERT_TRUE(two_packet_message);
   EXPECT_EQ(2U, two_packet_message->NumPackets());
 
   data.resize(kHidInitPacketDataSize);
-  auto one_packet_message = FidoHidMessage::Create(
-      channel_id, CtapHidDeviceCommand::kCtapHidPing, data);
+  auto one_packet_message =
+      FidoHidMessage::Create(channel_id, FidoHidDeviceCommand::kPing, data);
   ASSERT_TRUE(one_packet_message);
   EXPECT_EQ(1U, one_packet_message->NumPackets());
 
   data.resize(kHidInitPacketDataSize + kHidContinuationPacketDataSize + 1);
-  auto three_packet_message = FidoHidMessage::Create(
-      channel_id, CtapHidDeviceCommand::kCtapHidPing, data);
+  auto three_packet_message =
+      FidoHidMessage::Create(channel_id, FidoHidDeviceCommand::kPing, data);
   ASSERT_TRUE(three_packet_message);
   EXPECT_EQ(3U, three_packet_message->NumPackets());
 }
@@ -158,16 +158,16 @@
 TEST(FidoHidMessageTest, TestMaxSize) {
   uint32_t channel_id = 0x00010203;
   std::vector<uint8_t> data(kHidMaxMessageSize + 1);
-  auto oversize_message = FidoHidMessage::Create(
-      channel_id, CtapHidDeviceCommand::kCtapHidPing, data);
+  auto oversize_message =
+      FidoHidMessage::Create(channel_id, FidoHidDeviceCommand::kPing, data);
   EXPECT_EQ(nullptr, oversize_message);
 }
 
 TEST(FidoHidMessageTest, TestDeconstruct) {
   uint32_t channel_id = 0x0A0B0C0D;
   std::vector<uint8_t> data(kHidMaxMessageSize, 0x7F);
-  auto filled_message = FidoHidMessage::Create(
-      channel_id, CtapHidDeviceCommand::kCtapHidPing, data);
+  auto filled_message =
+      FidoHidMessage::Create(channel_id, FidoHidDeviceCommand::kPing, data);
   ASSERT_TRUE(filled_message);
   EXPECT_THAT(data,
               ::testing::ContainerEq(filled_message->GetMessagePayload()));
@@ -177,8 +177,8 @@
   uint32_t channel_id = 0x0A0B0C0D;
   std::vector<uint8_t> data(kHidMaxMessageSize);
 
-  auto orig_message = FidoHidMessage::Create(
-      channel_id, CtapHidDeviceCommand::kCtapHidPing, data);
+  auto orig_message =
+      FidoHidMessage::Create(channel_id, FidoHidDeviceCommand::kPing, data);
   ASSERT_TRUE(orig_message);
 
   base::circular_deque<std::vector<uint8_t>> orig_list;
diff --git a/device/fido/fido_hid_packet.cc b/device/fido/fido_hid_packet.cc
index 82063ff..10a1cebb 100644
--- a/device/fido/fido_hid_packet.cc
+++ b/device/fido/fido_hid_packet.cc
@@ -33,8 +33,8 @@
   channel_id |= (serialized[index++] & 0xff) << 8;
   channel_id |= serialized[index++] & 0xff;
 
-  auto command = static_cast<CtapHidDeviceCommand>(serialized[index++] & 0x7f);
-  if (!base::ContainsValue(GetCtapHidDeviceCommandList(), command))
+  auto command = static_cast<FidoHidDeviceCommand>(serialized[index++] & 0x7f);
+  if (!base::ContainsValue(GetFidoHidDeviceCommandList(), command))
     return nullptr;
 
   uint16_t payload_size = serialized[index++] << 8;
@@ -62,7 +62,7 @@
 // 6      1       Low order packet payload size
 // 7      (s-7)   Payload data
 FidoHidInitPacket::FidoHidInitPacket(uint32_t channel_id,
-                                     CtapHidDeviceCommand cmd,
+                                     FidoHidDeviceCommand cmd,
                                      std::vector<uint8_t> data,
                                      uint16_t payload_length)
     : FidoHidPacket(std::move(data), channel_id),
diff --git a/device/fido/fido_hid_packet.h b/device/fido/fido_hid_packet.h
index 4a24865..128f1ed 100644
--- a/device/fido/fido_hid_packet.h
+++ b/device/fido/fido_hid_packet.h
@@ -62,17 +62,17 @@
       size_t* remaining_size);
 
   FidoHidInitPacket(uint32_t channel_id,
-                    CtapHidDeviceCommand cmd,
+                    FidoHidDeviceCommand cmd,
                     std::vector<uint8_t> data,
                     uint16_t payload_length);
   ~FidoHidInitPacket() final;
 
   std::vector<uint8_t> GetSerializedData() const final;
-  CtapHidDeviceCommand command() const { return command_; }
+  FidoHidDeviceCommand command() const { return command_; }
   uint16_t payload_length() const { return payload_length_; }
 
  private:
-  CtapHidDeviceCommand command_;
+  FidoHidDeviceCommand command_;
   uint16_t payload_length_;
 
   DISALLOW_COPY_AND_ASSIGN(FidoHidInitPacket);
diff --git a/device/fido/mock_u2f_device.cc b/device/fido/mock_u2f_device.cc
index 03279a1..77fac1ce 100644
--- a/device/fido/mock_u2f_device.cc
+++ b/device/fido/mock_u2f_device.cc
@@ -7,12 +7,12 @@
 #include <utility>
 
 #include "components/apdu/apdu_response.h"
+#include "device/fido/fido_constants.h"
 #include "device/fido/u2f_response_test_data.h"
 
 namespace device {
 
 MockU2fDevice::MockU2fDevice() : weak_factory_(this) {}
-
 MockU2fDevice::~MockU2fDevice() = default;
 
 void MockU2fDevice::TryWink(WinkCallback cb) {
@@ -21,56 +21,70 @@
 
 void MockU2fDevice::DeviceTransact(std::vector<uint8_t> command,
                                    DeviceCallback cb) {
-  DeviceTransactPtr(std::move(command), cb);
+  DeviceTransactPtr(command, cb);
 }
 
 // static
-void MockU2fDevice::NotSatisfied(const std::vector<uint8_t>& cmd,
+void MockU2fDevice::NotSatisfied(const std::vector<uint8_t>& command,
                                  DeviceCallback& cb) {
-  std::move(cb).Run(
-      true, apdu::ApduResponse(
-                std::vector<uint8_t>(),
-                apdu::ApduResponse::Status::SW_CONDITIONS_NOT_SATISFIED));
+  std::move(cb).Run(apdu::ApduResponse(
+                        std::vector<uint8_t>(),
+                        apdu::ApduResponse::Status::SW_CONDITIONS_NOT_SATISFIED)
+                        .GetEncodedResponse());
 }
 
 // static
-void MockU2fDevice::WrongData(const std::vector<uint8_t>& cmd,
+void MockU2fDevice::WrongData(const std::vector<uint8_t>& command,
                               DeviceCallback& cb) {
   std::move(cb).Run(
-      true, apdu::ApduResponse(std::vector<uint8_t>(),
-                               apdu::ApduResponse::Status::SW_WRONG_DATA));
+      apdu::ApduResponse(std::vector<uint8_t>(),
+                         apdu::ApduResponse::Status::SW_WRONG_DATA)
+          .GetEncodedResponse());
 }
 
 // static
-void MockU2fDevice::NoErrorSign(const std::vector<uint8_t>& cmd,
+void MockU2fDevice::NoErrorSign(const std::vector<uint8_t>& command,
                                 DeviceCallback& cb) {
   std::move(cb).Run(
-      true, apdu::ApduResponse(std::vector<uint8_t>(
-                                   std::begin(test_data::kTestU2fSignResponse),
-                                   std::end(test_data::kTestU2fSignResponse)),
-                               apdu::ApduResponse::Status::SW_NO_ERROR));
+      apdu::ApduResponse(
+          std::vector<uint8_t>(std::begin(test_data::kTestU2fSignResponse),
+                               std::end(test_data::kTestU2fSignResponse)),
+          apdu::ApduResponse::Status::SW_NO_ERROR)
+          .GetEncodedResponse());
 }
 
 // static
-void MockU2fDevice::NoErrorRegister(const std::vector<uint8_t>& cmd,
+void MockU2fDevice::NoErrorRegister(const std::vector<uint8_t>& command,
                                     DeviceCallback& cb) {
   std::move(cb).Run(
-      true,
       apdu::ApduResponse(
           std::vector<uint8_t>(std::begin(test_data::kTestU2fRegisterResponse),
                                std::end(test_data::kTestU2fRegisterResponse)),
-          apdu::ApduResponse::Status::SW_NO_ERROR));
+          apdu::ApduResponse::Status::SW_NO_ERROR)
+          .GetEncodedResponse());
 }
 
 // static
-void MockU2fDevice::SignWithCorruptedResponse(const std::vector<uint8_t>& cmd,
-                                              DeviceCallback& cb) {
+void MockU2fDevice::NoErrorVersion(const std::vector<uint8_t>& command,
+                                   DeviceCallback& cb) {
   std::move(cb).Run(
-      true, apdu::ApduResponse(
-                std::vector<uint8_t>(
-                    std::begin(test_data::kTestCorruptedU2fSignResponse),
-                    std::end(test_data::kTestCorruptedU2fSignResponse)),
-                apdu::ApduResponse::Status::SW_NO_ERROR));
+      apdu::ApduResponse(std::vector<uint8_t>(kU2fVersionResponse.cbegin(),
+                                              kU2fVersionResponse.cend()),
+                         apdu::ApduResponse::Status::SW_NO_ERROR)
+          .GetEncodedResponse());
+}
+
+// static
+void MockU2fDevice::SignWithCorruptedResponse(
+    const std::vector<uint8_t>& command,
+    DeviceCallback& cb) {
+  std::move(cb).Run(
+      apdu::ApduResponse(
+          std::vector<uint8_t>(
+              std::begin(test_data::kTestCorruptedU2fSignResponse),
+              std::end(test_data::kTestCorruptedU2fSignResponse)),
+          apdu::ApduResponse::Status::SW_NO_ERROR)
+          .GetEncodedResponse());
 }
 
 // static
diff --git a/device/fido/mock_u2f_device.h b/device/fido/mock_u2f_device.h
index cf7ffa8..0302b37 100644
--- a/device/fido/mock_u2f_device.h
+++ b/device/fido/mock_u2f_device.h
@@ -33,11 +33,10 @@
   // TODO(crbug.com/729950): Remove these workarounds once support for move-only
   // types is added to GMock.
   MOCK_METHOD2(DeviceTransactPtr,
-               void(std::vector<uint8_t> command, DeviceCallback& cb));
+               void(const std::vector<uint8_t>& command, DeviceCallback& cb));
   void DeviceTransact(std::vector<uint8_t> command, DeviceCallback cb) override;
+
   base::WeakPtr<U2fDevice> GetWeakPtr() override;
-  static void TransactNoError(const std::vector<uint8_t>& command,
-                              DeviceCallback cb);
   static void NotSatisfied(const std::vector<uint8_t>& command,
                            DeviceCallback& cb);
   static void WrongData(const std::vector<uint8_t>& command,
@@ -46,6 +45,8 @@
                           DeviceCallback& cb);
   static void NoErrorRegister(const std::vector<uint8_t>& command,
                               DeviceCallback& cb);
+  static void NoErrorVersion(const std::vector<uint8_t>& command,
+                             DeviceCallback& cb);
   static void SignWithCorruptedResponse(const std::vector<uint8_t>& command,
                                         DeviceCallback& cb);
   static void WinkDoNothing(WinkCallback& cb);
diff --git a/device/fido/u2f_ble_connection.cc b/device/fido/u2f_ble_connection.cc
index 0e8a13a..d0f500c1 100644
--- a/device/fido/u2f_ble_connection.cc
+++ b/device/fido/u2f_ble_connection.cc
@@ -16,7 +16,7 @@
 #include "device/bluetooth/bluetooth_remote_gatt_characteristic.h"
 #include "device/bluetooth/bluetooth_remote_gatt_service.h"
 #include "device/bluetooth/bluetooth_uuid.h"
-#include "device/fido/u2f_ble_uuids.h"
+#include "device/fido/fido_ble_uuids.h"
 
 namespace device {
 
@@ -317,7 +317,7 @@
       device->GetGattServices();
   auto found =
       std::find_if(services.begin(), services.end(), [](const auto* service) {
-        return service->GetUUID().canonical_value() == kU2fServiceUUID;
+        return service->GetUUID().canonical_value() == kFidoServiceUUID;
       });
 
   if (found == services.end()) {
@@ -334,19 +334,19 @@
     // NOTE: Since GetUUID() returns a temporary |uuid| can't be a reference,
     // even though canonical_value() returns a const reference.
     const std::string uuid = characteristic->GetUUID().canonical_value();
-    if (uuid == kU2fControlPointLengthUUID) {
+    if (uuid == kFidoControlPointLengthUUID) {
       control_point_length_id_ = characteristic->GetIdentifier();
       DVLOG(2) << "Got U2F Control Point Length: " << *control_point_length_id_;
-    } else if (uuid == kU2fControlPointUUID) {
+    } else if (uuid == kFidoControlPointUUID) {
       control_point_id_ = characteristic->GetIdentifier();
       DVLOG(2) << "Got U2F Control Point: " << *control_point_id_;
-    } else if (uuid == kU2fStatusUUID) {
+    } else if (uuid == kFidoStatusUUID) {
       status_id_ = characteristic->GetIdentifier();
       DVLOG(2) << "Got U2F Status: " << *status_id_;
-    } else if (uuid == kU2fServiceRevisionUUID) {
+    } else if (uuid == kFidoServiceRevisionUUID) {
       service_revision_id_ = characteristic->GetIdentifier();
       DVLOG(2) << "Got U2F Service Revision: " << *service_revision_id_;
-    } else if (uuid == kU2fServiceRevisionBitfieldUUID) {
+    } else if (uuid == kFidoServiceRevisionBitfieldUUID) {
       service_revision_bitfield_id_ = characteristic->GetIdentifier();
       DVLOG(2) << "Got U2F Service Revision Bitfield: "
                << *service_revision_bitfield_id_;
diff --git a/device/fido/u2f_ble_connection_unittest.cc b/device/fido/u2f_ble_connection_unittest.cc
index 7b28877..2de3665 100644
--- a/device/fido/u2f_ble_connection_unittest.cc
+++ b/device/fido/u2f_ble_connection_unittest.cc
@@ -19,7 +19,7 @@
 #include "device/bluetooth/test/mock_bluetooth_gatt_connection.h"
 #include "device/bluetooth/test/mock_bluetooth_gatt_notify_session.h"
 #include "device/bluetooth/test/mock_bluetooth_gatt_service.h"
-#include "device/fido/u2f_ble_uuids.h"
+#include "device/fido/fido_ble_uuids.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -332,7 +332,7 @@
 
   void AddU2fService() {
     auto u2f_service = std::make_unique<NiceMockBluetoothGattService>(
-        u2f_device_, "u2f_service", BluetoothUUID(kU2fServiceUUID),
+        u2f_device_, "u2f_service", BluetoothUUID(kFidoServiceUUID),
         /* is_primary */ true, /* is_local */ false);
     u2f_service_ = u2f_service.get();
     u2f_device_->AddMockService(std::move(u2f_service));
@@ -353,7 +353,7 @@
       auto u2f_control_point =
           std::make_unique<NiceMockBluetoothGattCharacteristic>(
               u2f_service_, "u2f_control_point",
-              BluetoothUUID(kU2fControlPointUUID), is_local,
+              BluetoothUUID(kFidoControlPointUUID), is_local,
               BluetoothGattCharacteristic::PROPERTY_WRITE,
               BluetoothGattCharacteristic::PERMISSION_NONE);
       u2f_control_point_ = u2f_control_point.get();
@@ -362,7 +362,7 @@
 
     {
       auto u2f_status = std::make_unique<NiceMockBluetoothGattCharacteristic>(
-          u2f_service_, "u2f_status", BluetoothUUID(kU2fStatusUUID), is_local,
+          u2f_service_, "u2f_status", BluetoothUUID(kFidoStatusUUID), is_local,
           BluetoothGattCharacteristic::PROPERTY_NOTIFY,
           BluetoothGattCharacteristic::PERMISSION_NONE);
       u2f_status_ = u2f_status.get();
@@ -373,7 +373,7 @@
       auto u2f_control_point_length =
           std::make_unique<NiceMockBluetoothGattCharacteristic>(
               u2f_service_, "u2f_control_point_length",
-              BluetoothUUID(kU2fControlPointLengthUUID), is_local,
+              BluetoothUUID(kFidoControlPointLengthUUID), is_local,
               BluetoothGattCharacteristic::PROPERTY_READ,
               BluetoothGattCharacteristic::PERMISSION_NONE);
       u2f_control_point_length_ = u2f_control_point_length.get();
@@ -384,7 +384,7 @@
       auto u2f_service_revision =
           std::make_unique<NiceMockBluetoothGattCharacteristic>(
               u2f_service_, "u2f_service_revision",
-              BluetoothUUID(kU2fServiceRevisionUUID), is_local,
+              BluetoothUUID(kFidoServiceRevisionUUID), is_local,
               BluetoothGattCharacteristic::PROPERTY_READ,
               BluetoothGattCharacteristic::PERMISSION_NONE);
       u2f_service_revision_ = u2f_service_revision.get();
@@ -395,7 +395,7 @@
       auto u2f_service_revision_bitfield =
           std::make_unique<NiceMockBluetoothGattCharacteristic>(
               u2f_service_, "u2f_service_revision_bitfield",
-              BluetoothUUID(kU2fServiceRevisionBitfieldUUID), is_local,
+              BluetoothUUID(kFidoServiceRevisionBitfieldUUID), is_local,
               BluetoothGattCharacteristic::PROPERTY_READ |
                   BluetoothGattCharacteristic::PROPERTY_WRITE,
               BluetoothGattCharacteristic::PERMISSION_NONE);
diff --git a/device/fido/u2f_ble_device.cc b/device/fido/u2f_ble_device.cc
index 468843e..0dc9a38 100644
--- a/device/fido/u2f_ble_device.cc
+++ b/device/fido/u2f_ble_device.cc
@@ -27,23 +27,22 @@
 U2fBleDevice::~U2fBleDevice() = default;
 
 void U2fBleDevice::Connect() {
-  if (state_ != State::INIT)
+  if (state_ != State::kInit)
     return;
 
   StartTimeout();
-  state_ = State::BUSY;
+  state_ = State::kBusy;
   connection_->Connect();
 }
 
 void U2fBleDevice::SendPing(std::vector<uint8_t> data,
-                            MessageCallback callback) {
+                            DeviceCallback callback) {
   pending_frames_.emplace(
-      U2fBleFrame(U2fCommandType::CMD_PING, std::move(data)),
+      U2fBleFrame(FidoBleDeviceCommand::kPing, std::move(data)),
       base::BindOnce(
-          [](MessageCallback callback, base::Optional<U2fBleFrame> frame) {
-            std::move(callback).Run(
-                frame ? U2fReturnCode::SUCCESS : U2fReturnCode::FAILURE,
-                frame ? frame->data() : std::vector<uint8_t>());
+          [](DeviceCallback callback, base::Optional<U2fBleFrame> frame) {
+            std::move(callback).Run(frame ? base::make_optional(frame->data())
+                                          : base::nullopt);
           },
           std::move(callback)));
   Transition();
@@ -77,13 +76,11 @@
 void U2fBleDevice::DeviceTransact(std::vector<uint8_t> command,
                                   DeviceCallback callback) {
   pending_frames_.emplace(
-      U2fBleFrame(U2fCommandType::CMD_MSG, std::move(command)),
+      U2fBleFrame(FidoBleDeviceCommand::kMsg, std::move(command)),
       base::BindOnce(
           [](DeviceCallback callback, base::Optional<U2fBleFrame> frame) {
-            std::move(callback).Run(
-                frame.has_value(),
-                frame ? apdu::ApduResponse::CreateFromMessage(frame->data())
-                      : base::nullopt);
+            std::move(callback).Run(frame ? base::make_optional(frame->data())
+                                          : base::nullopt);
           },
           std::move(callback)));
   Transition();
@@ -95,16 +92,16 @@
 
 void U2fBleDevice::Transition() {
   switch (state_) {
-    case State::INIT:
+    case State::kInit:
       Connect();
       break;
-    case State::CONNECTED:
+    case State::kConnected:
       StartTimeout();
-      state_ = State::BUSY;
+      state_ = State::kBusy;
       connection_->ReadControlPointLength(base::BindOnce(
           &U2fBleDevice::OnReadControlPointLength, base::Unretained(this)));
       break;
-    case State::READY:
+    case State::kReady:
       if (!pending_frames_.empty()) {
         U2fBleFrame frame;
         FrameCallback callback;
@@ -113,9 +110,9 @@
         SendRequestFrame(std::move(frame), std::move(callback));
       }
       break;
-    case State::BUSY:
+    case State::kBusy:
       break;
-    case State::DEVICE_ERROR:
+    case State::kDeviceError:
       auto self = GetWeakPtr();
       // Executing callbacks may free |this|. Check |self| first.
       while (self && !pending_frames_.empty()) {
@@ -130,7 +127,7 @@
 
 void U2fBleDevice::OnConnectionStatus(bool success) {
   StopTimeout();
-  state_ = success ? State::CONNECTED : State::DEVICE_ERROR;
+  state_ = success ? State::kConnected : State::kDeviceError;
   Transition();
 }
 
@@ -138,9 +135,9 @@
   StopTimeout();
   if (length) {
     transaction_.emplace(connection_.get(), *length);
-    state_ = State::READY;
+    state_ = State::kReady;
   } else {
-    state_ = State::DEVICE_ERROR;
+    state_ = State::kDeviceError;
   }
   Transition();
 }
@@ -151,7 +148,7 @@
 }
 
 void U2fBleDevice::SendRequestFrame(U2fBleFrame frame, FrameCallback callback) {
-  state_ = State::BUSY;
+  state_ = State::kBusy;
   transaction_->WriteRequestFrame(
       std::move(frame),
       base::BindOnce(&U2fBleDevice::OnResponseFrame, base::Unretained(this),
@@ -160,7 +157,7 @@
 
 void U2fBleDevice::OnResponseFrame(FrameCallback callback,
                                    base::Optional<U2fBleFrame> frame) {
-  state_ = frame ? State::READY : State::DEVICE_ERROR;
+  state_ = frame ? State::kReady : State::kDeviceError;
   auto self = GetWeakPtr();
   std::move(callback).Run(std::move(frame));
   // Executing callbacks may free |this|. Check |self| first.
@@ -169,8 +166,7 @@
 }
 
 void U2fBleDevice::StartTimeout() {
-  timer_.Start(FROM_HERE, U2fDevice::kDeviceTimeout, this,
-               &U2fBleDevice::OnTimeout);
+  timer_.Start(FROM_HERE, kDeviceTimeout, this, &U2fBleDevice::OnTimeout);
 }
 
 void U2fBleDevice::StopTimeout() {
@@ -178,7 +174,7 @@
 }
 
 void U2fBleDevice::OnTimeout() {
-  state_ = State::DEVICE_ERROR;
+  state_ = State::kDeviceError;
 }
 
 }  // namespace device
diff --git a/device/fido/u2f_ble_device.h b/device/fido/u2f_ble_device.h
index a9409fc9..06ada63 100644
--- a/device/fido/u2f_ble_device.h
+++ b/device/fido/u2f_ble_device.h
@@ -17,6 +17,7 @@
 #include "base/optional.h"
 #include "base/strings/string_piece.h"
 #include "base/timer/timer.h"
+#include "device/fido/fido_constants.h"
 #include "device/fido/u2f_ble_connection.h"
 #include "device/fido/u2f_ble_transaction.h"
 #include "device/fido/u2f_device.h"
@@ -33,7 +34,7 @@
   ~U2fBleDevice() override;
 
   void Connect();
-  void SendPing(std::vector<uint8_t> data, MessageCallback callback);
+  void SendPing(std::vector<uint8_t> data, DeviceCallback callback);
   static std::string GetId(base::StringPiece address);
 
   // U2fDevice:
@@ -51,10 +52,6 @@
   base::WeakPtr<U2fDevice> GetWeakPtr() override;
 
  private:
-  // INIT --> BUSY --> CONNECTED --> BUSY <--> READY.
-  // DEVICE_ERROR persists.
-  enum class State { INIT, CONNECTED, READY, BUSY, DEVICE_ERROR };
-
   void Transition();
 
   void OnConnectionStatus(bool success);
@@ -72,7 +69,7 @@
   void StopTimeout();
   void OnTimeout();
 
-  State state_ = State::INIT;
+  State state_ = State::kInit;
   base::OneShotTimer timer_;
 
   std::unique_ptr<U2fBleConnection> connection_;
diff --git a/device/fido/u2f_ble_device_unittest.cc b/device/fido/u2f_ble_device_unittest.cc
index 94a62c9..f89a7fe 100644
--- a/device/fido/u2f_ble_device_unittest.cc
+++ b/device/fido/u2f_ble_device_unittest.cc
@@ -18,9 +18,8 @@
 using ::testing::_;
 using ::testing::Invoke;
 using ::testing::Test;
-using TestMessageCallbackReceiver =
-    test::StatusAndValueCallbackReceiver<U2fReturnCode,
-                                         const std::vector<uint8_t>&>;
+using TestDeviceCallbackReceiver =
+    test::TestCallbackReceiver<base::Optional<std::vector<uint8_t>>>;
 
 }  // namespace
 
@@ -73,12 +72,11 @@
       .WillOnce(Invoke(
           [this](const auto& data, auto* cb) { std::move(*cb).Run(false); }));
 
-  TestMessageCallbackReceiver callback_receiver;
+  TestDeviceCallbackReceiver callback_receiver;
   device()->SendPing({'T', 'E', 'S', 'T'}, callback_receiver.callback());
 
   callback_receiver.WaitForCallback();
-  EXPECT_EQ(U2fReturnCode::FAILURE, callback_receiver.status());
-  EXPECT_EQ(std::vector<uint8_t>(), callback_receiver.value());
+  EXPECT_FALSE(std::get<0>(*callback_receiver.result()));
 }
 
 TEST_F(U2fBleDeviceTest, SendPingTest_Failure_Timeout) {
@@ -86,15 +84,14 @@
 
   EXPECT_CALL(*connection(), WriteControlPointPtr(_, _))
       .WillOnce(Invoke([this](const auto& data, auto* cb) {
-        scoped_task_environment_.FastForwardBy(U2fDevice::kDeviceTimeout);
+        scoped_task_environment_.FastForwardBy(kDeviceTimeout);
       }));
 
-  TestMessageCallbackReceiver callback_receiver;
+  TestDeviceCallbackReceiver callback_receiver;
   device()->SendPing({'T', 'E', 'S', 'T'}, callback_receiver.callback());
 
   callback_receiver.WaitForCallback();
-  EXPECT_EQ(U2fReturnCode::FAILURE, callback_receiver.status());
-  EXPECT_EQ(std::vector<uint8_t>(), callback_receiver.value());
+  EXPECT_FALSE(std::get<0>(*callback_receiver.result()));
 }
 
 TEST_F(U2fBleDeviceTest, SendPingTest) {
@@ -104,18 +101,19 @@
   EXPECT_CALL(*connection(), WriteControlPointPtr(_, _))
       .WillOnce(Invoke([this](const auto& data, auto* cb) {
         auto almost_time_out =
-            U2fDevice::kDeviceTimeout - base::TimeDelta::FromMicroseconds(1);
+            kDeviceTimeout - base::TimeDelta::FromMicroseconds(1);
         scoped_task_environment_.FastForwardBy(almost_time_out);
         connection()->read_callback().Run(data);
         std::move(*cb).Run(true);
       }));
 
-  TestMessageCallbackReceiver callback_receiver;
+  TestDeviceCallbackReceiver callback_receiver;
   device()->SendPing(ping_data, callback_receiver.callback());
 
   callback_receiver.WaitForCallback();
-  EXPECT_EQ(U2fReturnCode::SUCCESS, callback_receiver.status());
-  EXPECT_EQ(ping_data, callback_receiver.value());
+  const auto& result = std::get<0>(*callback_receiver.result());
+  ASSERT_TRUE(result);
+  EXPECT_EQ(ping_data, *result);
 }
 
 TEST_F(U2fBleDeviceTest, StaticGetIdTest) {
diff --git a/device/fido/u2f_ble_discovery.cc b/device/fido/u2f_ble_discovery.cc
index c8fc158..67d3b0a 100644
--- a/device/fido/u2f_ble_discovery.cc
+++ b/device/fido/u2f_ble_discovery.cc
@@ -15,8 +15,8 @@
 #include "device/bluetooth/bluetooth_discovery_filter.h"
 #include "device/bluetooth/bluetooth_discovery_session.h"
 #include "device/bluetooth/bluetooth_uuid.h"
+#include "device/fido/fido_ble_uuids.h"
 #include "device/fido/u2f_ble_device.h"
-#include "device/fido/u2f_ble_uuids.h"
 
 namespace device {
 
@@ -55,7 +55,7 @@
 
 // static
 const BluetoothUUID& U2fBleDiscovery::U2fServiceUUID() {
-  static const BluetoothUUID service_uuid(kU2fServiceUUID);
+  static const BluetoothUUID service_uuid(kFidoServiceUUID);
   return service_uuid;
 }
 
diff --git a/device/fido/u2f_ble_frames.cc b/device/fido/u2f_ble_frames.cc
index c36135138..9720acf 100644
--- a/device/fido/u2f_ble_frames.cc
+++ b/device/fido/u2f_ble_frames.cc
@@ -9,12 +9,14 @@
 
 #include "base/logging.h"
 #include "base/numerics/safe_conversions.h"
+#include "device/fido/fido_constants.h"
 
 namespace device {
 
 U2fBleFrame::U2fBleFrame() = default;
 
-U2fBleFrame::U2fBleFrame(U2fCommandType command, std::vector<uint8_t> data)
+U2fBleFrame::U2fBleFrame(FidoBleDeviceCommand command,
+                         std::vector<uint8_t> data)
     : command_(command), data_(std::move(data)) {}
 
 U2fBleFrame::U2fBleFrame(U2fBleFrame&&) = default;
@@ -24,26 +26,26 @@
 
 bool U2fBleFrame::IsValid() const {
   switch (command_) {
-    case U2fCommandType::CMD_PING:
-    case U2fCommandType::CMD_MSG:
+    case FidoBleDeviceCommand::kPing:
+    case FidoBleDeviceCommand::kMsg:
+    case FidoBleDeviceCommand::kCancel:
       return true;
-    case U2fCommandType::CMD_KEEPALIVE:
-    case U2fCommandType::CMD_ERROR:
+    case FidoBleDeviceCommand::kKeepAlive:
+    case FidoBleDeviceCommand::kError:
       return data_.size() == 1;
-    case U2fCommandType::UNDEFINED:
-    default:
-      return false;
   }
+  NOTREACHED();
+  return false;
 }
 
 U2fBleFrame::KeepaliveCode U2fBleFrame::GetKeepaliveCode() const {
-  DCHECK_EQ(command_, U2fCommandType::CMD_KEEPALIVE);
+  DCHECK_EQ(command_, FidoBleDeviceCommand::kKeepAlive);
   DCHECK_EQ(data_.size(), 1u);
   return static_cast<KeepaliveCode>(data_[0]);
 }
 
 U2fBleFrame::ErrorCode U2fBleFrame::GetErrorCode() const {
-  DCHECK_EQ(command_, U2fCommandType::CMD_ERROR);
+  DCHECK_EQ(command_, FidoBleDeviceCommand::kError);
   DCHECK_EQ(data_.size(), 1u);
   return static_cast<ErrorCode>(data_[0]);
 }
@@ -97,7 +99,7 @@
   if (data.size() < 3)
     return false;
 
-  const auto command = static_cast<U2fCommandType>(data[0]);
+  const auto command = static_cast<FidoBleDeviceCommand>(data[0]);
   const uint16_t data_length = (static_cast<uint16_t>(data[1]) << 8) + data[2];
   if (static_cast<size_t>(data_length) + 3 < data.size())
     return false;
diff --git a/device/fido/u2f_ble_frames.h b/device/fido/u2f_ble_frames.h
index 5667942..0b744647 100644
--- a/device/fido/u2f_ble_frames.h
+++ b/device/fido/u2f_ble_frames.h
@@ -14,7 +14,7 @@
 #include "base/containers/queue.h"
 #include "base/containers/span.h"
 #include "base/macros.h"
-#include "device/fido/u2f_command_type.h"
+#include "device/fido/fido_constants.h"
 
 namespace device {
 
@@ -56,14 +56,14 @@
   };
 
   U2fBleFrame();
-  U2fBleFrame(U2fCommandType command, std::vector<uint8_t> data);
+  U2fBleFrame(FidoBleDeviceCommand command, std::vector<uint8_t> data);
 
   U2fBleFrame(U2fBleFrame&&);
   U2fBleFrame& operator=(U2fBleFrame&&);
 
   ~U2fBleFrame();
 
-  U2fCommandType command() const { return command_; }
+  FidoBleDeviceCommand command() const { return command_; }
 
   bool IsValid() const;
   KeepaliveCode GetKeepaliveCode() const;
@@ -83,7 +83,7 @@
   ToFragments(size_t max_fragment_size) const;
 
  private:
-  U2fCommandType command_ = U2fCommandType::UNDEFINED;
+  FidoBleDeviceCommand command_ = FidoBleDeviceCommand::kMsg;
   std::vector<uint8_t> data_;
 
   DISALLOW_COPY_AND_ASSIGN(U2fBleFrame);
@@ -121,20 +121,20 @@
                     U2fBleFrameInitializationFragment* fragment);
 
   U2fBleFrameInitializationFragment() = default;
-  U2fBleFrameInitializationFragment(U2fCommandType command,
+  U2fBleFrameInitializationFragment(FidoBleDeviceCommand command,
                                     uint16_t data_length,
                                     base::span<const uint8_t> fragment)
       : U2fBleFrameFragment(fragment),
         command_(command),
         data_length_(data_length) {}
 
-  U2fCommandType command() const { return command_; }
+  FidoBleDeviceCommand command() const { return command_; }
   uint16_t data_length() const { return data_length_; }
 
   size_t Serialize(std::vector<uint8_t>* buffer) const override;
 
  private:
-  U2fCommandType command_ = U2fCommandType::UNDEFINED;
+  FidoBleDeviceCommand command_ = FidoBleDeviceCommand::kMsg;
   uint16_t data_length_ = 0;
 };
 
diff --git a/device/fido/u2f_ble_frames_fuzzer.cc b/device/fido/u2f_ble_frames_fuzzer.cc
index 772a7e6..adb5e08 100644
--- a/device/fido/u2f_ble_frames_fuzzer.cc
+++ b/device/fido/u2f_ble_frames_fuzzer.cc
@@ -7,8 +7,8 @@
 
 #include <vector>
 
+#include "device/fido/fido_constants.h"
 #include "device/fido/u2f_ble_frames.h"
-#include "device/fido/u2f_command_type.h"
 
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* raw_data, size_t size) {
   auto data_span = base::make_span(raw_data, size);
@@ -16,7 +16,7 @@
 
   {
     device::U2fBleFrameInitializationFragment fragment(
-        device::U2fCommandType::CMD_MSG, 21123, data_span);
+        device::FidoBleDeviceCommand::kMsg, 21123, data_span);
     std::vector<uint8_t> buffer;
     fragment.Serialize(&buffer);
 
@@ -42,7 +42,7 @@
   }
 
   {
-    device::U2fBleFrame frame(device::U2fCommandType::CMD_PING, data);
+    device::U2fBleFrame frame(device::FidoBleDeviceCommand::kPing, data);
     auto fragments = frame.ToFragments(20);
 
     device::U2fBleFrameAssembler assembler(fragments.first);
diff --git a/device/fido/u2f_ble_frames_unittest.cc b/device/fido/u2f_ble_frames_unittest.cc
index 5b2757c..4ee467e 100644
--- a/device/fido/u2f_ble_frames_unittest.cc
+++ b/device/fido/u2f_ble_frames_unittest.cc
@@ -6,7 +6,6 @@
 
 #include <vector>
 
-#include "device/fido/u2f_command_type.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace {
@@ -27,7 +26,7 @@
   constexpr uint16_t kDataLength = 21123;
 
   U2fBleFrameInitializationFragment fragment(
-      U2fCommandType::CMD_MSG, kDataLength, base::make_span(data));
+      FidoBleDeviceCommand::kMsg, kDataLength, base::make_span(data));
 
   std::vector<uint8_t> buffer;
   const size_t binary_size = fragment.Serialize(&buffer);
@@ -41,7 +40,7 @@
 
   EXPECT_EQ(kDataLength, parsed_fragment.data_length());
   EXPECT_EQ(base::make_span(data), parsed_fragment.fragment());
-  EXPECT_EQ(U2fCommandType::CMD_MSG, parsed_fragment.command());
+  EXPECT_EQ(FidoBleDeviceCommand::kMsg, parsed_fragment.command());
 }
 
 TEST(U2fBleFramesTest, ContinuationFragment) {
@@ -68,7 +67,7 @@
                       37, 39, 40, 41, 54, 55, 56, 60, 100, 65535}) {
     SCOPED_TRACE(size);
 
-    U2fBleFrame frame(U2fCommandType::CMD_PING, GetSomeData(size));
+    U2fBleFrame frame(FidoBleDeviceCommand::kPing, GetSomeData(size));
 
     auto fragments = frame.ToFragments(20);
 
@@ -92,7 +91,7 @@
 }
 
 TEST(U2fBleFramesTest, FrameAssemblerError) {
-  U2fBleFrame frame(U2fCommandType::CMD_PING, GetSomeData(30));
+  U2fBleFrame frame(FidoBleDeviceCommand::kPing, GetSomeData(30));
 
   auto fragments = frame.ToFragments(20);
   ASSERT_EQ(1u, fragments.second.size());
@@ -110,17 +109,18 @@
 
 TEST(U2fBleFramesTest, FrameGettersAndValidity) {
   {
-    U2fBleFrame frame(U2fCommandType::CMD_KEEPALIVE, std::vector<uint8_t>(2));
+    U2fBleFrame frame(FidoBleDeviceCommand::kKeepAlive,
+                      std::vector<uint8_t>(2));
     EXPECT_FALSE(frame.IsValid());
   }
   {
-    U2fBleFrame frame(U2fCommandType::CMD_ERROR, {});
+    U2fBleFrame frame(FidoBleDeviceCommand::kError, {});
     EXPECT_FALSE(frame.IsValid());
   }
 
   for (auto code : {U2fBleFrame::KeepaliveCode::TUP_NEEDED,
                     U2fBleFrame::KeepaliveCode::PROCESSING}) {
-    U2fBleFrame frame(U2fCommandType::CMD_KEEPALIVE,
+    U2fBleFrame frame(FidoBleDeviceCommand::kKeepAlive,
                       std::vector<uint8_t>(1, static_cast<uint8_t>(code)));
     EXPECT_TRUE(frame.IsValid());
     EXPECT_EQ(code, frame.GetKeepaliveCode());
@@ -134,7 +134,8 @@
            U2fBleFrame::ErrorCode::REQ_TIMEOUT, U2fBleFrame::ErrorCode::NA_1,
            U2fBleFrame::ErrorCode::NA_2, U2fBleFrame::ErrorCode::NA_3,
        }) {
-    U2fBleFrame frame(U2fCommandType::CMD_ERROR, {static_cast<uint8_t>(code)});
+    U2fBleFrame frame(FidoBleDeviceCommand::kError,
+                      {static_cast<uint8_t>(code)});
     EXPECT_TRUE(frame.IsValid());
     EXPECT_EQ(code, frame.GetErrorCode());
   }
diff --git a/device/fido/u2f_ble_transaction.cc b/device/fido/u2f_ble_transaction.cc
index 0c8b1d5..aa12b94 100644
--- a/device/fido/u2f_ble_transaction.cc
+++ b/device/fido/u2f_ble_transaction.cc
@@ -106,7 +106,7 @@
     return;
   }
 
-  if (response_frame.command() == U2fCommandType::CMD_KEEPALIVE) {
+  if (response_frame.command() == FidoBleDeviceCommand::kKeepAlive) {
     DVLOG(2) << "CMD_KEEPALIVE: "
              << static_cast<uint8_t>(response_frame.GetKeepaliveCode());
     // Expect another reponse frame soon.
@@ -114,15 +114,14 @@
     return;
   }
 
-  DCHECK_EQ(response_frame.command(), U2fCommandType::CMD_ERROR);
+  DCHECK_EQ(response_frame.command(), FidoBleDeviceCommand::kError);
   DLOG(ERROR) << "CMD_ERROR: "
               << static_cast<uint8_t>(response_frame.GetErrorCode());
   OnError();
 }
 
 void U2fBleTransaction::StartTimeout() {
-  timer_.Start(FROM_HERE, U2fDevice::kDeviceTimeout, this,
-               &U2fBleTransaction::OnError);
+  timer_.Start(FROM_HERE, kDeviceTimeout, this, &U2fBleTransaction::OnError);
 }
 
 void U2fBleTransaction::StopTimeout() {
diff --git a/device/fido/u2f_ble_uuids.cc b/device/fido/u2f_ble_uuids.cc
deleted file mode 100644
index d8188a8..0000000
--- a/device/fido/u2f_ble_uuids.cc
+++ /dev/null
@@ -1,18 +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 "device/fido/u2f_ble_uuids.h"
-
-namespace device {
-
-const char kU2fServiceUUID[] = "0000fffd-0000-1000-8000-00805f9b34fb";
-const char kU2fControlPointUUID[] = "f1d0fff1-deaa-ecee-b42f-c9ba7ed623bb";
-const char kU2fStatusUUID[] = "f1d0fff2-deaa-ecee-b42f-c9ba7ed623bb";
-const char kU2fControlPointLengthUUID[] =
-    "f1d0fff3-deaa-ecee-b42f-c9ba7ed623bb";
-const char kU2fServiceRevisionUUID[] = "00002a28-0000-1000-8000-00805f9b34fb";
-const char kU2fServiceRevisionBitfieldUUID[] =
-    "f1d0fff4-deaa-ecee-b42f-c9ba7ed623bb";
-
-}  // namespace device
diff --git a/device/fido/u2f_ble_uuids.h b/device/fido/u2f_ble_uuids.h
deleted file mode 100644
index 919d617..0000000
--- a/device/fido/u2f_ble_uuids.h
+++ /dev/null
@@ -1,28 +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 DEVICE_FIDO_U2F_BLE_UUIDS_H_
-#define DEVICE_FIDO_U2F_BLE_UUIDS_H_
-
-#include "base/component_export.h"
-
-namespace device {
-
-// U2F GATT Service's UUIDs as defined by the standard:
-// https://fidoalliance.org/specs/fido-u2f-v1.2-ps-20170411/fido-u2f-bt-protocol-v1.2-ps-20170411.html#h3_u2f-service
-//
-// For details on how the short UUIDs for U2F Service (0xFFFD) and U2F Service
-// Revision (0x2A28) were converted to the long canonical ones, see
-// https://www.bluetooth.com/specifications/assigned-numbers/service-discovery
-COMPONENT_EXPORT(DEVICE_FIDO) extern const char kU2fServiceUUID[];
-COMPONENT_EXPORT(DEVICE_FIDO) extern const char kU2fControlPointUUID[];
-COMPONENT_EXPORT(DEVICE_FIDO) extern const char kU2fStatusUUID[];
-COMPONENT_EXPORT(DEVICE_FIDO) extern const char kU2fControlPointLengthUUID[];
-COMPONENT_EXPORT(DEVICE_FIDO) extern const char kU2fServiceRevisionUUID[];
-COMPONENT_EXPORT(DEVICE_FIDO)
-extern const char kU2fServiceRevisionBitfieldUUID[];
-
-}  // namespace device
-
-#endif  // DEVICE_FIDO_U2F_BLE_UUIDS_H_
diff --git a/device/fido/u2f_command_type.h b/device/fido/u2f_command_type.h
deleted file mode 100644
index 26811e6..0000000
--- a/device/fido/u2f_command_type.h
+++ /dev/null
@@ -1,44 +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 DEVICE_FIDO_U2F_COMMAND_TYPE_H_
-#define DEVICE_FIDO_U2F_COMMAND_TYPE_H_
-
-#include <stdint.h>
-
-namespace device {
-
-// The type of a command that can be sent either to or from a U2F authenticator,
-// i.e. a request or a response.
-//
-// Each request sent to a device results in a response of *the same* type sent
-// back, unless there was an error in which case a CMD_ERROR is returned.
-enum class U2fCommandType : uint8_t {
-  UNDEFINED = 0x00,
-
-  // Sends arbitrary data to the device which echoes the same data back.
-  CMD_PING = 0x81,
-
-  // Authenticator sends this in response to requests that it could not process
-  // within a time limit. The client should take action appropriate to the
-  // message reason (e.g., notify the user to perform a test-of-user-presence),
-  // and wait for the next message.
-  CMD_KEEPALIVE = 0x82,
-
-  // Encapsulates a U2F protocol raw message.
-  CMD_MSG = 0x83,
-
-  // Requests a unique channel from a USB/HID device.
-  CMD_INIT = 0x86,
-
-  // Instructs a USB/HID authenticator to show the user that it is active.
-  CMD_WINK = 0x88,
-
-  // Used as a response in case an error occurs during a request.
-  CMD_ERROR = 0xBF,
-};
-
-}  // namespace device
-
-#endif  // DEVICE_FIDO_U2F_COMMAND_TYPE_H_
diff --git a/device/fido/u2f_device.cc b/device/fido/u2f_device.cc
index afafc571..eb75a59 100644
--- a/device/fido/u2f_device.cc
+++ b/device/fido/u2f_device.cc
@@ -4,120 +4,9 @@
 
 #include "device/fido/u2f_device.h"
 
-#include <utility>
-
-#include "base/bind.h"
-#include "components/apdu/apdu_command.h"
-#include "device/fido/u2f_request.h"
-
 namespace device {
 
-constexpr base::TimeDelta U2fDevice::kDeviceTimeout;
-
 U2fDevice::U2fDevice() = default;
-
 U2fDevice::~U2fDevice() = default;
 
-void U2fDevice::Register(base::Optional<std::vector<uint8_t>> register_cmd,
-                         MessageCallback callback) {
-  if (!register_cmd) {
-    std::move(callback).Run(U2fReturnCode::INVALID_PARAMS,
-                            std::vector<uint8_t>());
-    return;
-  }
-  DeviceTransact(std::move(*register_cmd),
-                 base::BindOnce(&U2fDevice::OnRegisterComplete, GetWeakPtr(),
-                                std::move(callback)));
-}
-
-void U2fDevice::Sign(base::Optional<std::vector<uint8_t>> sign_cmd,
-                     MessageCallback callback) {
-  if (!sign_cmd) {
-    std::move(callback).Run(U2fReturnCode::INVALID_PARAMS,
-                            std::vector<uint8_t>());
-    return;
-  }
-  DeviceTransact(std::move(*sign_cmd),
-                 base::BindOnce(&U2fDevice::OnSignComplete, GetWeakPtr(),
-                                std::move(callback)));
-}
-
-void U2fDevice::Version(VersionCallback callback) {
-  DeviceTransact(U2fRequest::GetU2fVersionApduCommand(),
-                 base::BindOnce(&U2fDevice::OnVersionComplete, GetWeakPtr(),
-                                std::move(callback), false /* legacy */));
-}
-
-void U2fDevice::OnRegisterComplete(
-    MessageCallback callback,
-    bool success,
-    base::Optional<apdu::ApduResponse> register_response) {
-  if (!success || !register_response) {
-    std::move(callback).Run(U2fReturnCode::FAILURE, std::vector<uint8_t>());
-    return;
-  }
-  switch (register_response->status()) {
-    case apdu::ApduResponse::Status::SW_CONDITIONS_NOT_SATISFIED:
-      std::move(callback).Run(U2fReturnCode::CONDITIONS_NOT_SATISFIED,
-                              std::vector<uint8_t>());
-      break;
-    case apdu::ApduResponse::Status::SW_NO_ERROR:
-      std::move(callback).Run(U2fReturnCode::SUCCESS,
-                              register_response->data());
-      break;
-    case apdu::ApduResponse::Status::SW_WRONG_DATA:
-      std::move(callback).Run(U2fReturnCode::INVALID_PARAMS,
-                              std::vector<uint8_t>());
-      break;
-    default:
-      std::move(callback).Run(U2fReturnCode::FAILURE, std::vector<uint8_t>());
-      break;
-  }
-}
-
-void U2fDevice::OnSignComplete(
-    MessageCallback callback,
-    bool success,
-    base::Optional<apdu::ApduResponse> sign_response) {
-  if (!success || !sign_response) {
-    std::move(callback).Run(U2fReturnCode::FAILURE, std::vector<uint8_t>());
-    return;
-  }
-  switch (sign_response->status()) {
-    case apdu::ApduResponse::Status::SW_CONDITIONS_NOT_SATISFIED:
-      std::move(callback).Run(U2fReturnCode::CONDITIONS_NOT_SATISFIED,
-                              std::vector<uint8_t>());
-      break;
-    case apdu::ApduResponse::Status::SW_NO_ERROR:
-      std::move(callback).Run(U2fReturnCode::SUCCESS, sign_response->data());
-      break;
-    case apdu::ApduResponse::Status::SW_WRONG_DATA:
-    case apdu::ApduResponse::Status::SW_WRONG_LENGTH:
-    default:
-      std::move(callback).Run(U2fReturnCode::INVALID_PARAMS,
-                              std::vector<uint8_t>());
-      break;
-  }
-}
-
-void U2fDevice::OnVersionComplete(
-    VersionCallback callback,
-    bool legacy,
-    bool success,
-    base::Optional<apdu::ApduResponse> version_response) {
-  if (success && version_response &&
-      version_response->status() == apdu::ApduResponse::Status::SW_NO_ERROR &&
-      version_response->data() ==
-          std::vector<uint8_t>({'U', '2', 'F', '_', 'V', '2'})) {
-    std::move(callback).Run(success, ProtocolVersion::U2F_V2);
-  } else if (!legacy) {
-    // Standard GetVersion failed, attempt legacy GetVersion command.
-    DeviceTransact(U2fRequest::GetU2fVersionApduCommand(true /* legacy */),
-                   base::BindOnce(&U2fDevice::OnVersionComplete, GetWeakPtr(),
-                                  std::move(callback), true /* legacy */));
-  } else {
-    std::move(callback).Run(success, ProtocolVersion::UNKNOWN);
-  }
-}
-
 }  // namespace device
diff --git a/device/fido/u2f_device.h b/device/fido/u2f_device.h
index 25c386f..6065e05 100644
--- a/device/fido/u2f_device.h
+++ b/device/fido/u2f_device.h
@@ -5,7 +5,8 @@
 #ifndef DEVICE_FIDO_U2F_DEVICE_H_
 #define DEVICE_FIDO_U2F_DEVICE_H_
 
-#include <memory>
+#include <stdint.h>
+
 #include <string>
 #include <vector>
 
@@ -14,8 +15,7 @@
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "base/optional.h"
-#include "components/apdu/apdu_response.h"
-#include "device/fido/u2f_return_code.h"
+#include "base/time/time.h"
 
 namespace device {
 
@@ -23,56 +23,24 @@
 // standardized Register, Sign, and GetVersion methods.
 class COMPONENT_EXPORT(DEVICE_FIDO) U2fDevice {
  public:
-  enum class ProtocolVersion {
-    U2F_V2,
-    UNKNOWN,
-  };
-
-  using MessageCallback =
-      base::OnceCallback<void(U2fReturnCode, const std::vector<uint8_t>&)>;
-  using VersionCallback =
-      base::OnceCallback<void(bool success, ProtocolVersion version)>;
+  using WinkCallback = base::OnceClosure;
   using DeviceCallback =
-      base::OnceCallback<void(bool success,
-                              base::Optional<apdu::ApduResponse> response)>;
-  using WinkCallback = base::OnceCallback<void()>;
+      base::OnceCallback<void(base::Optional<std::vector<uint8_t>> response)>;
 
-  static constexpr auto kDeviceTimeout = base::TimeDelta::FromSeconds(3);
+  // Internal state machine states.
+  enum class State { kInit, kConnected, kBusy, kReady, kDeviceError };
 
   U2fDevice();
   virtual ~U2fDevice();
-
-  // TODO(hongjunchoi): https://crbug.com/810229 Move all encoding logic from
-  // U2fDevice to U2fRequest.
-  // Raw messages parameters are defined by the specification at
-  // https://fidoalliance.org/specs/fido-u2f-v1.0-nfc-bt-amendment-20150514/fido-u2f-raw-message-formats.html
-  void Register(base::Optional<std::vector<uint8_t>> register_cmd,
-                MessageCallback callback);
-  void Sign(base::Optional<std::vector<uint8_t>> sign_cmd,
-            MessageCallback callback);
-  void Version(VersionCallback callback);
-
-  virtual void TryWink(WinkCallback callback) = 0;
-  virtual std::string GetId() const = 0;
-
- protected:
   // Pure virtual function defined by each device type, implementing
   // the device communication transaction.
   virtual void DeviceTransact(std::vector<uint8_t> command,
                               DeviceCallback callback) = 0;
-  virtual base::WeakPtr<U2fDevice> GetWeakPtr() = 0;
+  virtual void TryWink(WinkCallback callback) = 0;
+  virtual std::string GetId() const = 0;
 
- private:
-  void OnRegisterComplete(MessageCallback callback,
-                          bool success,
-                          base::Optional<apdu::ApduResponse> register_response);
-  void OnSignComplete(MessageCallback callback,
-                      bool success,
-                      base::Optional<apdu::ApduResponse> sign_response);
-  void OnVersionComplete(VersionCallback callback,
-                         bool legacy,
-                         bool success,
-                         base::Optional<apdu::ApduResponse> version_response);
+ protected:
+  virtual base::WeakPtr<U2fDevice> GetWeakPtr() = 0;
 
   DISALLOW_COPY_AND_ASSIGN(U2fDevice);
 };
diff --git a/device/fido/u2f_hid_device.cc b/device/fido/u2f_hid_device.cc
index d705858..88df56b 100644
--- a/device/fido/u2f_hid_device.cc
+++ b/device/fido/u2f_hid_device.cc
@@ -26,7 +26,7 @@
 U2fHidDevice::U2fHidDevice(device::mojom::HidDeviceInfoPtr device_info,
                            device::mojom::HidManager* hid_manager)
     : U2fDevice(),
-      state_(State::INIT),
+      state_(State::kInit),
       hid_manager_(hid_manager),
       device_info_(std::move(device_info)),
       weak_factory_(this) {}
@@ -45,45 +45,44 @@
   auto repeating_callback =
       base::AdaptCallbackForRepeating(std::move(callback));
   switch (state_) {
-    case State::INIT:
-      state_ = State::BUSY;
+    case State::kInit:
+      state_ = State::kBusy;
       ArmTimeout(repeating_callback);
       Connect(base::BindOnce(&U2fHidDevice::OnConnect,
                              weak_factory_.GetWeakPtr(), std::move(command),
                              repeating_callback));
       break;
-    case State::CONNECTED:
-      state_ = State::BUSY;
+    case State::kConnected:
+      state_ = State::kBusy;
       ArmTimeout(repeating_callback);
       AllocateChannel(std::move(command), repeating_callback);
       break;
-    case State::IDLE: {
-      state_ = State::BUSY;
+    case State::kReady: {
+      state_ = State::kBusy;
       ArmTimeout(repeating_callback);
-      // Write message to the device
+      // Write message to the device.
       WriteMessage(
-          FidoHidMessage::Create(channel_id_, CtapHidDeviceCommand::kCtapHidMsg,
+          FidoHidMessage::Create(channel_id_, FidoHidDeviceCommand::kMsg,
                                  std::move(command)),
           true,
           base::BindOnce(&U2fHidDevice::MessageReceived,
                          weak_factory_.GetWeakPtr(), repeating_callback));
       break;
     }
-    case State::BUSY:
+    case State::kBusy:
       pending_transactions_.emplace(std::move(command), repeating_callback);
       break;
-    case State::DEVICE_ERROR:
+    case State::kDeviceError:
     default:
       base::WeakPtr<U2fHidDevice> self = weak_factory_.GetWeakPtr();
-      repeating_callback.Run(false, base::nullopt);
-
+      repeating_callback.Run(base::nullopt);
       // Executing callbacks may free |this|. Check |self| first.
       while (self && !pending_transactions_.empty()) {
-        // Respond to any pending requests
+        // Respond to any pending requests.
         DeviceCallback pending_cb =
             std::move(pending_transactions_.front().second);
         pending_transactions_.pop();
-        std::move(pending_cb).Run(false, base::nullopt);
+        std::move(pending_cb).Run(base::nullopt);
       }
       break;
   }
@@ -97,30 +96,30 @@
 void U2fHidDevice::OnConnect(std::vector<uint8_t> command,
                              DeviceCallback callback,
                              device::mojom::HidConnectionPtr connection) {
-  if (state_ == State::DEVICE_ERROR)
+  if (state_ == State::kDeviceError)
     return;
   timeout_callback_.Cancel();
 
   if (connection) {
     connection_ = std::move(connection);
-    state_ = State::CONNECTED;
+    state_ = State::kConnected;
   } else {
-    state_ = State::DEVICE_ERROR;
+    state_ = State::kDeviceError;
   }
   Transition(std::move(command), std::move(callback));
 }
 
 void U2fHidDevice::AllocateChannel(std::vector<uint8_t> command,
                                    DeviceCallback callback) {
-  // Send random nonce to device to verify received message
+  // Send random nonce to device to verify received message.
   std::vector<uint8_t> nonce(8);
   crypto::RandBytes(nonce.data(), nonce.size());
-  WriteMessage(FidoHidMessage::Create(
-                   channel_id_, CtapHidDeviceCommand::kCtapHidInit, nonce),
-               true,
-               base::BindOnce(&U2fHidDevice::OnAllocateChannel,
-                              weak_factory_.GetWeakPtr(), nonce,
-                              std::move(command), std::move(callback)));
+  WriteMessage(
+      FidoHidMessage::Create(channel_id_, FidoHidDeviceCommand::kInit, nonce),
+      true,
+      base::BindOnce(&U2fHidDevice::OnAllocateChannel,
+                     weak_factory_.GetWeakPtr(), nonce, std::move(command),
+                     std::move(callback)));
 }
 
 void U2fHidDevice::OnAllocateChannel(std::vector<uint8_t> nonce,
@@ -128,12 +127,12 @@
                                      DeviceCallback callback,
                                      bool success,
                                      std::unique_ptr<FidoHidMessage> message) {
-  if (state_ == State::DEVICE_ERROR)
+  if (state_ == State::kDeviceError)
     return;
   timeout_callback_.Cancel();
 
   if (!success || !message) {
-    state_ = State::DEVICE_ERROR;
+    state_ = State::kDeviceError;
     Transition(std::vector<uint8_t>(), std::move(callback));
     return;
   }
@@ -148,7 +147,7 @@
   // 16: Capabilities
   std::vector<uint8_t> payload = message->GetMessagePayload();
   if (payload.size() != 17) {
-    state_ = State::DEVICE_ERROR;
+    state_ = State::kDeviceError;
     Transition(std::vector<uint8_t>(), std::move(callback));
     return;
   }
@@ -172,7 +171,7 @@
   channel_id_ |= payload[index++] << 8;
   channel_id_ |= payload[index++];
   capabilities_ = payload[16];
-  state_ = State::IDLE;
+  state_ = State::kReady;
   Transition(std::move(command), std::move(callback));
 }
 
@@ -228,7 +227,7 @@
     return;
   }
 
-  // Received a message from a different channel, so try again
+  // Received a message from a different channel, so try again.
   if (channel_id_ != read_message->channel_id()) {
     connection_->Read(base::BindOnce(&U2fHidDevice::OnRead,
                                      weak_factory_.GetWeakPtr(),
@@ -241,7 +240,7 @@
     return;
   }
 
-  // Continue reading additional packets
+  // Continue reading additional packets.
   connection_->Read(base::BindOnce(
       &U2fHidDevice::OnReadContinuation, weak_factory_.GetWeakPtr(),
       std::move(read_message), std::move(callback)));
@@ -272,27 +271,24 @@
 void U2fHidDevice::MessageReceived(DeviceCallback callback,
                                    bool success,
                                    std::unique_ptr<FidoHidMessage> message) {
-  if (state_ == State::DEVICE_ERROR)
+  if (state_ == State::kDeviceError)
     return;
   timeout_callback_.Cancel();
   if (!success) {
-    state_ = State::DEVICE_ERROR;
+    state_ = State::kDeviceError;
     Transition(std::vector<uint8_t>(), std::move(callback));
     return;
   }
 
-  auto response =
-      message
-          ? apdu::ApduResponse::CreateFromMessage(message->GetMessagePayload())
-          : base::nullopt;
-
-  state_ = State::IDLE;
+  state_ = State::kReady;
   base::WeakPtr<U2fHidDevice> self = weak_factory_.GetWeakPtr();
-  std::move(callback).Run(success, std::move(response));
+  std::move(callback).Run(
+      (success && message) ? base::make_optional(message->GetMessagePayload())
+                           : base::nullopt);
 
   // Executing |callback| may have freed |this|. Check |self| first.
   if (self && !pending_transactions_.empty()) {
-    // If any transactions were queued, process the first one
+    // If any transactions were queued, process the first one.
     auto pending_cmd = std::move(pending_transactions_.front().first);
     auto pending_cb = std::move(pending_transactions_.front().second);
     pending_transactions_.pop();
@@ -301,18 +297,17 @@
 }
 
 void U2fHidDevice::TryWink(WinkCallback callback) {
-  // Only try to wink if device claims support
-  if (!(capabilities_ & kWinkCapability) || state_ != State::IDLE) {
+  // Only try to wink if device claims support.
+  if (!(capabilities_ & kWinkCapability) || state_ != State::kReady) {
     std::move(callback).Run();
     return;
   }
 
-  WriteMessage(
-      FidoHidMessage::Create(channel_id_, CtapHidDeviceCommand::kCtapHidWink,
-                             std::vector<uint8_t>()),
-      true,
-      base::BindOnce(&U2fHidDevice::OnWink, weak_factory_.GetWeakPtr(),
-                     std::move(callback)));
+  WriteMessage(FidoHidMessage::Create(channel_id_, FidoHidDeviceCommand::kWink,
+                                      std::vector<uint8_t>()),
+               true,
+               base::BindOnce(&U2fHidDevice::OnWink, weak_factory_.GetWeakPtr(),
+                              std::move(callback)));
 }
 
 void U2fHidDevice::OnWink(WinkCallback callback,
@@ -326,13 +321,13 @@
   timeout_callback_.Reset(base::BindOnce(&U2fHidDevice::OnTimeout,
                                          weak_factory_.GetWeakPtr(),
                                          std::move(callback)));
-  // Setup timeout task for 3 seconds
+  // Setup timeout task for 3 seconds.
   base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
       FROM_HERE, timeout_callback_.callback(), kDeviceTimeout);
 }
 
 void U2fHidDevice::OnTimeout(DeviceCallback callback) {
-  state_ = State::DEVICE_ERROR;
+  state_ = State::kDeviceError;
   Transition(std::vector<uint8_t>(), std::move(callback));
 }
 
diff --git a/device/fido/u2f_hid_device.h b/device/fido/u2f_hid_device.h
index 4ee250329..a42e6a6 100644
--- a/device/fido/u2f_hid_device.h
+++ b/device/fido/u2f_hid_device.h
@@ -11,9 +11,12 @@
 #include <utility>
 #include <vector>
 
+#include "base/callback.h"
 #include "base/cancelable_callback.h"
 #include "base/component_export.h"
 #include "base/macros.h"
+#include "components/apdu/apdu_command.h"
+#include "components/apdu/apdu_response.h"
 #include "device/fido/u2f_device.h"
 #include "services/device/public/mojom/hid.mojom.h"
 
@@ -27,40 +30,39 @@
                device::mojom::HidManager* hid_manager);
   ~U2fHidDevice() final;
 
-  // Send a U2f command to this device
+  // Send a command to this device.
   void DeviceTransact(std::vector<uint8_t> command,
                       DeviceCallback callback) final;
-  // Send a wink command if supported
+  // Send a wink command if supported.
   void TryWink(WinkCallback callback) final;
-  // Use a string identifier to compare to other devices
+  // Use a string identifier to compare to other devices.
   std::string GetId() const final;
-  // Get a string identifier for a given device info
+
+  // Get a string identifier for a given device info.
   static std::string GetIdForDevice(
       const device::mojom::HidDeviceInfo& device_info);
-  // Command line flag to enable tests on actual U2f HID hardware
+  // Command line flag to enable tests on actual HID hardware.
   static bool IsTestEnabled();
 
  private:
   FRIEND_TEST_ALL_PREFIXES(U2fHidDeviceTest, TestConnectionFailure);
   FRIEND_TEST_ALL_PREFIXES(U2fHidDeviceTest, TestDeviceError);
+  FRIEND_TEST_ALL_PREFIXES(U2fHidDeviceTest, TestRetryChannelAllocation);
 
   static constexpr uint8_t kWinkCapability = 0x01;
   static constexpr uint8_t kLockCapability = 0x02;
   static constexpr uint32_t kBroadcastChannel = 0xffffffff;
 
-  // Internal state machine states
-  enum class State { INIT, CONNECTED, BUSY, IDLE, DEVICE_ERROR };
-
   using U2fHidMessageCallback =
       base::OnceCallback<void(bool, std::unique_ptr<FidoHidMessage>)>;
   using ConnectCallback = device::mojom::HidManager::ConnectCallback;
 
-  // Open a connection to this device
+  // Open a connection to this device.
   void Connect(ConnectCallback callback);
   void OnConnect(std::vector<uint8_t> command,
                  DeviceCallback callback,
                  device::mojom::HidConnectionPtr connection);
-  // Ask device to allocate a unique channel id for this connection
+  // Ask device to allocate a unique channel id for this connection.
   void AllocateChannel(std::vector<uint8_t> command, DeviceCallback callback);
   void OnAllocateChannel(std::vector<uint8_t> nonce,
                          std::vector<uint8_t> command,
@@ -68,7 +70,7 @@
                          bool success,
                          std::unique_ptr<FidoHidMessage> message);
   void Transition(std::vector<uint8_t> command, DeviceCallback callback);
-  // Write all message packets to device, and read response if expected
+  // Write all message packets to device, and read response if expected.
   void WriteMessage(std::unique_ptr<FidoHidMessage> message,
                     bool response_expected,
                     U2fHidMessageCallback callback);
@@ -76,7 +78,7 @@
                      bool response_expected,
                      U2fHidMessageCallback callback,
                      bool success);
-  // Read all response message packets from device
+  // Read all response message packets from device.
   void ReadMessage(U2fHidMessageCallback callback);
   void MessageReceived(DeviceCallback callback,
                        bool success,
@@ -95,13 +97,11 @@
               std::unique_ptr<FidoHidMessage> response);
   void ArmTimeout(DeviceCallback callback);
   void OnTimeout(DeviceCallback callback);
-  void OnDeviceTransact(bool success,
-                        base::Optional<apdu::ApduResponse> response);
   base::WeakPtr<U2fDevice> GetWeakPtr() override;
 
   uint32_t channel_id_ = kBroadcastChannel;
   uint8_t capabilities_ = 0;
-  State state_ = State::INIT;
+  State state_ = State::kInit;
 
   base::CancelableOnceClosure timeout_callback_;
   std::queue<std::pair<std::vector<uint8_t>, DeviceCallback>>
diff --git a/device/fido/u2f_hid_device_unittest.cc b/device/fido/u2f_hid_device_unittest.cc
index eb6e155..4e2d5f3 100644
--- a/device/fido/u2f_hid_device_unittest.cc
+++ b/device/fido/u2f_hid_device_unittest.cc
@@ -9,13 +9,12 @@
 #include "base/memory/ptr_util.h"
 #include "base/run_loop.h"
 #include "base/strings/string_number_conversions.h"
-#include "base/test/scoped_mock_time_message_loop_task_runner.h"
 #include "base/test/scoped_task_environment.h"
 #include "components/apdu/apdu_command.h"
 #include "components/apdu/apdu_response.h"
 #include "device/fido/fake_hid_impl_for_testing.h"
+#include "device/fido/fido_constants.h"
 #include "device/fido/test_callback_receiver.h"
-#include "device/fido/u2f_command_type.h"
 #include "device/fido/u2f_hid_device.h"
 #include "device/fido/u2f_request.h"
 #include "mojo/public/cpp/bindings/binding.h"
@@ -54,11 +53,10 @@
 }
 
 // Returns HID_INIT request to send to device with mock connection.
-std::vector<uint8_t> CreateMockHidInitResponse(
-    std::vector<uint8_t> nonce,
-    std::vector<uint8_t> channel_id) {
+std::vector<uint8_t> CreateMockInitResponse(std::vector<uint8_t> nonce,
+                                            std::vector<uint8_t> channel_id) {
   // 4 bytes of broadcast channel identifier(ffffffff), followed by
-  // HID_INIT command(86) and 2 byte payload length(11)
+  // HID_INIT command(86) and 2 byte payload length(11).
   return MakePacket("ffffffff860011" + HexEncode(nonce) +
                     HexEncode(channel_id));
 }
@@ -71,12 +69,12 @@
   return MakePacket(HexEncode(channel_id) + "8300085532465f56329000");
 }
 
-// Returns a failure mock response to version request with given channel id.
-std::vector<uint8_t> CreateFailureMockVersionResponse(
-    std::vector<uint8_t> channel_id) {
-  // HID_MSG command(83), followed by payload length(0002), followed by
-  // an invalid class response code (6E00).
-  return MakePacket(HexEncode(channel_id) + "8300026E00");
+// Returns U2F_V2 version response formatted in APDU response encoding.
+std::vector<uint8_t> GetValidU2fVersionResponse() {
+  return apdu::ApduResponse(std::vector<uint8_t>(kU2fVersionResponse.begin(),
+                                                 kU2fVersionResponse.end()),
+                            apdu::ApduResponse::Status::SW_NO_ERROR)
+      .GetEncodedResponse();
 }
 
 device::mojom::HidDeviceInfoPtr TestHidDevice() {
@@ -122,10 +120,8 @@
   DISALLOW_COPY_AND_ASSIGN(U2fDeviceEnumerateCallbackReceiver);
 };
 
-using TestVersionCallbackReceiver =
-    test::StatusAndValueCallbackReceiver<bool, U2fDevice::ProtocolVersion>;
-using TestDeviceCallbackReceiver = ::device::test::
-    StatusAndValueCallbackReceiver<bool, base::Optional<apdu::ApduResponse>>;
+using TestDeviceCallbackReceiver =
+    ::device::test::TestCallbackReceiver<base::Optional<std::vector<uint8_t>>>;
 
 }  // namespace
 
@@ -146,43 +142,6 @@
   base::test::ScopedTaskEnvironment scoped_task_environment_;
 };
 
-TEST_F(U2fHidDeviceTest, TestHidDeviceVersion) {
-  if (!U2fHidDevice::IsTestEnabled())
-    return;
-
-  U2fDeviceEnumerateCallbackReceiver receiver(hid_manager_.get());
-  hid_manager_->GetDevices(receiver.callback());
-  receiver.WaitForCallback();
-
-  for (auto& device : receiver.TakeReturnedDevicesFiltered()) {
-    TestVersionCallbackReceiver vc;
-    device->Version(vc.callback());
-    vc.WaitForCallback();
-    EXPECT_EQ(U2fDevice::ProtocolVersion::U2F_V2, vc.value());
-  }
-}
-
-TEST_F(U2fHidDeviceTest, TestMultipleRequests) {
-  if (!U2fHidDevice::IsTestEnabled())
-    return;
-
-  U2fDeviceEnumerateCallbackReceiver receiver(hid_manager_.get());
-  hid_manager_->GetDevices(receiver.callback());
-  receiver.WaitForCallback();
-
-  for (auto& device : receiver.TakeReturnedDevicesFiltered()) {
-    TestVersionCallbackReceiver vc;
-    TestVersionCallbackReceiver vc2;
-    // Call version twice to check message queueing.
-    device->Version(vc.callback());
-    device->Version(vc2.callback());
-    vc.WaitForCallback();
-    EXPECT_EQ(U2fDevice::ProtocolVersion::U2F_V2, vc.value());
-    vc2.WaitForCallback();
-    EXPECT_EQ(U2fDevice::ProtocolVersion::U2F_V2, vc2.value());
-  }
-}
-
 TEST_F(U2fHidDeviceTest, TestConnectionFailure) {
   // Setup and enumerate mock device.
   U2fDeviceEnumerateCallbackReceiver receiver(hid_manager_.get());
@@ -197,7 +156,7 @@
   ASSERT_EQ(static_cast<size_t>(1), u2f_devices.size());
   auto& device = u2f_devices.front();
   // Put device in IDLE state.
-  device->state_ = U2fHidDevice::State::IDLE;
+  device->state_ = U2fDevice::State::kReady;
 
   // Manually delete connection.
   device->connection_ = nullptr;
@@ -213,10 +172,11 @@
   device->DeviceTransact(U2fRequest::GetU2fVersionApduCommand(),
                          receiver_3.callback());
 
-  EXPECT_EQ(U2fHidDevice::State::DEVICE_ERROR, device->state_);
-  EXPECT_EQ(base::nullopt, receiver_1.value());
-  EXPECT_EQ(base::nullopt, receiver_2.value());
-  EXPECT_EQ(base::nullopt, receiver_3.value());
+  EXPECT_EQ(U2fDevice::State::kDeviceError, device->state_);
+
+  EXPECT_FALSE(std::get<0>(*receiver_1.result()));
+  EXPECT_FALSE(std::get<0>(*receiver_2.result()));
+  EXPECT_FALSE(std::get<0>(*receiver_3.result()));
 }
 
 TEST_F(U2fHidDeviceTest, TestDeviceError) {
@@ -236,13 +196,13 @@
 
   // Mock connection where writes always fail.
   FakeHidConnection::mock_connection_error_ = true;
-  device->state_ = U2fHidDevice::State::IDLE;
+  device->state_ = U2fDevice::State::kReady;
 
   TestDeviceCallbackReceiver receiver_0;
   device->DeviceTransact(U2fRequest::GetU2fVersionApduCommand(),
                          receiver_0.callback());
-  EXPECT_EQ(base::nullopt, receiver_0.value());
-  EXPECT_EQ(U2fHidDevice::State::DEVICE_ERROR, device->state_);
+  EXPECT_FALSE(std::get<0>(*receiver_0.result()));
+  EXPECT_EQ(U2fDevice::State::kDeviceError, device->state_);
 
   // Add pending transactions manually and ensure they are processed.
   // Add pending transactions manually and ensure they are processed.
@@ -257,85 +217,10 @@
                          receiver_3.callback());
   FakeHidConnection::mock_connection_error_ = false;
 
-  EXPECT_EQ(U2fHidDevice::State::DEVICE_ERROR, device->state_);
-  EXPECT_EQ(base::nullopt, receiver_1.value());
-  EXPECT_EQ(base::nullopt, receiver_2.value());
-  EXPECT_EQ(base::nullopt, receiver_3.value());
-}
-
-TEST_F(U2fHidDeviceTest, TestLegacyVersion) {
-  const std::vector<uint8_t> kChannelId = {0x01, 0x02, 0x03, 0x04};
-
-  auto hid_device = TestHidDevice();
-
-  // Replace device HID connection with custom client connection bound to mock
-  // server-side mojo connection.
-  device::mojom::HidConnectionPtr connection_client;
-  MockHidConnection mock_connection(
-      hid_device.Clone(), mojo::MakeRequest(&connection_client), kChannelId);
-
-  // Delegate custom functions to be invoked for mock hid connection.
-  EXPECT_CALL(mock_connection, WritePtr(_, _, _))
-      // HID_INIT request to authenticator for channel allocation.
-      .WillOnce(WithArgs<1, 2>(
-          Invoke([&](const std::vector<uint8_t>& buffer,
-                     device::mojom::HidConnection::WriteCallback* cb) {
-            mock_connection.SetNonce(base::make_span(buffer).subspan(7, 8));
-            std::move(*cb).Run(true);
-          })))
-
-      // HID_MSG request to authenticator for version request.
-      .WillOnce(WithArgs<2>(
-          Invoke([](device::mojom::HidConnection::WriteCallback* cb) {
-            std::move(*cb).Run(true);
-          })))
-
-      .WillOnce(WithArgs<2>(
-          Invoke([](device::mojom::HidConnection::WriteCallback* cb) {
-            std::move(*cb).Run(true);
-          })));
-
-  EXPECT_CALL(mock_connection, ReadPtr(_))
-      // Response to HID_INIT request with correct nonce.
-      .WillOnce(WithArg<0>(Invoke(
-          [&mock_connection](device::mojom::HidConnection::ReadCallback* cb) {
-            std::move(*cb).Run(true, 0,
-                               CreateMockHidInitResponse(
-                                   mock_connection.nonce(),
-                                   mock_connection.connection_channel_id()));
-          })))
-      // Invalid version response from the authenticator.
-      .WillOnce(WithArg<0>(Invoke(
-          [&mock_connection](device::mojom::HidConnection::ReadCallback* cb) {
-            std::move(*cb).Run(true, 0,
-                               CreateFailureMockVersionResponse(
-                                   mock_connection.connection_channel_id()));
-          })))
-      // Legacy version response from the authenticator.
-      .WillOnce(WithArg<0>(Invoke(
-          [&mock_connection](device::mojom::HidConnection::ReadCallback* cb) {
-            std::move(*cb).Run(true, 0,
-                               CreateMockVersionResponse(
-                                   mock_connection.connection_channel_id()));
-          })));
-
-  // Add device and set mock connection to fake hid manager.
-  fake_hid_manager_->AddDeviceAndSetConnection(std::move(hid_device),
-                                               std::move(connection_client));
-
-  U2fDeviceEnumerateCallbackReceiver receiver(hid_manager_.get());
-  hid_manager_->GetDevices(receiver.callback());
-  receiver.WaitForCallback();
-
-  std::vector<std::unique_ptr<U2fHidDevice>> u2f_devices =
-      receiver.TakeReturnedDevicesFiltered();
-
-  ASSERT_EQ(1u, u2f_devices.size());
-  auto& device = u2f_devices.front();
-  TestVersionCallbackReceiver vc;
-  device->Version(vc.callback());
-  vc.WaitForCallback();
-  EXPECT_EQ(U2fDevice::ProtocolVersion::U2F_V2, vc.value());
+  EXPECT_EQ(U2fDevice::State::kDeviceError, device->state_);
+  EXPECT_FALSE(std::get<0>(*receiver_1.result()));
+  EXPECT_FALSE(std::get<0>(*receiver_2.result()));
+  EXPECT_FALSE(std::get<0>(*receiver_3.result()));
 }
 
 TEST_F(U2fHidDeviceTest, TestRetryChannelAllocation) {
@@ -375,14 +260,14 @@
                      device::mojom::HidConnection::ReadCallback* cb) {
             std::move(*cb).Run(
                 true, 0,
-                CreateMockHidInitResponse(
+                CreateMockInitResponse(
                     kIncorrectNonce, mock_connection.connection_channel_id()));
           })))
       // Second response to HID_INIT request with correct nonce.
       .WillOnce(WithArg<0>(Invoke(
           [&mock_connection](device::mojom::HidConnection::ReadCallback* cb) {
             std::move(*cb).Run(true, 0,
-                               CreateMockHidInitResponse(
+                               CreateMockInitResponse(
                                    mock_connection.nonce(),
                                    mock_connection.connection_channel_id()));
           })))
@@ -407,10 +292,15 @@
 
   ASSERT_EQ(1u, u2f_devices.size());
   auto& device = u2f_devices.front();
-  TestVersionCallbackReceiver vc;
-  device->Version(vc.callback());
-  vc.WaitForCallback();
-  EXPECT_EQ(U2fDevice::ProtocolVersion::U2F_V2, vc.value());
+
+  TestDeviceCallbackReceiver cb;
+  device->DeviceTransact(U2fRequest::GetU2fVersionApduCommand(false),
+                         cb.callback());
+  cb.WaitForCallback();
+
+  const auto& result = std::get<0>(*cb.result());
+  ASSERT_TRUE(result);
+  EXPECT_THAT(*result, testing::ElementsAreArray(GetValidU2fVersionResponse()));
 }
 
 }  // namespace device
diff --git a/device/fido/u2f_register.cc b/device/fido/u2f_register.cc
index 3081737c..e743fbf 100644
--- a/device/fido/u2f_register.cc
+++ b/device/fido/u2f_register.cc
@@ -7,6 +7,8 @@
 #include <utility>
 
 #include "base/stl_util.h"
+#include "components/apdu/apdu_command.h"
+#include "components/apdu/apdu_response.h"
 #include "device/fido/register_response_data.h"
 #include "services/service_manager/public/cpp/connector.h"
 
@@ -51,12 +53,13 @@
   DCHECK(current_device_);
   if (!registered_keys_.empty() && !CheckedForDuplicateRegistration()) {
     auto it = registered_keys_.cbegin();
-    current_device_->Sign(GetU2fSignApduCommand(application_parameter_, *it,
-                                                true /* check_only */),
-                          base::BindOnce(&U2fRegister::OnTryCheckRegistration,
-                                         weak_factory_.GetWeakPtr(), it));
+    InitiateDeviceTransaction(
+        GetU2fSignApduCommand(application_parameter_, *it,
+                              true /* check_only */),
+        base::BindOnce(&U2fRegister::OnTryCheckRegistration,
+                       weak_factory_.GetWeakPtr(), it));
   } else {
-    current_device_->Register(
+    InitiateDeviceTransaction(
         GetU2fRegisterApduCommand(individual_attestation_ok_),
         base::BindOnce(&U2fRegister::OnTryDevice, weak_factory_.GetWeakPtr(),
                        false /* is_duplicate_registration */));
@@ -65,24 +68,30 @@
 
 void U2fRegister::OnTryCheckRegistration(
     std::vector<std::vector<uint8_t>>::const_iterator it,
-    U2fReturnCode return_code,
-    const std::vector<uint8_t>& response_data) {
+    base::Optional<std::vector<uint8_t>> response) {
+  const auto apdu_response =
+      response ? apdu::ApduResponse::CreateFromMessage(std::move(*response))
+               : base::nullopt;
+  auto return_code = apdu_response ? apdu_response->status()
+                                   : apdu::ApduResponse::Status::SW_WRONG_DATA;
+
   switch (return_code) {
-    case U2fReturnCode::SUCCESS:
-    case U2fReturnCode::CONDITIONS_NOT_SATISFIED:
+    case apdu::ApduResponse::Status::SW_NO_ERROR:
+    case apdu::ApduResponse::Status::SW_CONDITIONS_NOT_SATISFIED: {
       // Duplicate registration found. Call bogus registration to check for
       // user presence (touch) and terminate the registration process.
-      current_device_->Register(
+      InitiateDeviceTransaction(
           U2fRequest::GetBogusRegisterCommand(),
           base::BindOnce(&U2fRegister::OnTryDevice, weak_factory_.GetWeakPtr(),
                          true /* is_duplicate_registration */));
       break;
+    }
 
-    case U2fReturnCode::INVALID_PARAMS:
+    case apdu::ApduResponse::Status::SW_WRONG_DATA:
       // Continue to iterate through the provided key handles in the exclude
       // list and check for already registered keys.
       if (++it != registered_keys_.end()) {
-        current_device_->Sign(
+        InitiateDeviceTransaction(
             GetU2fSignApduCommand(application_parameter_, *it,
                                   true /* check_only */),
             base::BindOnce(&U2fRegister::OnTryCheckRegistration,
@@ -122,10 +131,14 @@
 }
 
 void U2fRegister::OnTryDevice(bool is_duplicate_registration,
-                              U2fReturnCode return_code,
-                              const std::vector<uint8_t>& response_data) {
+                              base::Optional<std::vector<uint8_t>> response) {
+  const auto apdu_response =
+      response ? apdu::ApduResponse::CreateFromMessage(std::move(*response))
+               : base::nullopt;
+  auto return_code = apdu_response ? apdu_response->status()
+                                   : apdu::ApduResponse::Status::SW_WRONG_DATA;
   switch (return_code) {
-    case U2fReturnCode::SUCCESS: {
+    case apdu::ApduResponse::Status::SW_NO_ERROR: {
       state_ = State::COMPLETE;
       if (is_duplicate_registration) {
         std::move(completion_callback_)
@@ -133,7 +146,7 @@
         break;
       }
       auto response = RegisterResponseData::CreateFromU2fRegisterResponse(
-          application_parameter_, std::move(response_data));
+          application_parameter_, apdu_response->data());
       if (!response) {
         // The response data was corrupted / didn't parse properly.
         std::move(completion_callback_)
@@ -144,7 +157,7 @@
           .Run(U2fReturnCode::SUCCESS, std::move(response));
       break;
     }
-    case U2fReturnCode::CONDITIONS_NOT_SATISFIED:
+    case apdu::ApduResponse::Status::SW_CONDITIONS_NOT_SATISFIED:
       // Waiting for user touch, move on and try this device later.
       state_ = State::IDLE;
       Transition();
diff --git a/device/fido/u2f_register.h b/device/fido/u2f_register.h
index 3d7262e1..f04a94a 100644
--- a/device/fido/u2f_register.h
+++ b/device/fido/u2f_register.h
@@ -15,6 +15,7 @@
 #include "base/macros.h"
 #include "base/optional.h"
 #include "device/fido/u2f_request.h"
+#include "device/fido/u2f_return_code.h"
 #include "device/fido/u2f_transport_protocol.h"
 
 namespace service_manager {
@@ -50,20 +51,16 @@
   ~U2fRegister() override;
 
  private:
-  FRIEND_TEST_ALL_PREFIXES(U2fRegisterTest, TestCreateU2fRegisterCommand);
-
   void TryDevice() override;
   void OnTryDevice(bool is_duplicate_registration,
-                   U2fReturnCode return_code,
-                   const std::vector<uint8_t>& response_data);
+                   base::Optional<std::vector<uint8_t>> response);
 
   // Callback function called when non-empty exclude list was provided. This
   // function iterates through all key handles in |registered_keys_| for all
   // devices and checks for already registered keys.
   void OnTryCheckRegistration(
       std::vector<std::vector<uint8_t>>::const_iterator it,
-      U2fReturnCode return_code,
-      const std::vector<uint8_t>& response_data);
+      base::Optional<std::vector<uint8_t>> response);
   // Function handling registration flow after all devices were checked for
   // already registered keys.
   void CompleteNewDeviceRegistration();
diff --git a/device/fido/u2f_register_unittest.cc b/device/fido/u2f_register_unittest.cc
index e0246ae..de346f6 100644
--- a/device/fido/u2f_register_unittest.cc
+++ b/device/fido/u2f_register_unittest.cc
@@ -439,6 +439,7 @@
 
   register_callback_receiver().WaitForCallback();
   EXPECT_EQ(U2fReturnCode::SUCCESS, register_callback_receiver().status());
+  ASSERT_TRUE(register_callback_receiver().value());
   EXPECT_EQ(GetTestCredentialRawIdBytes(),
             register_callback_receiver().value()->raw_id());
 }
@@ -455,6 +456,7 @@
   EXPECT_EQ(U2fReturnCode::SUCCESS, register_callback_receiver().status());
 
   // We don't verify the response from the fake, but do a quick sanity check.
+  ASSERT_TRUE(register_callback_receiver().value());
   EXPECT_EQ(32ul, register_callback_receiver().value()->raw_id().size());
 }
 
@@ -476,6 +478,7 @@
 
   register_callback_receiver().WaitForCallback();
   EXPECT_EQ(U2fReturnCode::SUCCESS, register_callback_receiver().status());
+  ASSERT_TRUE(register_callback_receiver().value());
   EXPECT_EQ(GetTestCredentialRawIdBytes(),
             register_callback_receiver().value()->raw_id());
 }
@@ -506,6 +509,7 @@
 
   register_callback_receiver().WaitForCallback();
   EXPECT_EQ(U2fReturnCode::SUCCESS, register_callback_receiver().status());
+  ASSERT_TRUE(register_callback_receiver().value());
   EXPECT_EQ(GetTestCredentialRawIdBytes(),
             register_callback_receiver().value()->raw_id());
 }
@@ -544,6 +548,7 @@
 
   register_callback_receiver().WaitForCallback();
   EXPECT_EQ(U2fReturnCode::SUCCESS, register_callback_receiver().status());
+  ASSERT_TRUE(register_callback_receiver().value());
   EXPECT_EQ(GetTestCredentialRawIdBytes(),
             register_callback_receiver().value()->raw_id());
 }
@@ -596,6 +601,7 @@
 
   register_callback_receiver().WaitForCallback();
   EXPECT_EQ(U2fReturnCode::SUCCESS, register_callback_receiver().status());
+  ASSERT_TRUE(register_callback_receiver().value());
   EXPECT_EQ(GetTestCredentialRawIdBytes(),
             register_callback_receiver().value()->raw_id());
 }
@@ -637,7 +643,7 @@
   register_callback_receiver().WaitForCallback();
   EXPECT_EQ(U2fReturnCode::CONDITIONS_NOT_SATISFIED,
             register_callback_receiver().status());
-  EXPECT_EQ(base::nullopt, register_callback_receiver().value());
+  EXPECT_FALSE(register_callback_receiver().value());
 }
 
 // Tests a scenario where one (device1) of the two devices connected has created
@@ -689,7 +695,7 @@
   register_callback_receiver().WaitForCallback();
   EXPECT_EQ(U2fReturnCode::CONDITIONS_NOT_SATISFIED,
             register_callback_receiver().status());
-  EXPECT_EQ(base::nullopt, register_callback_receiver().value());
+  EXPECT_FALSE(register_callback_receiver().value());
 }
 
 // These test the parsing of the U2F raw bytes of the registration response.
@@ -825,6 +831,7 @@
 
     cb.WaitForCallback();
     EXPECT_EQ(U2fReturnCode::SUCCESS, cb.status());
+    ASSERT_TRUE(cb.value());
     EXPECT_EQ(GetTestCredentialRawIdBytes(), cb.value()->raw_id());
   }
 }
diff --git a/device/fido/u2f_request.cc b/device/fido/u2f_request.cc
index 3f7581d..817eb8c 100644
--- a/device/fido/u2f_request.cc
+++ b/device/fido/u2f_request.cc
@@ -13,6 +13,7 @@
 #include "base/threading/thread_task_runner_handle.h"
 #include "build/build_config.h"
 #include "components/apdu/apdu_command.h"
+#include "components/apdu/apdu_response.h"
 #include "services/service_manager/public/cpp/connector.h"
 
 namespace device {
@@ -119,7 +120,7 @@
     case State::IDLE:
       IterateDevice();
       if (!current_device_) {
-        // No devices available
+        // No devices available.
         state_ = State::OFF;
         break;
       }
@@ -136,6 +137,41 @@
   }
 }
 
+void U2fRequest::InitiateDeviceTransaction(
+    base::Optional<std::vector<uint8_t>> cmd,
+    U2fDevice::DeviceCallback callback) {
+  if (!cmd) {
+    std::move(callback).Run(base::nullopt);
+    return;
+  }
+  current_device_->DeviceTransact(std::move(*cmd), std::move(callback));
+}
+
+void U2fRequest::OnDeviceVersionRequest(
+    VersionCallback callback,
+    base::WeakPtr<U2fDevice> device,
+    bool legacy,
+    base::Optional<std::vector<uint8_t>> response) {
+  const auto apdu_response =
+      response ? apdu::ApduResponse::CreateFromMessage(std::move(*response))
+               : base::nullopt;
+  if (apdu_response &&
+      apdu_response->status() == apdu::ApduResponse::Status::SW_NO_ERROR &&
+      std::equal(apdu_response->data().cbegin(), apdu_response->data().cend(),
+                 kU2fVersionResponse.cbegin(), kU2fVersionResponse.cend())) {
+    std::move(callback).Run(ProtocolVersion::kU2f);
+  } else if (!legacy) {
+    // Standard GetVersion failed, attempt legacy GetVersion command.
+    device->DeviceTransact(
+        GetU2fVersionApduCommand(true),
+        base::BindOnce(&U2fRequest::OnDeviceVersionRequest,
+                       weak_factory_.GetWeakPtr(), std::move(callback), device,
+                       true /* legacy */));
+  } else {
+    std::move(callback).Run(ProtocolVersion::kUnknown);
+  }
+}
+
 void U2fRequest::DiscoveryStarted(U2fDiscovery* discovery, bool success) {
   if (success) {
     // The discovery might know about devices that have already been added to
@@ -215,7 +251,7 @@
     devices_.pop_front();
   } else if (attempted_devices_.size() > 0) {
     devices_ = std::move(attempted_devices_);
-    // After trying every device, wait 200ms before trying again
+    // After trying every device, wait 200ms before trying again.
     delay_callback_.Reset(
         base::Bind(&U2fRequest::OnWaitComplete, weak_factory_.GetWeakPtr()));
     base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
diff --git a/device/fido/u2f_request.h b/device/fido/u2f_request.h
index 696e8c0..88e4f99 100644
--- a/device/fido/u2f_request.h
+++ b/device/fido/u2f_request.h
@@ -5,6 +5,8 @@
 #ifndef DEVICE_FIDO_U2F_REQUEST_H_
 #define DEVICE_FIDO_U2F_REQUEST_H_
 
+#include <stdint.h>
+
 #include <list>
 #include <memory>
 #include <string>
@@ -28,6 +30,8 @@
 
 class COMPONENT_EXPORT(DEVICE_FIDO) U2fRequest : public U2fDiscovery::Observer {
  public:
+  using VersionCallback = base::OnceCallback<void(ProtocolVersion version)>;
+
   // U2fRequest will create a discovery instance and register itself as an
   // observer for each passed in transport protocol.
   // TODO(https://crbug.com/769631): Remove the dependency on Connector once U2F
@@ -68,6 +72,17 @@
 
   void Transition();
 
+  // Starts sign, register, and version request transaction on
+  // |current_device_|.
+  void InitiateDeviceTransaction(base::Optional<std::vector<uint8_t>> cmd,
+                                 U2fDevice::DeviceCallback callback);
+  // Callback function to U2F version request. If non-legacy version request
+  // fails, retry with legacy version request.
+  void OnDeviceVersionRequest(VersionCallback callback,
+                              base::WeakPtr<U2fDevice> device,
+                              bool legacy,
+                              base::Optional<std::vector<uint8_t>> response);
+
   virtual void TryDevice() = 0;
 
   // Hold handles to the devices known to the system. Known devices are
@@ -94,6 +109,7 @@
   FRIEND_TEST_ALL_PREFIXES(U2fRequestTest, TestMultipleDiscoveries);
   FRIEND_TEST_ALL_PREFIXES(U2fRequestTest, TestSlowDiscovery);
   FRIEND_TEST_ALL_PREFIXES(U2fRequestTest, TestMultipleDiscoveriesWithFailures);
+  FRIEND_TEST_ALL_PREFIXES(U2fRequestTest, TestLegacyVersionRequest);
 
   // U2fDiscovery::Observer
   void DiscoveryStarted(U2fDiscovery* discovery, bool success) override;
diff --git a/device/fido/u2f_request_unittest.cc b/device/fido/u2f_request_unittest.cc
index 57b4422..f57a9c09 100644
--- a/device/fido/u2f_request_unittest.cc
+++ b/device/fido/u2f_request_unittest.cc
@@ -9,6 +9,7 @@
 #include "base/test/scoped_task_environment.h"
 #include "device/fido/fake_u2f_discovery.h"
 #include "device/fido/mock_u2f_device.h"
+#include "device/fido/test_callback_receiver.h"
 #include "device/fido/u2f_request.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -34,6 +35,9 @@
   }
 };
 
+using TestVersionCallback =
+    ::device::test::TestCallbackReceiver<ProtocolVersion>;
+
 }  // namespace
 
 class U2fRequestTest : public ::testing::Test {
@@ -46,10 +50,15 @@
     return discovery_factory_;
   }
 
+  TestVersionCallback& version_callback_receiver() {
+    return version_callback_receiver_;
+  }
+
  private:
   base::test::ScopedTaskEnvironment scoped_task_environment_{
       base::test::ScopedTaskEnvironment::MainThreadType::MOCK_TIME};
   test::ScopedFakeU2fDiscoveryFactory discovery_factory_;
+  TestVersionCallback version_callback_receiver_;
 };
 
 TEST_F(U2fRequestTest, TestIterateDevice) {
@@ -336,4 +345,34 @@
               ::testing::ElementsAreArray(kEncodedU2fLegacyVersionRequest));
 }
 
+// Test a scenario when version request is sent to legacy U2F token.
+// After non-legacy version requests fails, legacy version request should be
+// sent to device as a retry.
+TEST_F(U2fRequestTest, TestLegacyVersionRequest) {
+  auto* discovery = discovery_factory().ForgeNextHidDiscovery();
+  FakeU2fRequest request({U2fTransportProtocol::kUsbHumanInterfaceDevice});
+  request.Start();
+
+  auto device0 = std::make_unique<MockU2fDevice>();
+  EXPECT_CALL(*device0, GetId()).WillRepeatedly(::testing::Return("device0"));
+  EXPECT_CALL(*device0,
+              DeviceTransactPtr(U2fRequest::GetU2fVersionApduCommand(true), _))
+      // Success response for legacy version request after retry.
+      .WillOnce(testing::Invoke(MockU2fDevice::NoErrorVersion));
+
+  auto* device_ptr = device0.get();
+  discovery->AddDevice(std::move(device0));
+
+  // Represents version callback received from legacy U2F token on initial
+  // version request. Device responses with invalid protocol version (in this
+  // case, empty byte array). Retry version request with legacy bit is expected
+  // to be issued afterwards.
+  request.OnDeviceVersionRequest(version_callback_receiver().callback(),
+                                 device_ptr->GetWeakPtr(), false /* legacy */,
+                                 std::vector<uint8_t>());
+
+  EXPECT_EQ(ProtocolVersion::kU2f,
+            std::get<0>(*version_callback_receiver().result()));
+}
+
 }  // namespace device
diff --git a/device/fido/u2f_sign.cc b/device/fido/u2f_sign.cc
index bb5b681a..c4d5f298 100644
--- a/device/fido/u2f_sign.cc
+++ b/device/fido/u2f_sign.cc
@@ -6,6 +6,8 @@
 
 #include <utility>
 
+#include "components/apdu/apdu_command.h"
+#include "components/apdu/apdu_response.h"
 #include "services/service_manager/public/cpp/connector.h"
 
 namespace device {
@@ -65,7 +67,7 @@
   // https://fidoalliance.org/specs/fido-v2.0-ps-20170927/fido-client-to-authenticator-protocol-v2.0-ps-20170927.html
   if (registered_keys_.size() == 0) {
     // Send registration (Fake enroll) if no keys were provided.
-    current_device_->Register(
+    InitiateDeviceTransaction(
         U2fRequest::GetBogusRegisterCommand(),
         base::BindOnce(&U2fSign::OnTryDevice, weak_factory_.GetWeakPtr(),
                        registered_keys_.cend(),
@@ -74,18 +76,26 @@
   }
   // Try signing current device with the first registered key.
   auto it = registered_keys_.cbegin();
-  current_device_->Sign(
+  InitiateDeviceTransaction(
       GetU2fSignApduCommand(application_parameter_, *it),
-      base::Bind(&U2fSign::OnTryDevice, weak_factory_.GetWeakPtr(), it,
-                 ApplicationParameterType::kPrimary));
+      base::BindOnce(&U2fSign::OnTryDevice, weak_factory_.GetWeakPtr(), it,
+                     ApplicationParameterType::kPrimary));
 }
 
 void U2fSign::OnTryDevice(std::vector<std::vector<uint8_t>>::const_iterator it,
                           ApplicationParameterType application_parameter_type,
-                          U2fReturnCode return_code,
-                          const std::vector<uint8_t>& response_data) {
+                          base::Optional<std::vector<uint8_t>> response) {
+  const auto apdu_response =
+      response ? apdu::ApduResponse::CreateFromMessage(std::move(*response))
+               : base::nullopt;
+  auto return_code = apdu_response ? apdu_response->status()
+                                   : apdu::ApduResponse::Status::SW_WRONG_DATA;
+  auto response_data = return_code == apdu::ApduResponse::Status::SW_WRONG_DATA
+                           ? std::vector<uint8_t>()
+                           : apdu_response->data();
+
   switch (return_code) {
-    case U2fReturnCode::SUCCESS: {
+    case apdu::ApduResponse::Status::SW_NO_ERROR: {
       state_ = State::COMPLETE;
       if (it == registered_keys_.cend()) {
         // This was a response to a fake enrollment. Return an empty key handle.
@@ -108,33 +118,34 @@
       }
       break;
     }
-    case U2fReturnCode::CONDITIONS_NOT_SATISFIED: {
+    case apdu::ApduResponse::Status::SW_CONDITIONS_NOT_SATISFIED: {
       // Key handle is accepted by this device, but waiting on user touch. Move
       // on and try this device again later.
       state_ = State::IDLE;
       Transition();
       break;
     }
-    case U2fReturnCode::INVALID_PARAMS: {
+    case apdu::ApduResponse::Status::SW_WRONG_DATA:
+    case apdu::ApduResponse::Status::SW_WRONG_LENGTH: {
       if (application_parameter_type == ApplicationParameterType::kPrimary &&
           alt_application_parameter_) {
         // |application_parameter_| failed, but there is also
         // |alt_application_parameter_| to try.
-        current_device_->Sign(
+        InitiateDeviceTransaction(
             GetU2fSignApduCommand(*alt_application_parameter_, *it),
             base::Bind(&U2fSign::OnTryDevice, weak_factory_.GetWeakPtr(), it,
                        ApplicationParameterType::kAlternative));
       } else if (++it != registered_keys_.end()) {
         // Key is not for this device. Try signing with the next key.
-        current_device_->Sign(
+        InitiateDeviceTransaction(
             GetU2fSignApduCommand(application_parameter_, *it),
             base::BindOnce(&U2fSign::OnTryDevice, weak_factory_.GetWeakPtr(),
                            it, ApplicationParameterType::kPrimary));
       } else {
         // No provided key was accepted by this device. Send registration
         // (Fake enroll) request to device.
-        current_device_->Register(
-            GetBogusRegisterCommand(),
+        InitiateDeviceTransaction(
+            U2fRequest::GetBogusRegisterCommand(),
             base::BindOnce(&U2fSign::OnTryDevice, weak_factory_.GetWeakPtr(),
                            registered_keys_.cend(),
                            ApplicationParameterType::kPrimary));
diff --git a/device/fido/u2f_sign.h b/device/fido/u2f_sign.h
index 8d8a67d..9c6d21fe 100644
--- a/device/fido/u2f_sign.h
+++ b/device/fido/u2f_sign.h
@@ -15,6 +15,7 @@
 #include "base/optional.h"
 #include "device/fido/sign_response_data.h"
 #include "device/fido/u2f_request.h"
+#include "device/fido/u2f_return_code.h"
 #include "device/fido/u2f_transport_protocol.h"
 
 namespace service_manager {
@@ -48,8 +49,6 @@
   ~U2fSign() override;
 
  private:
-  FRIEND_TEST_ALL_PREFIXES(U2fSignTest, TestCreateSignApduCommand);
-
   // Enumerates the two types of |application_parameter| values used: the
   // "primary" value is the hash of the relying party ID[1] and is always
   // provided. The "alternative" value is the hash of a U2F AppID, specified in
@@ -66,8 +65,7 @@
   void TryDevice() override;
   void OnTryDevice(std::vector<std::vector<uint8_t>>::const_iterator it,
                    ApplicationParameterType application_parameter_type,
-                   U2fReturnCode return_code,
-                   const std::vector<uint8_t>& response_data);
+                   base::Optional<std::vector<uint8_t>> response);
 
   base::Optional<std::vector<uint8_t>> alt_application_parameter_;
   SignResponseCallback completion_callback_;
diff --git a/device/fido/virtual_u2f_device.cc b/device/fido/virtual_u2f_device.cc
index 4eb7308..1607914 100644
--- a/device/fido/virtual_u2f_device.cc
+++ b/device/fido/virtual_u2f_device.cc
@@ -99,14 +99,7 @@
 operator=(RegistrationData&& other) = default;
 VirtualU2fDevice::RegistrationData::~RegistrationData() = default;
 
-VirtualU2fDevice::VirtualU2fDevice()
-    : attestation_private_key_(
-          crypto::ECPrivateKey::CreateFromPrivateKeyInfo(GetAttestationKey())),
-      attestation_cert_(std::begin(kAttestationCert),
-                        std::end(kAttestationCert)),
-      weak_factory_(this) {
-  DCHECK(attestation_private_key_);
-}
+VirtualU2fDevice::VirtualU2fDevice() : weak_factory_(this) {}
 
 VirtualU2fDevice::~VirtualU2fDevice() = default;
 
@@ -145,9 +138,9 @@
       break;
     default:
       std::move(cb).Run(
-          true,
           apdu::ApduResponse(std::vector<uint8_t>(),
-                             apdu::ApduResponse::Status::SW_INS_NOT_SUPPORTED));
+                             apdu::ApduResponse::Status::SW_INS_NOT_SUPPORTED)
+              .GetEncodedResponse());
   }
 }
 
@@ -162,8 +155,9 @@
                                   DeviceCallback cb) {
   if (data.size() != 64) {
     std::move(cb).Run(
-        true, apdu::ApduResponse(std::vector<uint8_t>(),
-                                 apdu::ApduResponse::Status::SW_WRONG_LENGTH));
+        apdu::ApduResponse(std::vector<uint8_t>(),
+                           apdu::ApduResponse::Status::SW_WRONG_LENGTH)
+            .GetEncodedResponse());
     return;
   }
 
@@ -202,20 +196,22 @@
   // Note: Non-deterministic, you need to mock this out if you rely on
   // deterministic behavior.
   std::vector<uint8_t> sig;
+  std::unique_ptr<crypto::ECPrivateKey> attestation_private_key =
+      crypto::ECPrivateKey::CreateFromPrivateKeyInfo(GetAttestationKey());
   auto signer =
-      crypto::ECSignatureCreator::Create(attestation_private_key_.get());
+      crypto::ECSignatureCreator::Create(attestation_private_key.get());
   status = signer->Sign(sign_buffer.data(), sign_buffer.size(), &sig);
   DCHECK(status);
 
   // U2F response data.
   std::vector<uint8_t> response;
   response.reserve(1 + public_key.size() + 1 + key_handle.size() +
-                   attestation_cert_.size() + sig.size());
+                   sizeof(kAttestationCert) + sig.size());
   response.push_back(kU2fRegistrationResponseHeader);
   AppendTo(&response, public_key);
   response.push_back(key_handle.size());
   AppendTo(&response, key_handle);
-  AppendTo(&response, attestation_cert_);
+  AppendTo(&response, kAttestationCert);
   AppendTo(&response, sig);
 
   // Store the registration.
@@ -223,9 +219,9 @@
                   std::vector<uint8_t>(app_id_hash.begin(), app_id_hash.end()),
                   1);
 
-  std::move(cb).Run(
-      true, apdu::ApduResponse(std::move(response),
-                               apdu::ApduResponse::Status::SW_NO_ERROR));
+  std::move(cb).Run(apdu::ApduResponse(std::move(response),
+                                       apdu::ApduResponse::Status::SW_NO_ERROR)
+                        .GetEncodedResponse());
 }
 
 void VirtualU2fDevice::DoSign(uint8_t ins,
@@ -237,8 +233,9 @@
         p1 == kP1IndividualAttestation) ||
       p2 != 0) {
     std::move(cb).Run(
-        true, apdu::ApduResponse(std::vector<uint8_t>(),
-                                 apdu::ApduResponse::Status::SW_WRONG_DATA));
+        apdu::ApduResponse(std::vector<uint8_t>(),
+                           apdu::ApduResponse::Status::SW_WRONG_DATA)
+            .GetEncodedResponse());
     return;
   }
 
@@ -249,14 +246,16 @@
     // Our own keyhandles are always 32 bytes long, if the request has something
     // else then we already know it is not ours.
     std::move(cb).Run(
-        true, apdu::ApduResponse(std::vector<uint8_t>(),
-                                 apdu::ApduResponse::Status::SW_WRONG_DATA));
+        apdu::ApduResponse(std::vector<uint8_t>(),
+                           apdu::ApduResponse::Status::SW_WRONG_DATA)
+            .GetEncodedResponse());
     return;
   }
   if (data.size() != 32 + 32 + 1 + key_handle_length) {
     std::move(cb).Run(
-        true, apdu::ApduResponse(std::vector<uint8_t>(),
-                                 apdu::ApduResponse::Status::SW_WRONG_LENGTH));
+        apdu::ApduResponse(std::vector<uint8_t>(),
+                           apdu::ApduResponse::Status::SW_WRONG_LENGTH)
+            .GetEncodedResponse());
     return;
   }
   auto key_handle = data.last(key_handle_length);
@@ -267,8 +266,9 @@
 
   if (it == registrations_.end()) {
     std::move(cb).Run(
-        true, apdu::ApduResponse(std::vector<uint8_t>(),
-                                 apdu::ApduResponse::Status::SW_WRONG_DATA));
+        apdu::ApduResponse(std::vector<uint8_t>(),
+                           apdu::ApduResponse::Status::SW_WRONG_DATA)
+            .GetEncodedResponse());
     return;
   }
 
@@ -278,8 +278,9 @@
     // It's important this error looks identical to the previous one, as
     // tokens should not reveal the existence of keyHandles to unrelated appIds.
     std::move(cb).Run(
-        true, apdu::ApduResponse(std::vector<uint8_t>(),
-                                 apdu::ApduResponse::Status::SW_WRONG_DATA));
+        apdu::ApduResponse(std::vector<uint8_t>(),
+                           apdu::ApduResponse::Status::SW_WRONG_DATA)
+            .GetEncodedResponse());
     return;
   }
 
@@ -311,9 +312,9 @@
   // Add signature for full response.
   AppendTo(&response, sig);
 
-  std::move(cb).Run(
-      true, apdu::ApduResponse(std::move(response),
-                               apdu::ApduResponse::Status::SW_NO_ERROR));
+  std::move(cb).Run(apdu::ApduResponse(std::move(response),
+                                       apdu::ApduResponse::Status::SW_NO_ERROR)
+                        .GetEncodedResponse());
 }
 
 }  // namespace device
diff --git a/device/fido/virtual_u2f_device.h b/device/fido/virtual_u2f_device.h
index b6e3a774..1f56c1d 100644
--- a/device/fido/virtual_u2f_device.h
+++ b/device/fido/virtual_u2f_device.h
@@ -70,9 +70,6 @@
               base::span<const uint8_t> data,
               DeviceCallback cb);
 
-  std::unique_ptr<crypto::ECPrivateKey> attestation_private_key_;
-  std::vector<uint8_t> attestation_cert_;
-
   // Keyed on appId/rpId hash (aka "applicationParam")
   std::map<std::vector<uint8_t>, RegistrationData> registrations_;
   base::WeakPtrFactory<U2fDevice> weak_factory_;
diff --git a/docs/layout_tests_linux.md b/docs/layout_tests_linux.md
index 5b62e043..33a99b7 100644
--- a/docs/layout_tests_linux.md
+++ b/docs/layout_tests_linux.md
@@ -31,10 +31,10 @@
 2.  Double check that
 
 ```shell
-ls third_party/content_shell_fonts/content_shell_test_fonts/
+ls third_party/test_fonts/test_fonts/
 ```
 
-is not empty and lists the fonts downloaded through the `content_shell_fonts`
+is not empty and lists the fonts downloaded through the `test_fonts`
 hook in the top level `DEPS` file.
 
 ## Plugins
diff --git a/gpu/BUILD.gn b/gpu/BUILD.gn
index f583dd1..109eb54 100644
--- a/gpu/BUILD.gn
+++ b/gpu/BUILD.gn
@@ -196,6 +196,7 @@
     "command_buffer/tests/gl_map_buffer_range_unittest.cc",
     "command_buffer/tests/gl_native_gmb_backbuffer_unittest.cc",
     "command_buffer/tests/gl_object_bindings_unittest.cc",
+    "command_buffer/tests/gl_oes_egl_image_unittest.cc",
     "command_buffer/tests/gl_offscreen_surface_unittest.cc",
     "command_buffer/tests/gl_oob_attrib_unittest.cc",
     "command_buffer/tests/gl_pointcoord_unittest.cc",
diff --git a/gpu/command_buffer/service/decoder_context.h b/gpu/command_buffer/service/decoder_context.h
index 6ead2f07..ba35ca6 100644
--- a/gpu/command_buffer/service/decoder_context.h
+++ b/gpu/command_buffer/service/decoder_context.h
@@ -17,6 +17,7 @@
 #include "gpu/command_buffer/common/context_result.h"
 #include "gpu/command_buffer/service/async_api_interface.h"
 #include "gpu/gpu_gles2_export.h"
+#include "ui/gfx/geometry/rect.h"
 
 namespace gl {
 class GLContext;
@@ -149,6 +150,15 @@
   // Gets the texture object associated with the client ID.  null is returned on
   // failure or if the texture has not been bound yet.
   virtual TextureBase* GetTextureBase(uint32_t client_id) = 0;
+  virtual void SetLevelInfo(uint32_t client_id,
+                            int level,
+                            unsigned internal_format,
+                            unsigned width,
+                            unsigned height,
+                            unsigned depth,
+                            unsigned format,
+                            unsigned type,
+                            const gfx::Rect& cleared_rect) = 0;
   virtual void BindImage(uint32_t client_texture_id,
                          uint32_t texture_target,
                          gl::GLImage* image,
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc
index 6f09197..bc63c6f 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -546,6 +546,16 @@
   return nullptr;
 }
 
+void GLES2Decoder::SetLevelInfo(uint32_t client_id,
+                                int level,
+                                unsigned internal_format,
+                                unsigned width,
+                                unsigned height,
+                                unsigned depth,
+                                unsigned format,
+                                unsigned type,
+                                const gfx::Rect& cleared_rect) {}
+
 void GLES2Decoder::BeginDecoding() {}
 
 void GLES2Decoder::EndDecoding() {}
@@ -681,6 +691,15 @@
   bool GetServiceTextureId(uint32_t client_texture_id,
                            uint32_t* service_texture_id) override;
   TextureBase* GetTextureBase(uint32_t client_id) override;
+  void SetLevelInfo(uint32_t client_id,
+                    int level,
+                    unsigned internal_format,
+                    unsigned width,
+                    unsigned height,
+                    unsigned depth,
+                    unsigned format,
+                    unsigned type,
+                    const gfx::Rect& cleared_rect) override;
 
   // Restores the current state to the user's settings.
   void RestoreCurrentFramebufferBindings();
@@ -4970,6 +4989,21 @@
   return texture_ref ? texture_ref->texture() : nullptr;
 }
 
+void GLES2DecoderImpl::SetLevelInfo(uint32_t client_id,
+                                    int level,
+                                    unsigned internal_format,
+                                    unsigned width,
+                                    unsigned height,
+                                    unsigned depth,
+                                    unsigned format,
+                                    unsigned type,
+                                    const gfx::Rect& cleared_rect) {
+  TextureRef* texture_ref = texture_manager()->GetTexture(client_id);
+  texture_manager()->SetLevelInfo(texture_ref, texture_ref->texture()->target(),
+                                  level, internal_format, width, height, depth,
+                                  0 /* border */, format, type, cleared_rect);
+}
+
 void GLES2DecoderImpl::Destroy(bool have_context) {
   if (!initialized())
     return;
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.h b/gpu/command_buffer/service/gles2_cmd_decoder.h
index a47529b3..b9419b50 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.h
@@ -99,6 +99,15 @@
   // DecoderContext implementation.
   bool initialized() const override;
   TextureBase* GetTextureBase(uint32_t client_id) override;
+  void SetLevelInfo(uint32_t client_id,
+                    int level,
+                    unsigned internal_format,
+                    unsigned width,
+                    unsigned height,
+                    unsigned depth,
+                    unsigned format,
+                    unsigned type,
+                    const gfx::Rect& cleared_rect) override;
   void BeginDecoding() override;
   void EndDecoding() override;
   base::StringPiece GetLogPrefix() override;
diff --git a/gpu/command_buffer/service/raster_decoder.cc b/gpu/command_buffer/service/raster_decoder.cc
index 8d4fbd4..e84cc6ac 100644
--- a/gpu/command_buffer/service/raster_decoder.cc
+++ b/gpu/command_buffer/service/raster_decoder.cc
@@ -100,6 +100,15 @@
   bool HasPollingWork() const override;
   void PerformPollingWork() override;
   TextureBase* GetTextureBase(uint32_t client_id) override;
+  void SetLevelInfo(uint32_t client_id,
+                    int level,
+                    unsigned internal_format,
+                    unsigned width,
+                    unsigned height,
+                    unsigned depth,
+                    unsigned format,
+                    unsigned type,
+                    const gfx::Rect& cleared_rect) override;
   bool WasContextLost() const override;
   bool WasContextLostByRobustnessExtension() const override;
   void MarkContextLost(error::ContextLostReason reason) override;
@@ -402,6 +411,16 @@
   return nullptr;
 }
 
+void RasterDecoder::SetLevelInfo(uint32_t client_id,
+                                 int level,
+                                 unsigned internal_format,
+                                 unsigned width,
+                                 unsigned height,
+                                 unsigned depth,
+                                 unsigned format,
+                                 unsigned type,
+                                 const gfx::Rect& cleared_rect) {}
+
 void RasterDecoder::BeginDecoding() {}
 
 void RasterDecoder::EndDecoding() {}
@@ -643,6 +662,18 @@
   return nullptr;
 }
 
+void RasterDecoderImpl::SetLevelInfo(uint32_t client_id,
+                                     int level,
+                                     unsigned internal_format,
+                                     unsigned width,
+                                     unsigned height,
+                                     unsigned depth,
+                                     unsigned format,
+                                     unsigned type,
+                                     const gfx::Rect& cleared_rect) {
+  NOTIMPLEMENTED();
+}
+
 bool RasterDecoderImpl::WasContextLost() const {
   return false;
 }
diff --git a/gpu/command_buffer/service/raster_decoder.h b/gpu/command_buffer/service/raster_decoder.h
index e86e5777..64833ed 100644
--- a/gpu/command_buffer/service/raster_decoder.h
+++ b/gpu/command_buffer/service/raster_decoder.h
@@ -37,6 +37,15 @@
   // DecoderContext implementation.
   bool initialized() const override;
   TextureBase* GetTextureBase(uint32_t client_id) override;
+  void SetLevelInfo(uint32_t client_id,
+                    int level,
+                    unsigned internal_format,
+                    unsigned width,
+                    unsigned height,
+                    unsigned depth,
+                    unsigned format,
+                    unsigned type,
+                    const gfx::Rect& cleared_rect) override;
   void BeginDecoding() override;
   void EndDecoding() override;
   base::StringPiece GetLogPrefix() override;
diff --git a/gpu/command_buffer/tests/gl_manager.cc b/gpu/command_buffer/tests/gl_manager.cc
index e068885..8a19b8fa 100644
--- a/gpu/command_buffer/tests/gl_manager.cc
+++ b/gpu/command_buffer/tests/gl_manager.cc
@@ -461,6 +461,7 @@
     decoder_->Destroy(have_context);
     decoder_.reset();
   }
+  context_ = nullptr;
 }
 
 const GpuDriverBugWorkarounds& GLManager::workarounds() const {
diff --git a/gpu/command_buffer/tests/gl_oes_egl_image_unittest.cc b/gpu/command_buffer/tests/gl_oes_egl_image_unittest.cc
new file mode 100644
index 0000000..d9c2107
--- /dev/null
+++ b/gpu/command_buffer/tests/gl_oes_egl_image_unittest.cc
@@ -0,0 +1,177 @@
+// 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 <GLES2/gl2.h>
+
+#include "build/build_config.h"
+#include "gpu/command_buffer/client/gles2_implementation.h"
+#include "gpu/command_buffer/tests/gl_test_utils.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/buffer_format_util.h"
+#include "ui/gl/gl_image.h"
+#include "ui/gl/init/gl_factory.h"
+
+#if defined(OS_LINUX)
+#include "ui/gl/gl_image_native_pixmap.h"
+#endif
+
+#define SKIP_TEST_IF(cmd)                        \
+  do {                                           \
+    if (cmd) {                                   \
+      LOG(INFO) << "Skip test because " << #cmd; \
+      return;                                    \
+    }                                            \
+  } while (false)
+
+namespace {
+
+static const int kImageWidth = 64;
+static const int kImageHeight = 64;
+
+class GpuOESEGLImageTest : public testing::Test,
+                           public gpu::GpuCommandBufferTestEGL {
+ protected:
+  void SetUp() override {
+    egl_gles2_initialized_ = InitializeEGLGLES2(kImageWidth, kImageHeight);
+  }
+
+  void TearDown() override { RestoreGLDefault(); }
+
+  bool egl_gles2_initialized_;
+};
+
+#if defined(OS_LINUX)
+
+#define SHADER(Src) #Src
+
+// clang-format off
+const char kVertexShader[] =
+SHADER(
+  attribute vec4 a_position;
+  varying vec2 v_texCoord;
+  void main() {
+    gl_Position = a_position;
+    v_texCoord = vec2((a_position.x + 1.0) * 0.5, (a_position.y + 1.0) * 0.5);
+  }
+);
+
+const char* kFragmentShader =
+SHADER(
+  precision mediump float;
+  uniform sampler2D a_texture;
+  varying vec2 v_texCoord;
+  void main() {
+    gl_FragColor = texture2D(a_texture, v_texCoord);
+  }
+);
+// clang-format on
+
+// The test verifies that the content of an EGLImage can be drawn. Indeed the
+// test upload some colored pixels into a GL texture. Then it creates an
+// EGLImage from this texture and binds this image to draw it into another
+// GL texture. At the end the test downloads the pixels from the final GL
+// texture and verifies that the colors match with the pixels uploaded into
+// the initial GL texture.
+TEST_F(GpuOESEGLImageTest, EGLImageToTexture) {
+  SKIP_TEST_IF(!egl_gles2_initialized_);
+
+  // This extension is required for creating an EGLImage from a GL texture.
+  SKIP_TEST_IF(!HasEGLExtension("EGL_KHR_image_base"));
+
+  // This extension is required to render an EGLImage into a GL texture.
+  SKIP_TEST_IF(!HasGLExtension("GL_OES_EGL_image"));
+
+  gfx::BufferFormat format = gfx::BufferFormat::RGBX_8888;
+  gfx::Size size(kImageWidth, kImageHeight);
+  size_t buffer_size = gfx::BufferSizeForBufferFormat(size, format);
+  uint8_t pixel[] = {128u, 92u, 45u, 255u};
+  size_t plane = 0;
+  uint32_t stride = gfx::RowSizeForBufferFormat(size.width(), format, plane);
+
+  std::unique_ptr<uint8_t[]> pixels(new uint8_t[buffer_size]);
+
+  // Assign a value to each pixel.
+  for (int y = 0; y < size.height(); ++y) {
+    uint8_t* line = static_cast<uint8_t*>(pixels.get()) + y * stride;
+    for (int x = 0; x < size.width() * 4; x += 4) {
+      line[x + 0] = pixel[0];
+      line[x + 1] = pixel[1];
+      line[x + 2] = pixel[2];
+      line[x + 3] = pixel[3];
+    }
+  }
+
+  // Create an EGLImage from a GL texture.
+  scoped_refptr<gl::GLImageNativePixmap> image =
+      CreateGLImageNativePixmap(format, size, pixels.get());
+  EXPECT_TRUE(image);
+  EXPECT_EQ(size, image->GetSize());
+
+  // Need a texture to bind the image.
+  GLuint texture_id = 0;
+  glGenTextures(1, &texture_id);
+  ASSERT_NE(0u, texture_id);
+  glActiveTexture(GL_TEXTURE0);
+  glBindTexture(GL_TEXTURE_2D, texture_id);
+  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+
+  // Make sure the texture exists in the service side.
+  glFinish();
+
+  // Bind the image.
+  EXPECT_TRUE(image->BindTexImage(GL_TEXTURE_2D));
+  unsigned internal_format = image->GetInternalFormat();
+  gl_.decoder()->SetLevelInfo(
+      texture_id, 0 /* level */, internal_format, size.width(), size.height(),
+      1 /* depth */, internal_format, GL_UNSIGNED_BYTE, gfx::Rect(size));
+  gl_.decoder()->BindImage(texture_id, GL_TEXTURE_2D, image.get(),
+                           true /* can_bind_to_sampler */);
+
+  // Build program, buffers and draw the texture.
+  GLuint vertex_shader =
+      gpu::GLTestHelper::LoadShader(GL_VERTEX_SHADER, kVertexShader);
+  GLuint fragment_shader =
+      gpu::GLTestHelper::LoadShader(GL_FRAGMENT_SHADER, kFragmentShader);
+  GLuint program =
+      gpu::GLTestHelper::SetupProgram(vertex_shader, fragment_shader);
+  ASSERT_NE(0u, program);
+  glUseProgram(program);
+
+  GLint sampler_location = glGetUniformLocation(program, "a_texture");
+  ASSERT_NE(-1, sampler_location);
+  glUniform1i(sampler_location, 0);
+
+  GLuint vbo = gpu::GLTestHelper::SetupUnitQuad(
+      glGetAttribLocation(program, "a_position"));
+  ASSERT_NE(0u, vbo);
+  glViewport(0, 0, kImageWidth, kImageHeight);
+
+  // Render the EGLImage into the GL texture.
+  glDrawArrays(GL_TRIANGLES, 0, 6);
+  ASSERT_TRUE(glGetError() == GL_NO_ERROR);
+
+  // Check if pixels match the values that were assigned to the mapped buffer.
+  gpu::GLTestHelper::CheckPixels(0, 0, kImageWidth, kImageHeight, 0, pixel,
+                                 nullptr);
+  EXPECT_TRUE(GL_NO_ERROR == glGetError());
+
+  // Release the image.
+  gl_.decoder()->BindImage(texture_id, GL_TEXTURE_2D, image.get(),
+                           false /* can_bind_to_sampler */);
+  image->ReleaseTexImage(GL_TEXTURE_2D);
+
+  // Clean up.
+  glDeleteProgram(program);
+  glDeleteShader(vertex_shader);
+  glDeleteShader(fragment_shader);
+  glDeleteBuffers(1, &vbo);
+  glDeleteTextures(1, &texture_id);
+}
+#endif  // defined(OS_LINUX)
+
+}  // namespace
diff --git a/gpu/command_buffer/tests/gl_test_utils.cc b/gpu/command_buffer/tests/gl_test_utils.cc
index 402a9694..5a3f935b 100644
--- a/gpu/command_buffer/tests/gl_test_utils.cc
+++ b/gpu/command_buffer/tests/gl_test_utils.cc
@@ -11,15 +11,63 @@
 #include <memory>
 #include <string>
 
+#include "base/command_line.h"
 #include "gpu/command_buffer/common/gles2_cmd_utils.h"
+#include "gpu/config/gpu_driver_bug_workarounds.h"
+#include "gpu/config/gpu_info_collector.h"
+#include "gpu/config/gpu_util.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/gfx/geometry/size.h"
+#include "ui/gl/init/gl_factory.h"
+
+#if defined(OS_LINUX)
+#include "ui/gl/gl_image_native_pixmap.h"
+#endif
+
+namespace gpu {
 
 // GCC requires these declarations, but MSVC requires they not be present.
 #ifndef COMPILER_MSVC
 const uint8_t GLTestHelper::kCheckClearValue;
 #endif
 
+bool GLTestHelper::InitializeGL(gl::GLImplementation gl_impl) {
+  if (gl_impl == gl::GLImplementation::kGLImplementationNone) {
+    if (!gl::init::InitializeGLNoExtensionsOneOff())
+      return false;
+  } else {
+    if (!gl::init::InitializeGLOneOffImplementation(
+            gl_impl,
+            false,  // fallback_to_software_gl
+            false,  // gpu_service_logging
+            false,  // disable_gl_drawing
+            false   // init_extensions
+            )) {
+      return false;
+    }
+  }
+
+  gpu::GPUInfo gpu_info;
+  gpu::CollectGraphicsInfoForTesting(&gpu_info);
+  gpu::GLManager::g_gpu_feature_info =
+      gpu::ComputeGpuFeatureInfo(gpu_info,
+                                 false,  // ignore_gpu_blacklist
+                                 false,  // disable_gpu_driver_bug_workarounds
+                                 false,  // log_gpu_control_list_decisions
+                                 base::CommandLine::ForCurrentProcess(),
+                                 nullptr  // needs_more_info
+                                 );
+
+  gl::init::SetDisabledExtensionsPlatform(
+      gpu::GLManager::g_gpu_feature_info.disabled_extensions);
+  return gl::init::InitializeExtensionSettingsOneOffPlatform();
+}
+
+bool GLTestHelper::InitializeGLDefault() {
+  return GLTestHelper::InitializeGL(
+      gl::GLImplementation::kGLImplementationNone);
+}
+
 bool GLTestHelper::HasExtension(const char* extension) {
   // Pad with an extra space to ensure that |extension| is not a substring of
   // another extension.
@@ -311,3 +359,105 @@
   glDeleteProgram(program);
   glDeleteBuffers(1, &vertex_buffer);
 }
+
+GpuCommandBufferTestEGL::GpuCommandBufferTestEGL() : gl_reinitialized_(false) {}
+
+GpuCommandBufferTestEGL::~GpuCommandBufferTestEGL() {}
+
+bool GpuCommandBufferTestEGL::InitializeEGLGLES2(int width, int height) {
+  if (gl::GetGLImplementation() !=
+      gl::GLImplementation::kGLImplementationEGLGLES2) {
+    const auto impls = gl::init::GetAllowedGLImplementations();
+    if (std::find(impls.begin(), impls.end(),
+                  gl::GLImplementation::kGLImplementationEGLGLES2) ==
+        impls.end()) {
+      LOG(INFO) << "Skip test, implementation EGLGLES2 is not available";
+      return false;
+    }
+
+    gl_reinitialized_ = true;
+    gl::init::ShutdownGL(false /* due_to_fallback */);
+    if (!GLTestHelper::InitializeGL(
+            gl::GLImplementation::kGLImplementationEGLGLES2)) {
+      LOG(INFO) << "Skip test, failed to initialize EGLGLES2";
+      return false;
+    }
+  }
+
+  DCHECK_EQ(gl::GLImplementation::kGLImplementationEGLGLES2,
+            gl::GetGLImplementation());
+
+  // Make the GL context current now to get all extensions.
+  GLManager::Options options;
+  options.size = gfx::Size(width, height);
+  gl_.Initialize(options);
+  gl_.MakeCurrent();
+
+  bool result =
+      gl::init::GetGLWindowSystemBindingInfo(&window_system_binding_info_);
+  DCHECK(result);
+
+  egl_extensions_ =
+      gl::MakeExtensionSet(window_system_binding_info_.extensions);
+  gl_extensions_ =
+      gl::MakeExtensionSet(gl::GetGLExtensionsFromCurrentContext());
+
+  return true;
+}
+
+void GpuCommandBufferTestEGL::RestoreGLDefault() {
+  gl_.Destroy();
+
+  if (gl_reinitialized_) {
+    gl::init::ShutdownGL(false /* due_to_fallback */);
+    GLTestHelper::InitializeGLDefault();
+  }
+
+  gl_reinitialized_ = false;
+  gl_extensions_.clear();
+  egl_extensions_.clear();
+  window_system_binding_info_ = gl::GLWindowSystemBindingInfo();
+}
+
+#if defined(OS_LINUX)
+scoped_refptr<gl::GLImageNativePixmap>
+GpuCommandBufferTestEGL::CreateGLImageNativePixmap(gfx::BufferFormat format,
+                                                   gfx::Size size,
+                                                   uint8_t* pixels) const {
+  // Upload raw pixels to a new GL texture.
+  GLuint tex_client_id = 0;
+  glGenTextures(1, &tex_client_id);
+  DCHECK_NE(0u, tex_client_id);
+  glBindTexture(GL_TEXTURE_2D, tex_client_id);
+  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size.width(), size.height(), 0,
+               GL_RGBA, GL_UNSIGNED_BYTE, pixels);
+
+  // Make sure the texture exists in the service side.
+  glFinish();
+
+  // This works because the test run in a similar mode as In-Process-GPU.
+  unsigned int tex_service_id = 0;
+  gl_.decoder()->GetServiceTextureId(tex_client_id, &tex_service_id);
+  EXPECT_NE(0u, tex_service_id);
+
+  // Create an EGLImage from the real texture id.
+  scoped_refptr<gl::GLImageNativePixmap> image(new gl::GLImageNativePixmap(
+      size, gl::GLImageNativePixmap::GetInternalFormatForTesting(format)));
+  bool result = image->InitializeFromTexture(tex_service_id);
+  DCHECK(result);
+
+  // The test will own the EGLImage no need to keep a reference on the GL
+  // texture after returning from this function. This is covered by the
+  // EGL_KHR_image_base.txt specification, i.e. the underlying memory remains
+  // allocated as long as there is at least one sibling (like ref count).
+  glDeleteTextures(1, &tex_client_id);
+
+  return image;
+}
+#endif
+
+}  // namespace gpu
diff --git a/gpu/command_buffer/tests/gl_test_utils.h b/gpu/command_buffer/tests/gl_test_utils.h
index 3a1641e..0bd40280 100644
--- a/gpu/command_buffer/tests/gl_test_utils.h
+++ b/gpu/command_buffer/tests/gl_test_utils.h
@@ -12,10 +12,23 @@
 
 #include <vector>
 
+#include "build/build_config.h"
+#include "gpu/command_buffer/tests/gl_manager.h"
+#include "ui/gl/gl_implementation.h"
+
+namespace gl {
+class GLImageNativePixmap;
+}
+
+namespace gpu {
+
 class GLTestHelper {
  public:
   static const uint8_t kCheckClearValue = 123u;
 
+  static bool InitializeGL(gl::GLImplementation gl_impl);
+  static bool InitializeGLDefault();
+
   static bool HasExtension(const char* extension);
   static bool CheckGLError(const char* msg, int line);
 
@@ -76,4 +89,45 @@
                               const char* face_name);
 };
 
+class GpuCommandBufferTestEGL {
+ public:
+  GpuCommandBufferTestEGL();
+  ~GpuCommandBufferTestEGL();
+
+  // Reinitialize GL to the EGLGLES2 implementation if it is available and not
+  // the current initialized GL implementation. Return true on sucess, false
+  // otherwise.
+  bool InitializeEGLGLES2(int width, int height);
+
+  // Restore the default GL implementation.
+  void RestoreGLDefault();
+
+  // Returns whether the current context supports the named EGL extension.
+  bool HasEGLExtension(const base::StringPiece& extension) {
+    return gl::HasExtension(egl_extensions_, extension);
+  }
+
+  // Returns whether the current context supports the named GL extension.
+  bool HasGLExtension(const base::StringPiece& extension) {
+    return gl::HasExtension(gl_extensions_, extension);
+  }
+
+#if defined(OS_LINUX)
+  // Create GLImageNativePixmap filled in with the given pixels.
+  scoped_refptr<gl::GLImageNativePixmap> CreateGLImageNativePixmap(
+      gfx::BufferFormat format,
+      gfx::Size size,
+      uint8_t* pixels) const;
+#endif
+
+ protected:
+  bool gl_reinitialized_;
+  GLManager gl_;
+  gl::GLWindowSystemBindingInfo window_system_binding_info_;
+  gl::ExtensionSet egl_extensions_;
+  gl::ExtensionSet gl_extensions_;
+};
+
+}  // namespace gpu
+
 #endif  // GPU_COMMAND_BUFFER_TESTS_GL_TEST_UTILS_H_
diff --git a/gpu/command_buffer/tests/gl_tests_main.cc b/gpu/command_buffer/tests/gl_tests_main.cc
index 2d9a5449..021ac07 100644
--- a/gpu/command_buffer/tests/gl_tests_main.cc
+++ b/gpu/command_buffer/tests/gl_tests_main.cc
@@ -4,7 +4,6 @@
 
 #include "base/at_exit.h"
 #include "base/bind.h"
-#include "base/command_line.h"
 #include "base/feature_list.h"
 #include "base/message_loop/message_loop.h"
 #if defined(OS_MACOSX)
@@ -13,12 +12,8 @@
 #include "base/test/launcher/unit_test_launcher.h"
 #include "base/test/test_suite.h"
 #include "gpu/command_buffer/client/gles2_lib.h"
-#include "gpu/command_buffer/tests/gl_manager.h"
-#include "gpu/config/gpu_driver_bug_workarounds.h"
-#include "gpu/config/gpu_info_collector.h"
-#include "gpu/config/gpu_util.h"
+#include "gpu/command_buffer/tests/gl_test_utils.h"
 #include "testing/gmock/include/gmock/gmock.h"
-#include "ui/gl/init/gl_factory.h"
 
 namespace {
 
@@ -29,18 +24,7 @@
   base::MessageLoopForIO message_loop;
 #endif
   base::FeatureList::InitializeInstance(std::string(), std::string());
-  gl::init::InitializeGLNoExtensionsOneOff();
-  gpu::GPUInfo gpu_info;
-  gpu::CollectGraphicsInfoForTesting(&gpu_info);
-  gpu::GLManager::g_gpu_feature_info = gpu::ComputeGpuFeatureInfo(
-      gpu_info,
-      false,  // ignore_gpu_blacklist
-      false,  // disable_gpu_driver_bug_workarounds
-      false,  // log_gpu_control_list_decisions
-      base::CommandLine::ForCurrentProcess(), nullptr);
-  gl::init::SetDisabledExtensionsPlatform(
-      gpu::GLManager::g_gpu_feature_info.disabled_extensions);
-  gl::init::InitializeExtensionSettingsOneOffPlatform();
+  gpu::GLTestHelper::InitializeGLDefault();
   ::gles2::Initialize();
   return testSuite->Run();
 }
diff --git a/gpu/ipc/service/gpu_memory_buffer_factory_native_pixmap.cc b/gpu/ipc/service/gpu_memory_buffer_factory_native_pixmap.cc
index 4d262b7..4c1f72e 100644
--- a/gpu/ipc/service/gpu_memory_buffer_factory_native_pixmap.cc
+++ b/gpu/ipc/service/gpu_memory_buffer_factory_native_pixmap.cc
@@ -7,6 +7,7 @@
 #include "ui/gfx/buffer_format_util.h"
 #include "ui/gfx/client_native_pixmap.h"
 #include "ui/gfx/native_pixmap.h"
+#include "ui/gl/gl_bindings.h"
 #include "ui/gl/gl_image_native_pixmap.h"
 
 #if defined(USE_OZONE)
diff --git a/headless/lib/dom_tree_extraction_expected_nodes.txt b/headless/lib/dom_tree_extraction_expected_nodes.txt
index 588c8b0..f27c42d 100644
--- a/headless/lib/dom_tree_extraction_expected_nodes.txt
+++ b/headless/lib/dom_tree_extraction_expected_nodes.txt
@@ -276,6 +276,13 @@
    "nodeValue": "\n"
 }
 {
+   "attributes": [ {
+      "name": "style",
+      "value": "font-family: \"SlightHintedTimesNewRoman\", \"Times New Roman\""
+   }, {
+      "name": ";\"",
+      "value": ""
+   } ],
    "backendNodeId": 26,
    "boundingBox": {
       "height": 37.0,
diff --git a/headless/lib/dom_tree_extraction_expected_styles.txt b/headless/lib/dom_tree_extraction_expected_styles.txt
index 1d2a58023..d78ea8c 100644
--- a/headless/lib/dom_tree_extraction_expected_styles.txt
+++ b/headless/lib/dom_tree_extraction_expected_styles.txt
@@ -61,7 +61,7 @@
 {
    "color": "rgb(0, 0, 0)",
    "display": "block",
-   "font-family": "\"Times New Roman\"",
+   "font-family": "SlightHintedTimesNewRoman, \"Times New Roman\"",
    "font-style": "normal",
    "margin-bottom": "21.44px",
    "margin-left": "0px",
diff --git a/headless/test/data/iframe.html b/headless/test/data/iframe.html
index 655c965..1e8b7fe 100644
--- a/headless/test/data/iframe.html
+++ b/headless/test/data/iframe.html
@@ -1,5 +1,5 @@
 <html>
 <body>
-<h1>Hello from the iframe!</h1>
+<h1 style='font-family: "SlightHintedTimesNewRoman", "Times New Roman"';">Hello from the iframe!</h1>
 </body>
 </html>
diff --git a/infra/config/global/cr-buildbucket.cfg b/infra/config/global/cr-buildbucket.cfg
index 09fd2bb..089b878 100644
--- a/infra/config/global/cr-buildbucket.cfg
+++ b/infra/config/global/cr-buildbucket.cfg
@@ -714,67 +714,55 @@
     builders {
       name: "Win10 FYI Debug (NVIDIA)"
       mixins: "win-gpu-fyi-ci"
-      dimensions: "os:Windows-10"
+      mixins: "gpu-slow-bot"
     }
     builders {
       name: "Win10 FYI dEQP Release (NVIDIA)"
       mixins: "win-gpu-fyi-ci"
-      dimensions: "os:Windows-10"
     }
     builders {
       name: "Win10 FYI Exp Release (NVIDIA)"
       mixins: "win-gpu-fyi-ci"
-      dimensions: "os:Windows-10"
     }
     builders {
       name: "Win10 FYI Release (Intel HD 630)"
       mixins: "win-gpu-fyi-ci"
-      dimensions: "os:Windows-10"
     }
     builders {
       name: "Win10 FYI Release (NVIDIA)"
       mixins: "win-gpu-fyi-ci"
-      dimensions: "os:Windows-10"
     }
     builders {
       name: "Win7 FYI Debug (AMD)"
       mixins: "win-gpu-fyi-ci"
-      dimensions: "os:Windows-7"
     }
     builders {
       name: "Win7 FYI Debug (NVIDIA)"
       mixins: "win-gpu-fyi-ci"
-      dimensions: "os:Windows-7"
     }
     builders {
       name: "Win7 FYI dEQP Release (AMD)"
       mixins: "win-gpu-fyi-ci"
-      dimensions: "os:Windows-7"
     }
     builders {
       name: "Win7 FYI Release (AMD)"
       mixins: "win-gpu-fyi-ci"
-      dimensions: "os:Windows-7"
     }
     builders {
       name: "Win7 FYI Release (NVIDIA)"
       mixins: "win-gpu-fyi-ci"
-      dimensions: "os:Windows-7"
     }
     builders {
       name: "Win7 FYI x64 Debug (NVIDIA)"
       mixins: "win-gpu-fyi-ci"
-      dimensions: "os:Windows-7"
     }
     builders {
       name: "Win7 FYI x64 dEQP Release (NVIDIA)"
       mixins: "win-gpu-fyi-ci"
-      dimensions: "os:Windows-7"
     }
     builders {
       name: "Win7 FYI x64 Release (NVIDIA)"
       mixins: "win-gpu-fyi-ci"
-      dimensions: "os:Windows-7"
     }
   }
 }
diff --git a/ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_table_view_controller.mm b/ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_table_view_controller.mm
index 3d66bae..5f332d9 100644
--- a/ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_table_view_controller.mm
+++ b/ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_table_view_controller.mm
@@ -41,6 +41,7 @@
 #include "ios/chrome/grit/ios_strings.h"
 #import "ios/web/public/web_state/context_menu_params.h"
 #include "ui/base/l10n/l10n_util.h"
+#include "ui/base/l10n/time_format.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -76,6 +77,9 @@
 int const kNumberOfSectionsBeforeSessions = 2;
 // Estimated Table Row height.
 const CGFloat kEstimatedRowHeight = 56;
+// The UI displays relative time for up to this number of hours and then
+// switches to absolute values.
+const int kRelativeTimeMaxHours = 4;
 
 }  // namespace
 
@@ -271,6 +275,9 @@
         [[TableViewTextHeaderFooterItem alloc]
             initWithType:ItemTypeSessionHeader];
     header.text = base::SysUTF8ToNSString(session->name);
+    header.subtitleText = l10n_util::GetNSStringF(
+        IDS_IOS_OPEN_TABS_LAST_USED,
+        base::SysNSStringToUTF16([self lastSyncStringForSesssion:session]));
     [model setHeader:header forSectionWithIdentifier:sessionIdentifier];
     [self addItemsForSession:session];
   }
@@ -609,6 +616,43 @@
   return session->tabs[indexOfDistantTab].get();
 }
 
+- (NSString*)lastSyncStringForSesssion:
+    (synced_sessions::DistantSession const*)session {
+  base::Time time = session->modified_time;
+  NSDate* lastUsedDate = [NSDate dateWithTimeIntervalSince1970:time.ToTimeT()];
+  NSString* dateString =
+      [NSDateFormatter localizedStringFromDate:lastUsedDate
+                                     dateStyle:NSDateFormatterShortStyle
+                                     timeStyle:NSDateFormatterNoStyle];
+
+  NSString* timeString;
+  base::TimeDelta last_used_delta;
+  if (base::Time::Now() > time)
+    last_used_delta = base::Time::Now() - time;
+
+  if (last_used_delta.InMicroseconds() < base::Time::kMicrosecondsPerMinute) {
+    timeString = l10n_util::GetNSString(IDS_IOS_OPEN_TABS_RECENTLY_SYNCED);
+    // This will return something similar to "Seconds ago mm/dd/yy"
+    return [NSString stringWithFormat:@"%@ %@", timeString, dateString];
+  }
+
+  if (last_used_delta.InHours() < kRelativeTimeMaxHours) {
+    timeString = base::SysUTF16ToNSString(
+        ui::TimeFormat::Simple(ui::TimeFormat::FORMAT_ELAPSED,
+                               ui::TimeFormat::LENGTH_SHORT, last_used_delta));
+    // This will return something similar to "1 min/hour ago mm/dd/yy"
+    return [NSString stringWithFormat:@"%@ %@", timeString, dateString];
+  }
+
+  NSDate* date = [NSDate dateWithTimeIntervalSince1970:time.ToTimeT()];
+  timeString =
+      [NSDateFormatter localizedStringFromDate:date
+                                     dateStyle:NSDateFormatterNoStyle
+                                     timeStyle:NSDateFormatterShortStyle];
+  // This will return something similar to "H:MM mm/dd/yy"
+  return [NSString stringWithFormat:@"%@ %@", timeString, dateString];
+}
+
 #pragma mark - Navigation helpers
 
 - (void)dismissRecentTabsModal {
diff --git a/ios/chrome/browser/ui/tab_grid/BUILD.gn b/ios/chrome/browser/ui/tab_grid/BUILD.gn
index e3dfc1c..9c698007 100644
--- a/ios/chrome/browser/ui/tab_grid/BUILD.gn
+++ b/ios/chrome/browser/ui/tab_grid/BUILD.gn
@@ -53,6 +53,8 @@
     "grid_view_controller.mm",
     "tab_grid_bottom_toolbar.h",
     "tab_grid_bottom_toolbar.mm",
+    "tab_grid_page_control.h",
+    "tab_grid_page_control.mm",
     "tab_grid_paging.h",
     "tab_grid_top_toolbar.h",
     "tab_grid_top_toolbar.mm",
diff --git a/ios/chrome/browser/ui/tab_grid/grid_layout.mm b/ios/chrome/browser/ui/tab_grid/grid_layout.mm
index d1307de..3af4b66 100644
--- a/ios/chrome/browser/ui/tab_grid/grid_layout.mm
+++ b/ios/chrome/browser/ui/tab_grid/grid_layout.mm
@@ -15,11 +15,13 @@
 @interface GridLayout ()
 @property(nonatomic, assign) CGFloat startingTabWidth;
 @property(nonatomic, assign) CGFloat maxTabWidth;
+@property(nonatomic, strong) NSArray<NSIndexPath*>* indexPathsOfDeletingItems;
 @end
 
 @implementation GridLayout
 @synthesize startingTabWidth = _startingTabWidth;
 @synthesize maxTabWidth = _maxTabWidth;
+@synthesize indexPathsOfDeletingItems = _indexPathsOfDeletingItems;
 
 - (instancetype)init {
   if (self = [super init]) {
@@ -42,6 +44,44 @@
   }
 }
 
+- (void)prepareForCollectionViewUpdates:
+    (NSArray<UICollectionViewUpdateItem*>*)updateItems {
+  NSMutableArray<NSIndexPath*>* deletingItems =
+      [NSMutableArray arrayWithCapacity:updateItems.count];
+  for (UICollectionViewUpdateItem* item in updateItems) {
+    if (item.updateAction == UICollectionUpdateActionDelete) {
+      [deletingItems addObject:item.indexPathBeforeUpdate];
+    }
+  }
+  self.indexPathsOfDeletingItems = [deletingItems copy];
+}
+
+- (UICollectionViewLayoutAttributes*)
+finalLayoutAttributesForDisappearingItemAtIndexPath:
+    (NSIndexPath*)itemIndexPath {
+  UICollectionViewLayoutAttributes* attributes =
+      [super finalLayoutAttributesForDisappearingItemAtIndexPath:itemIndexPath];
+  // Disappearing items that aren't being deleted just use the default
+  // attributes.
+  if (![self.indexPathsOfDeletingItems containsObject:itemIndexPath]) {
+    return attributes;
+  }
+  // Cells being deleted fade out, are scaled down, and drop downwards slightly.
+  attributes.alpha = 0.0;
+  // Scaled down to 60%.
+  CGAffineTransform transform =
+      CGAffineTransformScale(attributes.transform, 0.6, 0.6);
+  // Translated down (positive-y direction) by 50% of the cell cell size.
+  transform =
+      CGAffineTransformTranslate(transform, 0, attributes.size.height * 0.5);
+  attributes.transform = transform;
+  return attributes;
+}
+
+- (void)finalizeCollectionViewUpdates {
+  self.indexPathsOfDeletingItems = @[];
+}
+
 #pragma mark - Private
 
 // This sets the appropriate itemSize given the width of the collection view.
diff --git a/ios/chrome/browser/ui/tab_grid/tab_grid_page_control.h b/ios/chrome/browser/ui/tab_grid/tab_grid_page_control.h
new file mode 100644
index 0000000..2418fc4
--- /dev/null
+++ b/ios/chrome/browser/ui/tab_grid/tab_grid_page_control.h
@@ -0,0 +1,55 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_CHROME_BROWSER_UI_TAB_GRID_TAB_GRID_PAGE_CONTROL_H_
+#define IOS_CHROME_BROWSER_UI_TAB_GRID_TAB_GRID_PAGE_CONTROL_H_
+
+#import <UIKit/UIKit.h>
+
+#import "ios/chrome/browser/ui/tab_grid/tab_grid_paging.h"
+
+// A three-sectioned control for selecting a page in the tab grid.
+// A "slider" is positioned over the section for the selected page.
+// This is a fixed-size control; it's an error to set  or change its size.
+// The sections are arranged in leading-to-trailing order:
+//   incognito tabs, regular tabs, remote tabs.
+@interface TabGridPageControl : UIControl
+
+// The currently selected page in the control. When this value is changed by
+// a user interaction, the UIControlEventValueChanged actions are sent.
+// Setting this property will update the position of the slider without
+// animation. When an instance of this control is created, this value defaults
+// to TabGridPageRegularTabs.
+@property(nonatomic, assign) TabGridPage selectedPage;
+// The position of the slider, from 0.0 to 1.0, where 0.0 is as far as possible
+// to the leading side of the control, and 1.0 is as far as possible to the
+// trailing side of the control. Setting this property will update the position
+// of the slider without animation. Setting a value below 0.0 or above 1.0 will
+// set 0.0 or 1.0 instead.
+// Setting this property will *not* update the selected page.
+@property(nonatomic, assign) CGFloat sliderPosition;
+
+// Text displayed next to the incognito and inside the regular tabs icons. The
+// available space for text is small -- no wider than two numerals. Text wider
+// than this will be clipped.
+@property(nonatomic, copy) NSString* incognitoText;
+@property(nonatomic, copy) NSString* regularText;
+
+// Create and return a new instance of this control. This is the preferred way
+// to create instances of this class.
++ (instancetype)pageControl;
+
+// Designated initializer.
+- (instancetype)init NS_DESIGNATED_INITIALIZER;
+
+- (instancetype)initWithFrame:(CGRect)frame NS_UNAVAILABLE;
+- (instancetype)initWithCoder:(NSCoder*)aDecoder NS_UNAVAILABLE;
+
+// Set |selectedPage| as the selected page. If |animated| is YES, the
+// position change of the slider will be animated.
+- (void)setSelectedPage:(TabGridPage)selectedPage animated:(BOOL)animated;
+
+@end
+
+#endif  // IOS_CHROME_BROWSER_UI_TAB_GRID_TAB_GRID_PAGE_CONTROL_H_
diff --git a/ios/chrome/browser/ui/tab_grid/tab_grid_page_control.mm b/ios/chrome/browser/ui/tab_grid/tab_grid_page_control.mm
new file mode 100644
index 0000000..25525835
--- /dev/null
+++ b/ios/chrome/browser/ui/tab_grid/tab_grid_page_control.mm
@@ -0,0 +1,474 @@
+// 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/tab_grid/tab_grid_page_control.h"
+
+#import <CoreGraphics/CoreGraphics.h>
+
+#include "base/logging.h"
+#import "ios/chrome/browser/ui/uikit_ui_util.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+// Structure of this control:
+//
+// The page control is similar to a UISegmentedCoffee in appearance, but not in
+// function. This control doesn't have segments that highlight; instead there
+// is a white "slider" that moves across the view onto whichever segment is
+// active. Each segment has an image and (optionally) a label. When the slider
+// is over a segment, the corresponding image and label are colored black-on-
+// white and are slightly larger. This is implemented by having two versions of
+// each image and label; the larger "selected" versions are positioned above the
+// smaller ones in the view hierarchy but are masked out by the slider view, so
+// they are only seen when the slider is over them.
+//
+// This control is built out of several views. From the bottom up, they are:
+//
+//  * The background view, a grey roundrect with vertical transparent bars.
+//  * The background image views.
+//  * The numeric labels on the incognito and regular tab icons.
+//  * The "slider" view -- a white roundrect that's taller and wider than each
+//    of the background segments. It clips its subview to its bounds, and it
+//    adjusts its subview's frame so that it (the subview) remains fixed
+//    relative to the background.
+//     * The selected image view, which contains the selected images and labels
+//       and is a subview of the slider.
+//        * The selected images and labels.
+//
+// (Note that currently only labels are used; images will be added once assets
+// are available).
+
+// Notes on layout:
+// This control has an intrinsic size, and generally ignores frame changes. It's
+// not expected that its bounds will ever change.
+// Given that, it's generally simpler to used fixed (frame-based) layout for
+// most of the content of this control. However, in order to acommodate RTL
+// layout, three layout guides are used to define the position of the
+// incognito, regular, and remote tab sections. The layout frames of these
+// guides are used to map points in the view to specific TabGridPage values.
+// This means that the initial view layout for this control happens in two
+// phases. -setupViews creates all of the subviews and the layout guides, but
+// the positions of the images and labels is set in -layoutSubviews, after the
+// constrainst for the guides have been applied.
+
+namespace {
+// Height and width of the slider.
+const CGFloat kSliderHeight = 40.0;
+const CGFloat kSliderWidth = 78.0;
+
+// Height and width of each segment.
+const CGFloat kSegmentHeight = 36.0;
+const CGFloat kSegmentWidth = 64.0;
+
+// Points that the slider overhangs a segment on each side, or 0 if the slider
+// is narrower than a segment.
+const CGFloat kSliderOverhang = MAX((kSliderWidth - kSegmentWidth) / 2.0, 0.0);
+
+// Width of the separator bars between segments.
+const CGFloat kSeparatorWidth = 1.0;
+
+// Width of the background -- three segments plus two separators.
+const CGFloat kBackgroundWidth = 3 * kSegmentWidth + 2 * kSeparatorWidth;
+
+// Overall height of the control -- the larger of the slider and segment
+// heights.
+const CGFloat kOverallHeight = MAX(kSliderHeight, kSegmentHeight);
+// Overall width of the control -- the background width plusand twice
+// the slider overhang.
+const CGFloat kOverallWidth = kBackgroundWidth + 2 * kSliderOverhang;
+
+// Radius used to draw the background and the slider.
+const CGFloat kCornerRadius = 13.0;
+
+// Sizes for the labels and their selected counterparts.
+const CGFloat kLabelSize = 20.0;
+const CGFloat kSelectedLabelSize = 23.0;
+
+// Maximum duration of slider motion animation.
+const NSTimeInterval kSliderMoveDuration = 0.2;
+
+// Color for the slider
+const int kSliderColor = 0xF8F9FA;
+// Color for the background view.
+const int kBackgroundColor = 0x5F6368;
+
+// Returns the point that's at the center of |rect|.
+CGPoint RectCenter(CGRect rect) {
+  return CGPointMake(CGRectGetMidX(rect), CGRectGetMidY(rect));
+}
+}
+
+// View class used for the background of this control; it draws the grey
+// rectangles with clear separators.
+@interface TabGridPageControlBackground : UIView
+@end
+
+@interface TabGridPageControl ()<UIGestureRecognizerDelegate>
+// Layout guides used to position segment-specific content.
+@property(nonatomic, weak) UILayoutGuide* incognitoGuide;
+@property(nonatomic, weak) UILayoutGuide* regularGuide;
+@property(nonatomic, weak) UILayoutGuide* remoteGuide;
+// The view for the slider.
+@property(nonatomic, weak) UIView* sliderView;
+// The view for the selected images and labels (a subview of |sliderView).
+@property(nonatomic, weak) UIView* selectedImageView;
+// The labels for the incognito and regular sections, in regular and selected
+// variants.
+@property(nonatomic, weak) UILabel* incognitoLabel;
+@property(nonatomic, weak) UILabel* incognitoSelectedLabel;
+@property(nonatomic, weak) UILabel* regularLabel;
+@property(nonatomic, weak) UILabel* regularSelectedLabel;
+// Temporary labels for the remote tabs section, to be replaced by image assets.
+@property(nonatomic, weak) UILabel* remoteLabel;
+@property(nonatomic, weak) UILabel* remoteSelectedLabel;
+// The center point for the slider corresponding to a |sliderPosition| of 0.
+@property(nonatomic) CGFloat sliderOrigin;
+// The (signed) x-coordinate distance the slider moves over. The slider's
+// position is set by adding a fraction of this distance to |sliderOrigin|, so
+// that when |sliderRange| is negative (in RTL layout), the slider will move in
+// the negative-x direction from |sliderOrigin|, and otherwise it will move in
+// the positive-x direction.
+@property(nonatomic) CGFloat sliderRange;
+@end
+
+@implementation TabGridPageControl
+// Public properties
+@synthesize selectedPage = _selectedPage;
+@synthesize sliderPosition = _sliderPosition;
+@synthesize incognitoText = _incognitoText;
+@synthesize regularText = _regularText;
+// Private properties
+@synthesize incognitoGuide = _incognitoGuide;
+@synthesize regularGuide = _regularGuide;
+@synthesize remoteGuide = _remoteGuide;
+@synthesize sliderView = _sliderView;
+@synthesize selectedImageView = _selectedImageView;
+@synthesize incognitoLabel = _incognitoLabel;
+@synthesize incognitoSelectedLabel = _incognitoSelectedLabel;
+@synthesize regularLabel = _regularLabel;
+@synthesize regularSelectedLabel = _regularSelectedLabel;
+@synthesize remoteLabel = _remoteLabel;
+@synthesize remoteSelectedLabel = _remoteSelectedLabel;
+@synthesize sliderOrigin = _sliderOrigin;
+@synthesize sliderRange = _sliderRange;
+
++ (instancetype)pageControl {
+  return [[TabGridPageControl alloc] init];
+}
+
+- (instancetype)init {
+  CGRect frame = CGRectMake(0, 0, kOverallWidth, kOverallHeight);
+  if (self = [super initWithFrame:frame]) {
+    // Default to the regular tab page as the selected page.
+
+    _selectedPage = TabGridPageRegularTabs;
+  }
+  return self;
+}
+
+#pragma mark - Public Properies
+
+- (void)setSelectedPage:(TabGridPage)selectedPage {
+  [self setSelectedPage:selectedPage animated:NO];
+}
+
+- (void)setSliderPosition:(CGFloat)sliderPosition {
+  // Clamp |selectionOffset| to (0.0 - 1.0).
+  sliderPosition = MIN(MAX(0.0, sliderPosition), 1.0);
+  CGPoint center = self.sliderView.center;
+  center.x = self.sliderOrigin + self.sliderRange * sliderPosition;
+  self.sliderView.center = center;
+  // Reposition the selected image view so that it's still centered in the
+  // control itself.
+  self.selectedImageView.center =
+      [self convertPoint:RectCenter(self.bounds) toView:self.sliderView];
+  _sliderPosition = sliderPosition;
+}
+
+// Setters for the control's text values. These need to update three things:
+// the text in both labels (the regular and the  "selected" versions that's
+// visible when the slider is over a segment), and an ivar to store values that
+// are set before the labels are created.
+- (void)setIncognitoText:(NSString*)incognitoText {
+  self.incognitoLabel.text = incognitoText;
+  self.incognitoSelectedLabel.text = incognitoText;
+  _incognitoText = [incognitoText copy];
+}
+
+- (void)setRegularText:(NSString*)regularText {
+  self.regularLabel.text = regularText;
+  self.regularSelectedLabel.text = regularText;
+  _regularText = [regularText copy];
+}
+
+#pragma mark - Public methods
+
+- (void)setSelectedPage:(TabGridPage)selectedPage animated:(BOOL)animated {
+  CGFloat newPosition;
+  switch (selectedPage) {
+    case TabGridPageIncognitoTabs:
+      newPosition = 0.0;
+      break;
+    case TabGridPageRegularTabs:
+      newPosition = 0.5;
+      break;
+    case TabGridPageRemoteTabs:
+      newPosition = 1.0;
+      break;
+  }
+  if (self.selectedPage == selectedPage && newPosition == self.sliderPosition) {
+    return;
+  }
+
+  _selectedPage = selectedPage;
+  if (animated) {
+    // Scale duration to the distance the slider travels, but cap it at
+    // the slider move duration. This means that for motion induced by
+    // tapping on a section, the duration will be the same even if the slider
+    // is moving across two segments.
+    CGFloat offsetDelta = abs(newPosition - self.sliderPosition);
+    NSTimeInterval duration = offsetDelta * kSliderMoveDuration;
+    [UIView animateWithDuration:MIN(duration, kSliderMoveDuration)
+                     animations:^{
+                       self.sliderPosition = newPosition;
+                     }];
+  } else {
+    self.sliderPosition = newPosition;
+  }
+}
+
+#pragma mark - UIView
+
+- (CGSize)intrinsicContentSize {
+  return CGSizeMake(kOverallWidth, kOverallHeight);
+}
+
+- (void)willMoveToSuperview:(UIView*)newSuperview {
+  // The first time this moves to a superview, perform the view setup.
+  if (newSuperview && self.subviews.count == 0) {
+    [self setupViews];
+  }
+}
+
+- (void)layoutSubviews {
+  // The superclass call should be made first, so the constraint-based layout
+  // guides can be set correctly.
+  [super layoutSubviews];
+  // Position the section images and labels, which depend on the layout guides.
+  self.incognitoLabel.center = [self centerOfSegment:TabGridPageIncognitoTabs];
+  self.incognitoSelectedLabel.center =
+      [self centerOfSegment:TabGridPageIncognitoTabs];
+
+  self.regularLabel.center = [self centerOfSegment:TabGridPageRegularTabs];
+  self.regularSelectedLabel.center =
+      [self centerOfSegment:TabGridPageRegularTabs];
+
+  self.remoteLabel.center = [self centerOfSegment:TabGridPageRemoteTabs];
+  self.remoteSelectedLabel.center =
+      [self centerOfSegment:TabGridPageRemoteTabs];
+
+  // Determine the slider origin and range; this is based on the layout guides
+  // and can't be computed until they are determined.
+  self.sliderOrigin = CGRectGetMidX(self.incognitoGuide.layoutFrame);
+  self.sliderRange =
+      CGRectGetMidX(self.remoteGuide.layoutFrame) - self.sliderOrigin;
+
+  // Set the slider position using the new slider origin and range.
+  self.sliderPosition = _sliderPosition;
+}
+
+#pragma mark - Private
+
+// Sets up all of the subviews for this control, as well as the layout guides
+// used to position the section content.
+- (void)setupViews {
+  UIView* backgroundView = [[TabGridPageControlBackground alloc] init];
+  backgroundView.layer.cornerRadius = kCornerRadius;
+  backgroundView.layer.masksToBounds = YES;
+  [self addSubview:backgroundView];
+  backgroundView.center =
+      CGPointMake(kOverallWidth / 2.0, kOverallHeight / 2.0);
+
+  // Set up the layout guides for the segments.
+  UILayoutGuide* incognitoGuide = [[UILayoutGuide alloc] init];
+  [self addLayoutGuide:incognitoGuide];
+  self.incognitoGuide = incognitoGuide;
+  UILayoutGuide* regularGuide = [[UILayoutGuide alloc] init];
+  [self addLayoutGuide:regularGuide];
+  self.regularGuide = regularGuide;
+  UILayoutGuide* remoteGuide = [[UILayoutGuide alloc] init];
+  [self addLayoutGuide:remoteGuide];
+  self.remoteGuide = remoteGuide;
+
+  // All of the guides are of the same height, and vertically centered in the
+  // control.
+  for (UILayoutGuide* guide in @[ incognitoGuide, regularGuide, remoteGuide ]) {
+    [guide.heightAnchor constraintEqualToConstant:kOverallHeight].active = YES;
+    [guide.centerYAnchor constraintEqualToAnchor:self.centerYAnchor].active =
+        YES;
+  }
+
+  // Guides are all the same width (except the regular guide is wider to include
+  // the separators on either side of it. The regular guide is centered in the
+  // control, and the incognito and remote guides are on the leading and
+  // trailing sides of it.
+  [NSLayoutConstraint activateConstraints:@[
+    [incognitoGuide.widthAnchor constraintEqualToConstant:kSegmentWidth],
+    [regularGuide.widthAnchor
+        constraintEqualToConstant:kSegmentWidth + 2 * kSeparatorWidth],
+    [remoteGuide.widthAnchor constraintEqualToConstant:kSegmentWidth],
+    [regularGuide.centerXAnchor constraintEqualToAnchor:self.centerXAnchor],
+    [incognitoGuide.trailingAnchor
+        constraintEqualToAnchor:regularGuide.leadingAnchor],
+    [remoteGuide.leadingAnchor
+        constraintEqualToAnchor:regularGuide.trailingAnchor]
+  ]];
+
+  // Create the section images and labels and add them below the slider.
+  UILabel* incognitoLabel = [self labelSelected:NO incognito:YES];
+  [self addSubview:incognitoLabel];
+  self.incognitoLabel = incognitoLabel;
+
+  UILabel* regularLabel = [self labelSelected:NO incognito:NO];
+  [self addSubview:regularLabel];
+  self.regularLabel = regularLabel;
+
+  // Add the slider above the section images and labels.
+  CGRect sliderFrame = CGRectMake(0, 0, kSliderWidth, kSliderHeight);
+  UIView* slider = [[UIView alloc] initWithFrame:sliderFrame];
+  slider.layer.cornerRadius = kCornerRadius;
+  slider.layer.masksToBounds = YES;
+  slider.backgroundColor = UIColorFromRGB(kSliderColor);
+
+  [self addSubview:slider];
+  self.sliderView = slider;
+
+  UIView* selectedImageView = [[UIView alloc]
+      initWithFrame:(CGRectMake(0, 0, kOverallWidth, kOverallHeight))];
+  [self.sliderView addSubview:selectedImageView];
+  self.selectedImageView = selectedImageView;
+
+  // Add the selected images and labels to the selected image view so they
+  // will be clipped by it.
+  UILabel* incognitoSelectedLabel = [self labelSelected:YES incognito:YES];
+  [self.selectedImageView addSubview:incognitoSelectedLabel];
+  self.incognitoSelectedLabel = incognitoSelectedLabel;
+
+  UILabel* regularSelectedLabel = [self labelSelected:YES incognito:NO];
+  [self.selectedImageView addSubview:regularSelectedLabel];
+  self.regularSelectedLabel = regularSelectedLabel;
+
+  // Create a temporary label for the remote tabs section.
+  // TODO(crbug.com/804500): Remove this when assets are available.
+  UILabel* remoteLabel = [self labelSelected:NO incognito:NO];
+  [self insertSubview:remoteLabel belowSubview:self.sliderView];
+  self.remoteLabel = remoteLabel;
+  UILabel* remoteSelectedLabel = [self labelSelected:YES incognito:NO];
+  [self.selectedImageView addSubview:remoteSelectedLabel];
+  self.remoteSelectedLabel = remoteSelectedLabel;
+  remoteLabel.text = @"R";
+  remoteSelectedLabel.text = @"R";
+
+  // Update the label text, in case these properties have been set before the
+  // views were set up.
+  self.regularText = _regularText;
+  self.incognitoText = _incognitoText;
+
+  // Mark the control's layout as dirty so the the guides will be computed, then
+  // force a layout now so it won't be triggered later (perhaps during an
+  // animation).
+  [self setNeedsLayout];
+  [self layoutIfNeeded];
+
+  // Add the gesture recognizer for taps on this control.
+  UITapGestureRecognizer* tapRecognizer =
+      [[UITapGestureRecognizer alloc] initWithTarget:self
+                                              action:@selector(handleTap:)];
+  [self addGestureRecognizer:tapRecognizer];
+}
+
+// Creates a label for use in this control.
+// Selected labels use a different size and are black.
+// Incognito labels have a solid background and use inverted text.
+- (UILabel*)labelSelected:(BOOL)selected incognito:(BOOL)incognito {
+  CGFloat size = selected ? kSelectedLabelSize : kLabelSize;
+  UIColor* color = selected ? UIColor.blackColor : UIColor.lightGrayColor;
+  UILabel* label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, size, size)];
+  label.backgroundColor = incognito ? color : UIColor.clearColor;
+  label.layer.borderWidth = 2.5;
+  label.layer.borderColor = color.CGColor;
+  label.layer.masksToBounds = YES;
+  label.layer.cornerRadius = 6.0;
+  label.textAlignment = NSTextAlignmentCenter;
+  label.textColor = incognito ? (selected ? UIColorFromRGB(kSliderColor)
+                                          : UIColorFromRGB(kBackgroundColor))
+                              : color;
+  label.font =
+      [UIFont systemFontOfSize:size * .6 weight:UIFontWeightBold];  // ?
+  return label;
+}
+
+// Handles tap gesture recognizer taps, setting a new selected page if the
+// tap was outside the current page and sending the value changed actions.
+- (void)handleTap:(UIGestureRecognizer*)tapRecognizer {
+  CGPoint point = [tapRecognizer locationInView:self];
+  // Determine which section the tap is in by looking at the layout frames of
+  // each guide.
+  TabGridPage page;
+  if (CGRectContainsPoint(self.incognitoGuide.layoutFrame, point)) {
+    page = TabGridPageIncognitoTabs;
+  } else if (CGRectContainsPoint(self.remoteGuide.layoutFrame, point)) {
+    page = TabGridPageRemoteTabs;
+  } else {
+    // bug: taps in the left- or rightmost |kSliderOverhang| points of the
+    // control will fall through to this case.
+    // TODO(crbug.com/804500): Fix this.
+    page = TabGridPageRegularTabs;
+  }
+  if (page != self.selectedPage) {
+    [self setSelectedPage:page animated:YES];
+    [self sendActionsForControlEvents:UIControlEventValueChanged];
+  }
+}
+
+// Returns the point at the center of |segment|.
+- (CGPoint)centerOfSegment:(TabGridPage)segment {
+  switch (segment) {
+    case TabGridPageIncognitoTabs:
+      return RectCenter(self.incognitoGuide.layoutFrame);
+    case TabGridPageRegularTabs:
+      return RectCenter(self.regularGuide.layoutFrame);
+    case TabGridPageRemoteTabs:
+      return RectCenter(self.remoteGuide.layoutFrame);
+  }
+}
+
+@end
+
+@implementation TabGridPageControlBackground
+
+- (instancetype)init {
+  return
+      [super initWithFrame:CGRectMake(0, 0, kBackgroundWidth, kSegmentHeight)];
+}
+
+- (CGSize)intrinsicContentsSize {
+  return CGSizeMake(kBackgroundWidth, kSegmentHeight);
+}
+
+- (void)drawRect:(CGRect)rect {
+  CGContextRef drawing = UIGraphicsGetCurrentContext();
+  UIColor* backgroundColor = UIColorFromRGB(kBackgroundColor);
+  CGContextSetFillColorWithColor(drawing, backgroundColor.CGColor);
+  CGRect fillRect = CGRectMake(0, 0, kSegmentWidth, kSegmentHeight);
+  CGContextFillRect(drawing, fillRect);
+  fillRect.origin.x += kSegmentWidth + kSeparatorWidth;
+  CGContextFillRect(drawing, fillRect);
+  fillRect.origin.x += kSegmentWidth + kSeparatorWidth;
+  CGContextFillRect(drawing, fillRect);
+}
+
+@end
diff --git a/ios/chrome/browser/ui/tab_grid/tab_grid_top_toolbar.h b/ios/chrome/browser/ui/tab_grid/tab_grid_top_toolbar.h
index f28fd18..a2906d3 100644
--- a/ios/chrome/browser/ui/tab_grid/tab_grid_top_toolbar.h
+++ b/ios/chrome/browser/ui/tab_grid/tab_grid_top_toolbar.h
@@ -7,6 +7,8 @@
 
 #import <UIKit/UIKit.h>
 
+@class TabGridPageControl;
+
 // Toolbar view with two text buttons and a segmented control. The contents have
 // a fixed height and are pinned to the bottom of this view, therefore it is
 // intended to be used as a top toolbar.
@@ -15,7 +17,7 @@
 // contents, visibility and actions.
 @property(nonatomic, weak, readonly) UIButton* leadingButton;
 @property(nonatomic, weak, readonly) UIButton* trailingButton;
-@property(nonatomic, weak, readonly) UIView* segmentedControl;
+@property(nonatomic, weak, readonly) TabGridPageControl* pageControl;
 
 - (instancetype)init NS_DESIGNATED_INITIALIZER;
 - (instancetype)initWithFrame:(CGRect)frame NS_UNAVAILABLE;
diff --git a/ios/chrome/browser/ui/tab_grid/tab_grid_top_toolbar.mm b/ios/chrome/browser/ui/tab_grid/tab_grid_top_toolbar.mm
index e011ad4..8e549ce7 100644
--- a/ios/chrome/browser/ui/tab_grid/tab_grid_top_toolbar.mm
+++ b/ios/chrome/browser/ui/tab_grid/tab_grid_top_toolbar.mm
@@ -4,22 +4,21 @@
 
 #import "ios/chrome/browser/ui/tab_grid/tab_grid_top_toolbar.h"
 
+#import "ios/chrome/browser/ui/tab_grid/tab_grid_page_control.h"
+
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
 #endif
 
 namespace {
 // Height of the toolbar.
-const CGFloat kToolbarHeight = 44.0f;
-// Height of the segmented control. The segmented control should have an
-// intrinsic width.
-const CGFloat kSegmentedControlHeight = 30.0f;
+const CGFloat kToolbarHeight = 52.0f;
 }  // namespace
 
 @implementation TabGridTopToolbar
 @synthesize leadingButton = _leadingButton;
 @synthesize trailingButton = _trailingButton;
-@synthesize segmentedControl = _segmentedControl;
+@synthesize pageControl = _pageControl;
 
 - (instancetype)init {
   if (self = [super initWithFrame:CGRectZero]) {
@@ -37,12 +36,9 @@
     leadingButton.titleLabel.adjustsFontForContentSizeCategory = YES;
     leadingButton.tintColor = [UIColor whiteColor];
 
-    UILabel* segmentedControl = [[UILabel alloc] init];
-    segmentedControl.translatesAutoresizingMaskIntoConstraints = NO;
-    segmentedControl.backgroundColor = [UIColor whiteColor];
-    segmentedControl.text = @"Segmented Control";
-    segmentedControl.layer.cornerRadius = 11.0f;
-    segmentedControl.layer.masksToBounds = YES;
+    // The segmented control has an intrinsic size.
+    TabGridPageControl* pageControl = [[TabGridPageControl alloc] init];
+    pageControl.translatesAutoresizingMaskIntoConstraints = NO;
 
     UIButton* trailingButton = [UIButton buttonWithType:UIButtonTypeSystem];
     trailingButton.translatesAutoresizingMaskIntoConstraints = NO;
@@ -53,10 +49,10 @@
 
     [toolbar.contentView addSubview:leadingButton];
     [toolbar.contentView addSubview:trailingButton];
-    [toolbar.contentView addSubview:segmentedControl];
+    [toolbar.contentView addSubview:pageControl];
     _leadingButton = leadingButton;
     _trailingButton = trailingButton;
-    _segmentedControl = segmentedControl;
+    _pageControl = pageControl;
 
     NSArray* constraints = @[
       [toolbar.topAnchor constraintEqualToAnchor:self.topAnchor],
@@ -67,13 +63,9 @@
       [leadingButton.leadingAnchor
           constraintEqualToAnchor:toolbar.layoutMarginsGuide.leadingAnchor],
       [leadingButton.bottomAnchor constraintEqualToAnchor:toolbar.bottomAnchor],
-      [segmentedControl.heightAnchor
-          constraintEqualToConstant:kSegmentedControlHeight],
-      [segmentedControl.centerXAnchor
-          constraintEqualToAnchor:toolbar.centerXAnchor],
-      [segmentedControl.bottomAnchor
-          constraintEqualToAnchor:toolbar.bottomAnchor
-                         constant:-7.0f],
+      [pageControl.centerXAnchor constraintEqualToAnchor:toolbar.centerXAnchor],
+      [pageControl.bottomAnchor constraintEqualToAnchor:toolbar.bottomAnchor
+                                               constant:-7.0f],
       [trailingButton.heightAnchor constraintEqualToConstant:kToolbarHeight],
       [trailingButton.trailingAnchor
           constraintEqualToAnchor:toolbar.layoutMarginsGuide.trailingAnchor],
diff --git a/ios/chrome/browser/ui/tab_grid/tab_grid_view_controller.mm b/ios/chrome/browser/ui/tab_grid/tab_grid_view_controller.mm
index 00b566d..62dbe58 100644
--- a/ios/chrome/browser/ui/tab_grid/tab_grid_view_controller.mm
+++ b/ios/chrome/browser/ui/tab_grid/tab_grid_view_controller.mm
@@ -10,6 +10,7 @@
 #import "ios/chrome/browser/ui/tab_grid/grid_image_data_source.h"
 #import "ios/chrome/browser/ui/tab_grid/grid_view_controller.h"
 #import "ios/chrome/browser/ui/tab_grid/tab_grid_bottom_toolbar.h"
+#import "ios/chrome/browser/ui/tab_grid/tab_grid_page_control.h"
 #import "ios/chrome/browser/ui/tab_grid/tab_grid_top_toolbar.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -134,6 +135,15 @@
 
 #pragma mark - UIScrollViewDelegate
 
+- (void)scrollViewDidScroll:(UIScrollView*)scrollView {
+  if (scrollView.dragging) {
+    CGFloat offsetWidth =
+        self.scrollView.contentSize.width - self.scrollView.frame.size.width;
+    CGFloat offset = scrollView.contentOffset.x / offsetWidth;
+    self.topToolbar.pageControl.sliderPosition = offset;
+  }
+}
+
 - (void)scrollViewDidEndDecelerating:(UIScrollView*)scrollView {
   // Bookkeeping for the current page.
   CGFloat pageWidth = scrollView.frame.size.width;
@@ -526,6 +536,7 @@
     self.doneButton = self.topToolbar.trailingButton;
     self.closeAllButton = self.topToolbar.leadingButton;
   }
+
   // TODO(crbug.com/818699) : Localize strings.
   [self.doneButton setTitle:@"Done" forState:UIControlStateNormal];
   [self.closeAllButton setTitle:@"Close All" forState:UIControlStateNormal];
@@ -539,10 +550,17 @@
   [self.newTabButton addTarget:self
                         action:@selector(newTabButtonTapped:)
               forControlEvents:UIControlEventTouchUpInside];
+  [self.topToolbar.pageControl addTarget:self
+                                  action:@selector(pageControlChanged:)
+                        forControlEvents:UIControlEventValueChanged];
+  // TODO(crbug.com/804501): Use the actual live tab counts.
+  self.topToolbar.pageControl.regularText = @"5";
+  self.topToolbar.pageControl.incognitoText = @"0";
   [self configureButtonsForCurrentPage];
 }
 
 - (void)configureButtonsForCurrentPage {
+  [self.topToolbar.pageControl setSelectedPage:self.currentPage animated:YES];
   switch (self.currentPage) {
     case TabGridPageIncognitoTabs:
       self.doneButton.enabled = !self.incognitoTabsViewController.isGridEmpty;
@@ -671,7 +689,7 @@
   [self configureButtonsForCurrentPage];
 }
 
-#pragma mark - Button actions
+#pragma mark - Control actions
 
 - (void)doneButtonTapped:(id)sender {
   [self.tabPresentationDelegate showActiveTab];
@@ -707,4 +725,8 @@
   }
 }
 
+- (void)pageControlChanged:(id)sender {
+  self.currentPage = self.topToolbar.pageControl.selectedPage;
+}
+
 @end
diff --git a/ios/chrome/browser/ui/table_view/cells/table_view_text_header_footer_item.h b/ios/chrome/browser/ui/table_view/cells/table_view_text_header_footer_item.h
index af154aa5..a8b8bd3d 100644
--- a/ios/chrome/browser/ui/table_view/cells/table_view_text_header_footer_item.h
+++ b/ios/chrome/browser/ui/table_view/cells/table_view_text_header_footer_item.h
@@ -12,14 +12,13 @@
 // TableViewTextHeaderFooterItem contains the model data for a
 // UITableViewHeaderFooterView.
 @interface TableViewTextHeaderFooterItem : TableViewHeaderFooterItem
-
 @property(nonatomic, readwrite, strong) NSString* text;
-
+@property(nonatomic, readwrite, strong) NSString* subtitleText;
 @end
 
 // UITableViewHeaderFooterView that displays a text label.
 @interface TableViewTextHeaderFooterView : UITableViewHeaderFooterView
-
+@property(nonatomic, readwrite, strong) UILabel* subtitleLabel;
 @end
 
 #endif  // IOS_CHROME_BROWSER_UI_TABLE_VIEW_CELLS_TABLE_VIEW_TEXT_HEADER_FOOTER_ITEM_H_
diff --git a/ios/chrome/browser/ui/table_view/cells/table_view_text_header_footer_item.mm b/ios/chrome/browser/ui/table_view/cells/table_view_text_header_footer_item.mm
index 51b5221a..5a9bd8a 100644
--- a/ios/chrome/browser/ui/table_view/cells/table_view_text_header_footer_item.mm
+++ b/ios/chrome/browser/ui/table_view/cells/table_view_text_header_footer_item.mm
@@ -14,9 +14,13 @@
 namespace {
 // The inner insets of the View content.
 const CGFloat kMargin = 16;
+
+// The vertical spacing between text labels.
+const CGFloat kVerticalSpacing = 2.0;
 }
 
 @implementation TableViewTextHeaderFooterItem
+@synthesize subtitleText = _subtitleText;
 @synthesize text = _text;
 
 - (instancetype)initWithType:(NSInteger)type {
@@ -37,8 +41,7 @@
   TableViewTextHeaderFooterView* header =
       base::mac::ObjCCastStrict<TableViewTextHeaderFooterView>(headerFooter);
   header.textLabel.text = self.text;
-  header.textLabel.font =
-      [UIFont preferredFontForTextStyle:UIFontTextStyleHeadline];
+  header.subtitleLabel.text = self.subtitleText;
 }
 
 @end
@@ -46,21 +49,33 @@
 #pragma mark - TableViewTextHeaderFooter
 
 @implementation TableViewTextHeaderFooterView
+@synthesize subtitleLabel = _subtitleLabel;
 @synthesize textLabel = _textLabel;
 
 - (instancetype)initWithReuseIdentifier:(NSString*)reuseIdentifier {
   self = [super initWithReuseIdentifier:reuseIdentifier];
   if (self) {
-    // Text Label, set font sizes using dynamic type.
+    // Labels, set font sizes using dynamic type.
     _textLabel = [[UILabel alloc] init];
-    _textLabel.translatesAutoresizingMaskIntoConstraints = NO;
+    _textLabel.font =
+        [UIFont preferredFontForTextStyle:UIFontTextStyleHeadline];
+    _subtitleLabel = [[UILabel alloc] init];
+    _subtitleLabel.font =
+        [UIFont preferredFontForTextStyle:UIFontTextStyleCaption1];
+
+    // Vertical StackView.
+    UIStackView* verticalStack = [[UIStackView alloc]
+        initWithArrangedSubviews:@[ _textLabel, _subtitleLabel ]];
+    verticalStack.axis = UILayoutConstraintAxisVertical;
+    verticalStack.spacing = kVerticalSpacing;
+    verticalStack.translatesAutoresizingMaskIntoConstraints = NO;
 
     // Container View.
     UIView* containerView = [[UIView alloc] init];
     containerView.translatesAutoresizingMaskIntoConstraints = NO;
 
     // Add subviews to View Hierarchy.
-    [containerView addSubview:_textLabel];
+    [containerView addSubview:verticalStack];
     [self.contentView addSubview:containerView];
 
     // Set and activate constraints.
@@ -80,12 +95,14 @@
                                    constant:-kMargin],
       [containerView.centerYAnchor
           constraintEqualToAnchor:self.contentView.centerYAnchor],
-      // Title Label Constraints.
-      [_textLabel.leadingAnchor
+      // Vertical StackView Constraints.
+      [verticalStack.leadingAnchor
           constraintEqualToAnchor:containerView.leadingAnchor],
-      [_textLabel.topAnchor constraintEqualToAnchor:containerView.topAnchor],
-      [_textLabel.bottomAnchor
+      [verticalStack.topAnchor constraintEqualToAnchor:containerView.topAnchor],
+      [verticalStack.bottomAnchor
           constraintEqualToAnchor:containerView.bottomAnchor],
+      [verticalStack.trailingAnchor
+          constraintEqualToAnchor:containerView.trailingAnchor],
     ]];
   }
   return self;
diff --git a/ios/third_party/material_components_ios/README.chromium b/ios/third_party/material_components_ios/README.chromium
index c0b922b2..0353d28 100644
--- a/ios/third_party/material_components_ios/README.chromium
+++ b/ios/third_party/material_components_ios/README.chromium
@@ -1,7 +1,7 @@
 Name: Material Components for iOS
 URL: https://github.com/material-components/material-components-ios
 Version: 0
-Revision: 7d2e0214553aba8b5bb09fbe023df0f0dc48005a
+Revision: dd21af4fef24ddb42d39e9610b84109273c50899
 License: Apache 2.0
 License File: LICENSE
 Security Critical: yes
diff --git a/ipc/ipc_channel_proxy_unittest.cc b/ipc/ipc_channel_proxy_unittest.cc
index 08e4011..2bf18d4 100644
--- a/ipc/ipc_channel_proxy_unittest.cc
+++ b/ipc/ipc_channel_proxy_unittest.cc
@@ -418,14 +418,11 @@
   std::unique_ptr<QuitListener> listener_;
 };
 
-#if !defined(OS_WIN)
-  // TODO(jam): for some reason this is flaky on win buildbots.
 TEST_F(IPCChannelBadMessageTest, BadMessage) {
   sender()->Send(new TestMsg_SendBadMessage());
   SendQuitMessageAndWaitForIdle();
   EXPECT_TRUE(DidListenerGetBadMessage());
 }
-#endif
 
 DEFINE_IPC_CHANNEL_MOJO_TEST_CLIENT(ChannelProxyClient) {
   ChannelReflectorListener listener;
diff --git a/media/cast/net/udp_socket_client_unittest.cc b/media/cast/net/udp_socket_client_unittest.cc
index 5dacda40..c1b00df 100644
--- a/media/cast/net/udp_socket_client_unittest.cc
+++ b/media/cast/net/udp_socket_client_unittest.cc
@@ -138,8 +138,21 @@
                                                   std::move(receiver));
     OnUDPSocketCreated();
   }
+  void CreateTCPServerSocket(
+      const net::IPEndPoint& local_addr,
+      uint32_t backlog,
+      const net::MutableNetworkTrafficAnnotationTag& traffic_annotation,
+      network::mojom::TCPServerSocketRequest request,
+      CreateTCPServerSocketCallback callback) override {}
+  void CreateTCPConnectedSocket(
+      const base::Optional<net::IPEndPoint>& local_addr,
+      const net::AddressList& remote_addr_list,
+      const net::MutableNetworkTrafficAnnotationTag& traffic_annotation,
+      network::mojom::TCPConnectedSocketRequest request,
+      network::mojom::TCPConnectedSocketObserverPtr observer,
+      CreateTCPConnectedSocketCallback callback) override {}
 
-  MockUdpSocket* udp_socket() const { return udp_socket_.get(); };
+  MockUdpSocket* udp_socket() const { return udp_socket_.get(); }
 
  private:
   mojo::Binding<network::mojom::NetworkContext> binding_;
diff --git a/media/gpu/vaapi/vaapi_picture_native_pixmap.cc b/media/gpu/vaapi/vaapi_picture_native_pixmap.cc
index 6ef8b6e..9c3274ac 100644
--- a/media/gpu/vaapi/vaapi_picture_native_pixmap.cc
+++ b/media/gpu/vaapi/vaapi_picture_native_pixmap.cc
@@ -10,6 +10,7 @@
 #include "ui/gfx/gpu_memory_buffer.h"
 #include "ui/gfx/linux/native_pixmap_dmabuf.h"
 #include "ui/gfx/native_pixmap.h"
+#include "ui/gl/gl_bindings.h"
 #include "ui/gl/gl_image_native_pixmap.h"
 
 namespace media {
diff --git a/media/gpu/vaapi/vaapi_video_decode_accelerator.cc b/media/gpu/vaapi/vaapi_video_decode_accelerator.cc
index 1285d1d..8a53263 100644
--- a/media/gpu/vaapi/vaapi_video_decode_accelerator.cc
+++ b/media/gpu/vaapi/vaapi_video_decode_accelerator.cc
@@ -173,6 +173,8 @@
   vaapi_wrapper_ = VaapiWrapper::CreateForVideoCodec(
       VaapiWrapper::kDecode, profile, base::Bind(&ReportToUMA, VAAPI_ERROR));
 
+  UMA_HISTOGRAM_BOOLEAN("Media.VAVDA.VaapiWrapperCreationSuccess",
+                        vaapi_wrapper_.get());
   if (!vaapi_wrapper_.get()) {
     VLOGF(1) << "Failed initializing VAAPI for profile "
              << GetProfileName(profile);
@@ -181,13 +183,13 @@
 
   if (profile >= H264PROFILE_MIN && profile <= H264PROFILE_MAX) {
     decoder_.reset(new H264Decoder(
-        std::make_unique<VaapiH264Accelerator>(this, vaapi_wrapper_.get())));
+        std::make_unique<VaapiH264Accelerator>(this, vaapi_wrapper_)));
   } else if (profile >= VP8PROFILE_MIN && profile <= VP8PROFILE_MAX) {
     decoder_.reset(new VP8Decoder(
         std::make_unique<VaapiVP8Accelerator>(this, vaapi_wrapper_)));
   } else if (profile >= VP9PROFILE_MIN && profile <= VP9PROFILE_MAX) {
     decoder_.reset(new VP9Decoder(
-        std::make_unique<VaapiVP9Accelerator>(this, vaapi_wrapper_.get())));
+        std::make_unique<VaapiVP9Accelerator>(this, vaapi_wrapper_)));
   } else {
     VLOGF(1) << "Unsupported profile " << GetProfileName(profile);
     return false;
@@ -222,7 +224,7 @@
   }
   // Notify the client a picture is ready to be displayed.
   ++num_frames_at_client_;
-  TRACE_COUNTER1("media,gpu", "Textures at client", num_frames_at_client_);
+  TRACE_COUNTER1("media,gpu", "Vaapi frames at client", num_frames_at_client_);
   VLOGF(4) << "Notifying output picture id " << output_id << " for input "
            << input_id
            << " is ready. visible rect: " << visible_rect.ToString();
@@ -284,7 +286,7 @@
     input_buffers_.push(std::move(input_buffer));
   }
 
-  TRACE_COUNTER1("media,gpu", "Input buffers", input_buffers_.size());
+  TRACE_COUNTER1("media,gpu", "Vaapi input buffers", input_buffers_.size());
 
   switch (state_) {
     case kIdle:
@@ -609,7 +611,7 @@
   }
 
   --num_frames_at_client_;
-  TRACE_COUNTER1("media,gpu", "Textures at client", num_frames_at_client_);
+  TRACE_COUNTER1("media,gpu", "Vaapi frames at client", num_frames_at_client_);
 
   output_buffers_.push(picture_buffer_id);
   TryOutputSurface();
@@ -709,7 +711,7 @@
   // Drop all remaining input buffers, if present.
   while (!input_buffers_.empty())
     input_buffers_.pop();
-  TRACE_COUNTER1("media,gpu", "Input buffers", input_buffers_.size());
+  TRACE_COUNTER1("media,gpu", "Vaapi input buffers", input_buffers_.size());
 
   decoder_thread_task_runner_->PostTask(
       FROM_HERE, base::Bind(&VaapiVideoDecodeAccelerator::ResetTask,
diff --git a/media/gpu/vaapi/vaapi_wrapper.cc b/media/gpu/vaapi/vaapi_wrapper.cc
index 91b72c6..764c64c0 100644
--- a/media/gpu/vaapi/vaapi_wrapper.cc
+++ b/media/gpu/vaapi/vaapi_wrapper.cc
@@ -18,6 +18,7 @@
 #include "base/environment.h"
 #include "base/logging.h"
 #include "base/macros.h"
+#include "base/metrics/histogram_macros.h"
 #include "base/numerics/safe_conversions.h"
 #include "base/stl_util.h"
 #include "base/sys_info.h"
@@ -164,6 +165,9 @@
   void SetDrmFd(base::PlatformFile fd) { drm_fd_.reset(HANDLE_EINTR(dup(fd))); }
 
  private:
+  // Implementation of Initialize() called only once.
+  bool InitializeOnce();
+
   // Protected by |va_lock_|.
   int refcount_;
 
@@ -208,12 +212,21 @@
 #if defined(USE_X11)
       !IsVa_x11Initialized() ||
 #endif
-      !IsVa_drmInitialized())
+      !IsVa_drmInitialized()) {
     return false;
+  }
 
+  // Manual refcounting to ensure the rest of the method is called only once.
   if (refcount_++ > 0)
     return true;
 
+  const bool success = InitializeOnce();
+  UMA_HISTOGRAM_BOOLEAN("Media.VaapiWrapper.VADisplayStateInitializeSuccess",
+                        success);
+  return success;
+}
+
+bool VADisplayState::InitializeOnce() {
   switch (gl::GetGLImplementation()) {
     case gl::kGLImplementationEGLGLES2:
       va_display_ = vaGetDisplayDRM(drm_fd_.get());
diff --git a/mojo/public/cpp/bindings/lib/connector.cc b/mojo/public/cpp/bindings/lib/connector.cc
index f255efd9..94b6b4a 100644
--- a/mojo/public/cpp/bindings/lib/connector.cc
+++ b/mojo/public/cpp/bindings/lib/connector.cc
@@ -89,10 +89,8 @@
   }
 
   static RunLoopNestingObserver* GetForThread() {
-    if (!base::MessageLoop::current() ||
-        !base::RunLoop::IsNestingAllowedOnCurrentThread()) {
+    if (!base::MessageLoop::current())
       return nullptr;
-    }
     auto* observer = static_cast<RunLoopNestingObserver*>(
         g_tls_nesting_observer.Get().Get());
     if (!observer) {
diff --git a/net/dns/address_sorter_posix_unittest.cc b/net/dns/address_sorter_posix_unittest.cc
index 204fc87..1407ab4 100644
--- a/net/dns/address_sorter_posix_unittest.cc
+++ b/net/dns/address_sorter_posix_unittest.cc
@@ -79,6 +79,7 @@
     return NetworkChangeNotifier::kInvalidNetworkHandle;
   }
   void ApplySocketTag(const SocketTag& tag) override {}
+  void SetMsgConfirm(bool confirm) override {}
 
   int Connect(const IPEndPoint& remote) override {
     if (connected_)
diff --git a/net/dns/mock_mdns_socket_factory.h b/net/dns/mock_mdns_socket_factory.h
index 059a93a..3036ff6 100644
--- a/net/dns/mock_mdns_socket_factory.h
+++ b/net/dns/mock_mdns_socket_factory.h
@@ -45,6 +45,7 @@
   MOCK_METHOD1(SetReceiveBufferSize, int(int32_t size));
   MOCK_METHOD1(SetSendBufferSize, int(int32_t size));
   MOCK_METHOD0(SetDoNotFragment, int());
+  MOCK_METHOD1(SetMsgConfirm, void(bool confirm));
 
   MOCK_METHOD0(Close, void());
 
diff --git a/net/network_error_logging/network_error_logging_end_to_end_test.cc b/net/network_error_logging/network_error_logging_end_to_end_test.cc
index 5b20bff..d395643 100644
--- a/net/network_error_logging/network_error_logging_end_to_end_test.cc
+++ b/net/network_error_logging/network_error_logging_end_to_end_test.cc
@@ -199,7 +199,8 @@
 
 // Make sure an upload that is in progress at shutdown does not crash.
 // This verifies that https://crbug.com/792978 is fixed.
-TEST_F(NetworkErrorLoggingEndToEndTest, UploadAtShutdown) {
+// Disabled due to frequent timeouts - see https://crbug.com/820950 .
+TEST_F(NetworkErrorLoggingEndToEndTest, DISABLED_UploadAtShutdown) {
   upload_should_hang_ = true;
 
   TestDelegate configure_delegate;
diff --git a/net/socket/datagram_socket.h b/net/socket/datagram_socket.h
index f529474..254922d 100644
--- a/net/socket/datagram_socket.h
+++ b/net/socket/datagram_socket.h
@@ -45,6 +45,10 @@
   // return ERR_IO_PENDING.
   virtual int SetDoNotFragment() = 0;
 
+  // If |confirm| is true, then the MSG_CONFIRM flag will be passed to
+  // subsequent writes if it's supported by the platform.
+  virtual void SetMsgConfirm(bool confirm) = 0;
+
   // Gets the NetLog for this socket.
   virtual const NetLogWithSource& NetLog() const = 0;
 };
diff --git a/net/socket/fuzzed_datagram_client_socket.h b/net/socket/fuzzed_datagram_client_socket.h
index 6d19562..172ed24e 100644
--- a/net/socket/fuzzed_datagram_client_socket.h
+++ b/net/socket/fuzzed_datagram_client_socket.h
@@ -59,6 +59,7 @@
   int SetReceiveBufferSize(int32_t size) override;
   int SetSendBufferSize(int32_t size) override;
   int SetDoNotFragment() override;
+  void SetMsgConfirm(bool confirm) override {}
 
  private:
   void OnReadComplete(const net::CompletionCallback& callback, int result);
diff --git a/net/socket/socket_test_util.h b/net/socket/socket_test_util.h
index b9b0f02..65015f5 100644
--- a/net/socket/socket_test_util.h
+++ b/net/socket/socket_test_util.h
@@ -799,6 +799,7 @@
   int ConnectUsingDefaultNetwork(const IPEndPoint& address) override;
   NetworkChangeNotifier::NetworkHandle GetBoundNetwork() const override;
   void ApplySocketTag(const SocketTag& tag) override;
+  void SetMsgConfirm(bool confirm) override {}
 
   // AsyncSocket implementation.
   void OnReadComplete(const MockRead& data) override;
diff --git a/net/socket/udp_client_socket.cc b/net/socket/udp_client_socket.cc
index 049a1fca..f84d28d 100644
--- a/net/socket/udp_client_socket.cc
+++ b/net/socket/udp_client_socket.cc
@@ -119,6 +119,10 @@
   return socket_.SetDoNotFragment();
 }
 
+void UDPClientSocket::SetMsgConfirm(bool confirm) {
+  socket_.SetMsgConfirm(confirm);
+}
+
 const NetLogWithSource& UDPClientSocket::NetLog() const {
   return socket_.NetLog();
 }
diff --git a/net/socket/udp_client_socket.h b/net/socket/udp_client_socket.h
index 4abdb27..9f4f1ea 100644
--- a/net/socket/udp_client_socket.h
+++ b/net/socket/udp_client_socket.h
@@ -49,6 +49,7 @@
   int SetReceiveBufferSize(int32_t size) override;
   int SetSendBufferSize(int32_t size) override;
   int SetDoNotFragment() override;
+  void SetMsgConfirm(bool confirm) override;
   const NetLogWithSource& NetLog() const override;
   void EnableRecvOptimization() override;
 
diff --git a/net/socket/udp_server_socket.cc b/net/socket/udp_server_socket.cc
index d5f107a..ca9d848 100644
--- a/net/socket/udp_server_socket.cc
+++ b/net/socket/udp_server_socket.cc
@@ -67,6 +67,10 @@
   return socket_.SetDoNotFragment();
 }
 
+void UDPServerSocket::SetMsgConfirm(bool confirm) {
+  return socket_.SetMsgConfirm(confirm);
+}
+
 void UDPServerSocket::Close() {
   socket_.Close();
 }
diff --git a/net/socket/udp_server_socket.h b/net/socket/udp_server_socket.h
index 5d3cbdb2..0d2dc7e3 100644
--- a/net/socket/udp_server_socket.h
+++ b/net/socket/udp_server_socket.h
@@ -39,6 +39,7 @@
   int SetReceiveBufferSize(int32_t size) override;
   int SetSendBufferSize(int32_t size) override;
   int SetDoNotFragment() override;
+  void SetMsgConfirm(bool confirm) override;
   void Close() override;
   int GetPeerAddress(IPEndPoint* address) const override;
   int GetLocalAddress(IPEndPoint* address) const override;
diff --git a/net/socket/udp_socket_posix.cc b/net/socket/udp_socket_posix.cc
index 9bc55d7..e84a785 100644
--- a/net/socket/udp_socket_posix.cc
+++ b/net/socket/udp_socket_posix.cc
@@ -199,6 +199,7 @@
       addr_family_(0),
       is_connected_(false),
       socket_options_(SOCKET_OPTION_MULTICAST_LOOP),
+      sendto_flags_(0),
       multicast_interface_(0),
       multicast_time_to_live_(1),
       bind_type_(bind_type),
@@ -649,6 +650,16 @@
 #endif
 }
 
+void UDPSocketPosix::SetMsgConfirm(bool confirm) {
+#if !defined(OS_MACOSX) && !defined(OS_IOS)
+  if (confirm) {
+    sendto_flags_ |= MSG_CONFIRM;
+  } else {
+    sendto_flags_ &= ~MSG_CONFIRM;
+  }
+#endif  // !defined(OS_MACOSX) && !defined(OS_IOS)
+}
+
 int UDPSocketPosix::AllowAddressReuse() {
   DCHECK_NE(socket_, kInvalidSocket);
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
@@ -867,12 +878,8 @@
     }
   }
 
-  int result = HANDLE_EINTR(sendto(socket_,
-                            buf->data(),
-                            buf_len,
-                            0,
-                            addr,
-                            storage.addr_len));
+  int result = HANDLE_EINTR(sendto(socket_, buf->data(), buf_len, sendto_flags_,
+                                   addr, storage.addr_len));
   if (result < 0)
     result = MapSystemError(errno);
   if (result != ERR_IO_PENDING)
diff --git a/net/socket/udp_socket_posix.h b/net/socket/udp_socket_posix.h
index 65958803..77189fe 100644
--- a/net/socket/udp_socket_posix.h
+++ b/net/socket/udp_socket_posix.h
@@ -177,6 +177,10 @@
   // return ERR_IO_PENDING.
   int SetDoNotFragment();
 
+  // If |confirm| is true, then the MSG_CONFIRM flag will be passed to
+  // subsequent writes if it's supported by the platform.
+  void SetMsgConfirm(bool confirm);
+
   // Returns true if the socket is already connected or bound.
   bool is_connected() const { return is_connected_; }
 
@@ -354,6 +358,9 @@
   // options that should be applied to |socket_| before Bind().
   int socket_options_;
 
+  // Flags passed to sendto().
+  int sendto_flags_;
+
   // Multicast interface.
   uint32_t multicast_interface_;
 
diff --git a/net/socket/udp_socket_win.cc b/net/socket/udp_socket_win.cc
index 7790d6a..b848b54 100644
--- a/net/socket/udp_socket_win.cc
+++ b/net/socket/udp_socket_win.cc
@@ -567,6 +567,8 @@
   return rv == 0 ? OK : MapSystemError(WSAGetLastError());
 }
 
+void UDPSocketWin::SetMsgConfirm(bool confirm) {}
+
 int UDPSocketWin::AllowAddressReuse() {
   DCHECK_NE(socket_, INVALID_SOCKET);
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
diff --git a/net/socket/udp_socket_win.h b/net/socket/udp_socket_win.h
index 71094d4..09d8196 100644
--- a/net/socket/udp_socket_win.h
+++ b/net/socket/udp_socket_win.h
@@ -137,6 +137,9 @@
   // return ERR_IO_PENDING.
   int SetDoNotFragment();
 
+  // This is a no-op on Windows.
+  void SetMsgConfirm(bool confirm);
+
   // Returns true if the socket is already connected or bound.
   bool is_connected() const { return is_connected_; }
 
diff --git a/net/traffic_annotation/network_traffic_annotation_test_helper.h b/net/traffic_annotation/network_traffic_annotation_test_helper.h
index ce77c41..82b2ba1 100644
--- a/net/traffic_annotation/network_traffic_annotation_test_helper.h
+++ b/net/traffic_annotation/network_traffic_annotation_test_helper.h
@@ -7,7 +7,7 @@
 
 #include "net/traffic_annotation/network_traffic_annotation.h"
 
-// Macro for unit tests traffic annotations.
+// Macros for tests traffic annotations.
 #define TRAFFIC_ANNOTATION_FOR_TESTS   \
   net::DefineNetworkTrafficAnnotation( \
       "test", "Traffic annotation for unit, browser and other tests")
diff --git a/printing/backend/cups_jobs.cc b/printing/backend/cups_jobs.cc
index ab347e7f..3461e00 100644
--- a/printing/backend/cups_jobs.cc
+++ b/printing/backend/cups_jobs.cc
@@ -450,9 +450,15 @@
     return false;
   }
 
+  // TODO(crbug.com/821497): Use a library to canonicalize the URL.
+  size_t first_non_slash = resource.find_first_not_of('/');
+  const std::string path = (first_non_slash == std::string::npos)
+                               ? ""
+                               : resource.substr(first_non_slash);
+
   std::string printer_uri =
       base::StringPrintf("%s://%s:%d/%s", encrypted ? kIppsScheme : kIppScheme,
-                         address.c_str(), port, resource.c_str());
+                         address.c_str(), port, path.c_str());
 
   ipp_status_t status;
   ScopedIppPtr response =
diff --git a/services/network/BUILD.gn b/services/network/BUILD.gn
index 66a45f78..a7cf45ba 100644
--- a/services/network/BUILD.gn
+++ b/services/network/BUILD.gn
@@ -52,6 +52,12 @@
     "resource_scheduler_client.h",
     "restricted_cookie_manager.cc",
     "restricted_cookie_manager.h",
+    "socket_factory.cc",
+    "socket_factory.h",
+    "tcp_connected_socket.cc",
+    "tcp_connected_socket.h",
+    "tcp_server_socket.cc",
+    "tcp_server_socket.h",
     "throttling/network_conditions.cc",
     "throttling/network_conditions.h",
     "throttling/throttling_controller.cc",
@@ -66,8 +72,6 @@
     "throttling/throttling_upload_data_stream.h",
     "udp_socket.cc",
     "udp_socket.h",
-    "udp_socket_factory.cc",
-    "udp_socket_factory.h",
     "upload_progress_tracker.cc",
     "upload_progress_tracker.h",
     "url_loader.cc",
@@ -139,11 +143,11 @@
     "proxy_resolving_client_socket_unittest.cc",
     "resource_scheduler_unittest.cc",
     "restricted_cookie_manager_unittest.cc",
+    "tcp_socket_unittest.cc",
     "test/test_url_loader_factory_unittest.cc",
     "test_chunked_data_pipe_getter.cc",
     "test_chunked_data_pipe_getter.h",
     "throttling/throttling_controller_unittest.cc",
-    "udp_socket_factory_unittest.cc",
     "udp_socket_unittest.cc",
     "upload_progress_tracker_unittest.cc",
     "url_loader_unittest.cc",
diff --git a/services/network/network_context.cc b/services/network/network_context.cc
index 60a07ff..41fb0e7 100644
--- a/services/network/network_context.cc
+++ b/services/network/network_context.cc
@@ -36,6 +36,7 @@
 #include "net/reporting/reporting_policy.h"
 #include "net/ssl/channel_id_service.h"
 #include "net/ssl/default_channel_id_store.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
 #include "net/url_request/url_request_context.h"
 #include "net/url_request/url_request_context_builder.h"
 #include "services/network/http_server_properties_pref_delegate.h"
@@ -49,7 +50,6 @@
 #include "services/network/throttling/network_conditions.h"
 #include "services/network/throttling/throttling_controller.h"
 #include "services/network/throttling/throttling_network_transaction_factory.h"
-#include "services/network/udp_socket_factory.h"
 #include "services/network/url_loader.h"
 #include "services/network/url_loader_factory.h"
 #include "services/network/url_request_context_builder_mojo.h"
@@ -92,7 +92,8 @@
                                mojom::NetworkContextParamsPtr params)
     : network_service_(network_service),
       params_(std::move(params)),
-      binding_(this, std::move(request)) {
+      binding_(this, std::move(request)),
+      socket_factory_(network_service_->net_log()) {
   url_request_context_owner_ = MakeURLRequestContext(params_.get());
   url_request_context_getter_ =
       url_request_context_owner_.url_request_context_getter;
@@ -115,7 +116,8 @@
     std::unique_ptr<URLRequestContextBuilderMojo> builder)
     : network_service_(network_service),
       params_(std::move(params)),
-      binding_(this, std::move(request)) {
+      binding_(this, std::move(request)),
+      socket_factory_(network_service_->net_log()) {
   url_request_context_owner_ = ApplyContextParamsToBuilder(
       builder.get(), params_.get(), network_service->quic_disabled(),
       network_service->net_log());
@@ -136,8 +138,9 @@
       url_request_context_getter_(std::move(url_request_context_getter)),
       binding_(this, std::move(request)),
       cookie_manager_(std::make_unique<CookieManager>(
-          url_request_context_getter_->GetURLRequestContext()
-              ->cookie_store())) {
+          url_request_context_getter_->GetURLRequestContext()->cookie_store())),
+      socket_factory_(network_service_ ? network_service_->net_log()
+                                       : nullptr) {
   // May be nullptr in tests.
   if (network_service_)
     network_service_->RegisterNetworkContext(this);
@@ -222,7 +225,10 @@
 }
 
 NetworkContext::NetworkContext(mojom::NetworkContextParamsPtr params)
-    : network_service_(nullptr), params_(std::move(params)), binding_(this) {
+    : network_service_(nullptr),
+      params_(std::move(params)),
+      binding_(this),
+      socket_factory_(network_service_->net_log()) {
   url_request_context_owner_ = MakeURLRequestContext(params_.get());
   url_request_context_getter_ =
       url_request_context_owner_.url_request_context_getter;
@@ -486,9 +492,32 @@
 
 void NetworkContext::CreateUDPSocket(mojom::UDPSocketRequest request,
                                      mojom::UDPSocketReceiverPtr receiver) {
-  if (!udp_socket_factory_)
-    udp_socket_factory_ = std::make_unique<UDPSocketFactory>();
-  udp_socket_factory_->CreateUDPSocket(std::move(request), std::move(receiver));
+  socket_factory_.CreateUDPSocket(std::move(request), std::move(receiver));
+}
+
+void NetworkContext::CreateTCPServerSocket(
+    const net::IPEndPoint& local_addr,
+    uint32_t backlog,
+    const net::MutableNetworkTrafficAnnotationTag& traffic_annotation,
+    mojom::TCPServerSocketRequest request,
+    CreateTCPServerSocketCallback callback) {
+  socket_factory_.CreateTCPServerSocket(
+      local_addr, backlog,
+      static_cast<net::NetworkTrafficAnnotationTag>(traffic_annotation),
+      std::move(request), std::move(callback));
+}
+
+void NetworkContext::CreateTCPConnectedSocket(
+    const base::Optional<net::IPEndPoint>& local_addr,
+    const net::AddressList& remote_addr_list,
+    const net::MutableNetworkTrafficAnnotationTag& traffic_annotation,
+    mojom::TCPConnectedSocketRequest request,
+    mojom::TCPConnectedSocketObserverPtr observer,
+    CreateTCPConnectedSocketCallback callback) {
+  socket_factory_.CreateTCPConnectedSocket(
+      local_addr, remote_addr_list,
+      static_cast<net::NetworkTrafficAnnotationTag>(traffic_annotation),
+      std::move(request), std::move(observer), std::move(callback));
 }
 
 void NetworkContext::AddHSTSForTesting(const std::string& host,
diff --git a/services/network/network_context.h b/services/network/network_context.h
index 0c558a5..0519c8a 100644
--- a/services/network/network_context.h
+++ b/services/network/network_context.h
@@ -20,8 +20,10 @@
 #include "services/network/cookie_manager.h"
 #include "services/network/http_cache_data_remover.h"
 #include "services/network/public/mojom/network_service.mojom.h"
+#include "services/network/public/mojom/tcp_socket.mojom.h"
 #include "services/network/public/mojom/udp_socket.mojom.h"
 #include "services/network/public/mojom/url_loader_factory.mojom.h"
+#include "services/network/socket_factory.h"
 #include "services/network/url_request_context_owner.h"
 
 namespace net {
@@ -33,7 +35,6 @@
 class NetworkService;
 class ResourceScheduler;
 class ResourceSchedulerClient;
-class UDPSocketFactory;
 class URLRequestContextBuilderMojo;
 
 // A NetworkContext creates and manages access to a URLRequestContext.
@@ -112,6 +113,19 @@
                             mojom::NetworkConditionsPtr conditions) override;
   void CreateUDPSocket(mojom::UDPSocketRequest request,
                        mojom::UDPSocketReceiverPtr receiver) override;
+  void CreateTCPServerSocket(
+      const net::IPEndPoint& local_addr,
+      uint32_t backlog,
+      const net::MutableNetworkTrafficAnnotationTag& traffic_annotation,
+      mojom::TCPServerSocketRequest request,
+      CreateTCPServerSocketCallback callback) override;
+  void CreateTCPConnectedSocket(
+      const base::Optional<net::IPEndPoint>& local_addr,
+      const net::AddressList& remote_addr_list,
+      const net::MutableNetworkTrafficAnnotationTag& traffic_annotation,
+      mojom::TCPConnectedSocketRequest request,
+      mojom::TCPConnectedSocketObserverPtr observer,
+      CreateTCPConnectedSocketCallback callback) override;
   void AddHSTSForTesting(const std::string& host,
                          base::Time expiry,
                          bool include_subdomains,
@@ -169,7 +183,7 @@
 
   std::unique_ptr<CookieManager> cookie_manager_;
 
-  std::unique_ptr<UDPSocketFactory> udp_socket_factory_;
+  SocketFactory socket_factory_;
 
   std::vector<std::unique_ptr<HttpCacheDataRemover>> http_cache_data_removers_;
 
diff --git a/services/network/public/cpp/network_param_ipc_traits.h b/services/network/public/cpp/network_param_ipc_traits.h
index dbc7440..a52c22f 100644
--- a/services/network/public/cpp/network_param_ipc_traits.h
+++ b/services/network/public/cpp/network_param_ipc_traits.h
@@ -282,6 +282,7 @@
 
 IPC_STRUCT_TRAITS_BEGIN(network::URLLoaderCompletionStatus)
   IPC_STRUCT_TRAITS_MEMBER(error_code)
+  IPC_STRUCT_TRAITS_MEMBER(exists_in_cache)
   IPC_STRUCT_TRAITS_MEMBER(completion_time)
   IPC_STRUCT_TRAITS_MEMBER(encoded_data_length)
   IPC_STRUCT_TRAITS_MEMBER(encoded_body_length)
@@ -358,7 +359,6 @@
   IPC_STRUCT_TRAITS_MEMBER(ct_policy_compliance)
   IPC_STRUCT_TRAITS_MEMBER(is_legacy_symantec_cert)
   IPC_STRUCT_TRAITS_MEMBER(content_length)
-  IPC_STRUCT_TRAITS_MEMBER(was_cached)
   IPC_STRUCT_TRAITS_MEMBER(encoded_data_length)
   IPC_STRUCT_TRAITS_MEMBER(encoded_body_length)
   IPC_STRUCT_TRAITS_MEMBER(appcache_id)
diff --git a/services/network/public/cpp/resource_response.cc b/services/network/public/cpp/resource_response.cc
index 3b6c98f..777a2b4 100644
--- a/services/network/public/cpp/resource_response.cc
+++ b/services/network/public/cpp/resource_response.cc
@@ -21,7 +21,6 @@
   new_response->head.ct_policy_compliance = head.ct_policy_compliance;
   new_response->head.is_legacy_symantec_cert = head.is_legacy_symantec_cert;
   new_response->head.content_length = head.content_length;
-  new_response->head.was_cached = head.was_cached;
   new_response->head.encoded_data_length = head.encoded_data_length;
   new_response->head.encoded_body_length = head.encoded_body_length;
   new_response->head.appcache_id = head.appcache_id;
diff --git a/services/network/public/cpp/resource_response_info.cc b/services/network/public/cpp/resource_response_info.cc
index 1e0470a..c47e87b 100644
--- a/services/network/public/cpp/resource_response_info.cc
+++ b/services/network/public/cpp/resource_response_info.cc
@@ -15,7 +15,6 @@
       content_length(-1),
       encoded_data_length(-1),
       encoded_body_length(-1),
-      was_cached(false),
       appcache_id(0),
       was_fetched_via_spdy(false),
       was_alpn_negotiated(false),
diff --git a/services/network/public/cpp/resource_response_info.h b/services/network/public/cpp/resource_response_info.h
index 12f5cd7..9b9c6c7 100644
--- a/services/network/public/cpp/resource_response_info.h
+++ b/services/network/public/cpp/resource_response_info.h
@@ -69,9 +69,6 @@
   // has been read to the end.
   int64_t encoded_body_length;
 
-  // True if the response was fetched from the network cache.
-  bool was_cached;
-
   // The appcache this response was loaded from, or kAppCacheNoCacheId.
   // TODO(rdsmith): Remove conceptual dependence on appcache.
   int64_t appcache_id;
diff --git a/services/network/public/cpp/url_loader_completion_status.cc b/services/network/public/cpp/url_loader_completion_status.cc
index 095bd13..b7792fa 100644
--- a/services/network/public/cpp/url_loader_completion_status.cc
+++ b/services/network/public/cpp/url_loader_completion_status.cc
@@ -26,6 +26,7 @@
 bool URLLoaderCompletionStatus::operator==(
     const URLLoaderCompletionStatus& rhs) const {
   return error_code == rhs.error_code &&
+         exists_in_cache == rhs.exists_in_cache &&
          completion_time == rhs.completion_time &&
          encoded_data_length == rhs.encoded_data_length &&
          encoded_body_length == rhs.encoded_body_length &&
diff --git a/services/network/public/cpp/url_loader_completion_status.h b/services/network/public/cpp/url_loader_completion_status.h
index dec74f3..4d474d1 100644
--- a/services/network/public/cpp/url_loader_completion_status.h
+++ b/services/network/public/cpp/url_loader_completion_status.h
@@ -36,6 +36,9 @@
   // The error code. ERR_FAILED is set for CORS errors.
   int error_code = 0;
 
+  // A copy of the data requested exists in the cache.
+  bool exists_in_cache = false;
+
   // Time the request completed.
   base::TimeTicks completion_time;
 
diff --git a/services/network/public/mojom/BUILD.gn b/services/network/public/mojom/BUILD.gn
index 838874d..bfd5dd5 100644
--- a/services/network/public/mojom/BUILD.gn
+++ b/services/network/public/mojom/BUILD.gn
@@ -70,6 +70,7 @@
     "proxy_config_with_annotation.mojom",
     "request_context_frame_type.mojom",
     "restricted_cookie_manager.mojom",
+    "tcp_socket.mojom",
     "url_loader.mojom",
     "url_loader_factory.mojom",
   ]
diff --git a/services/network/public/mojom/network_service.mojom b/services/network/public/mojom/network_service.mojom
index df71a07..f666cb26 100644
--- a/services/network/public/mojom/network_service.mojom
+++ b/services/network/public/mojom/network_service.mojom
@@ -9,9 +9,11 @@
 import "net/interfaces/address_list.mojom";
 import "net/interfaces/ip_endpoint.mojom";
 import "services/network/public/mojom/cookie_manager.mojom";
+import "services/network/public/mojom/mutable_network_traffic_annotation_tag.mojom";
 import "services/network/public/mojom/network_change_manager.mojom";
 import "services/network/public/mojom/proxy_config.mojom";
 import "services/network/public/mojom/proxy_config_with_annotation.mojom";
+import "services/network/public/mojom/tcp_socket.mojom";
 import "services/network/public/mojom/udp_socket.mojom";
 import "services/network/public/mojom/url_loader.mojom";
 import "services/network/public/mojom/url_loader_factory.mojom";
@@ -188,8 +190,46 @@
   // is not interested in incoming data.
   // Any sockets that are created but are yet to be destroyed will be destroyed
   // when NetworkContext goes away.
-  CreateUDPSocket(network.mojom.UDPSocket& request,
-                  network.mojom.UDPSocketReceiver? receiver);
+  CreateUDPSocket(UDPSocket& request, UDPSocketReceiver? receiver);
+
+  // Creates a TCP server socket that listens on |local_addr|. The socket
+  // created can only be used for the purpose specified in |traffic_annotation|,
+  // and cannot be re-used for other purposes. Caller must specify an address
+  // family in |local_addr| to be either IPv4 or IPv6. If port in |local_addr|
+  // is 0, the OS will pick an available port. If address bytes are 0, the OS
+  // will pick a local address of the specified address family. |backlog| will
+  // be passed to the OS to set the size of accept queue.
+  // On success, the resulting local address will be written to |local_addr_out|
+  // and |result| is net::OK. On failure, |result| is a network error code.
+  //
+  // Any sockets that are created but are yet to be destroyed will be destroyed
+  // when NetworkContext goes away.
+  CreateTCPServerSocket(net.interfaces.IPEndPoint local_addr,
+                        uint32 backlog,
+                        MutableNetworkTrafficAnnotationTag traffic_annotation,
+                        TCPServerSocket& socket)
+      => (int32 result, net.interfaces.IPEndPoint? local_addr_out);
+
+  // Creates a TCP socket connected to |remote_addr|. |observer| will be used
+  // to listen for any network connection error on the newly established
+  // connection. The socket created can only be used for the purpose specified
+  // in |traffic_annotation|, and cannot be re-used for other purposes.
+  // |local_addr| should be set to null unless the caller wants to bind the
+  // socket to a specific address and port. On success, |result| is net::OK.
+  // Caller is to use |send_stream| to send data and |receive_stream| to receive
+  // data over the connection. On failure, |result| is a network error code.
+  //
+  // Any sockets that are created but are yet to be destroyed will be destroyed
+  // when NetworkContext goes away.
+  CreateTCPConnectedSocket(
+      net.interfaces.IPEndPoint? local_addr,
+      net.interfaces.AddressList remote_addr_list,
+      MutableNetworkTrafficAnnotationTag traffic_annotation,
+      TCPConnectedSocket& socket,
+      TCPConnectedSocketObserver observer)
+     => (int32 result,
+         handle<data_pipe_consumer>? receive_stream,
+         handle<data_pipe_producer>? send_stream);
 
   [Sync]
   // Adds explicitly-specified data as if it was processed from an
diff --git a/services/network/public/mojom/tcp_socket.mojom b/services/network/public/mojom/tcp_socket.mojom
new file mode 100644
index 0000000..0367f3a
--- /dev/null
+++ b/services/network/public/mojom/tcp_socket.mojom
@@ -0,0 +1,53 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+module network.mojom;
+
+import "net/interfaces/ip_endpoint.mojom";
+
+// Represents a connected TCP socket. Writes and Reads are through the data
+// pipes supplied upon construction. Consumer should use
+// TCPConnectedSocketObserver interface to get notified about any error occurred
+// during reading or writing to data pipes. Consumer can close the socket by
+// destroying the interface pointer.
+interface TCPConnectedSocket {
+  // Gets the local address of this connected socket. On success, |net_error| is
+  // net::OK and |local_addr| contains the local address of the socket. On
+  // failure, |local_addr| is null and |net_error| is a net error code.
+  GetLocalAddress() => (int32 net_error, net.interfaces.IPEndPoint? local_addr);
+};
+
+// Interface to listen for network connection error on a TCPConnectedSocket.
+// Because data pipe doesn't surface any network connection error, if a network
+// error happens during a read or a write, consumer can find out about it by
+// implementing this interface.
+interface TCPConnectedSocketObserver {
+  // Called when an error occurs during reading from the network. The producer
+  // side of |receive_stream| will be closed.
+  OnReadError(int32 net_error);
+
+  // Called when an error occurs during sending to the network. The consumer
+  // side of |send_stream| will be closed.
+  OnWriteError(int32 net_error);
+};
+
+// Represents a TCP server socket that has been successfully bound to a local
+// address. Caller can close the socket by destroying the interface pointer.
+interface TCPServerSocket {
+  // Waits for an incoming connection request. On success, returns net::OK,
+  // |remote_addr| represents the peer address, |connected_socket| is the new
+  // connection established. Caller uses |send_stream| to send data and
+  // |receive_stream| for receiving data over the new connection. On failure,
+  // |net_error| is a net error code and other fields are null.
+  // Up to |backlog| Accept()s can be pending at a time. |backlog| is a
+  // number that is specified when requesting TCPServerSocket. If more than
+  // |backlog| number of Accept()s are outstanding,
+  // net::ERR_INSUFFICIENT_RESOUCES will be returned.
+  Accept(TCPConnectedSocketObserver observer)
+      => (int32 net_error,
+          net.interfaces.IPEndPoint? remote_addr,
+          TCPConnectedSocket? connected_socket,
+          handle<data_pipe_consumer>? send_stream,
+          handle<data_pipe_producer>? receive_stream);
+};
diff --git a/services/network/socket_factory.cc b/services/network/socket_factory.cc
new file mode 100644
index 0000000..b4dca59
--- /dev/null
+++ b/services/network/socket_factory.cc
@@ -0,0 +1,69 @@
+// 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 "services/network/socket_factory.h"
+
+#include <utility>
+
+#include "base/memory/ptr_util.h"
+#include "base/optional.h"
+#include "net/base/completion_once_callback.h"
+#include "net/base/net_errors.h"
+#include "net/log/net_log.h"
+#include "services/network/tcp_connected_socket.h"
+#include "services/network/udp_socket.h"
+
+namespace network {
+
+SocketFactory::SocketFactory(net::NetLog* net_log) : net_log_(net_log) {}
+
+SocketFactory::~SocketFactory() {}
+
+void SocketFactory::CreateUDPSocket(mojom::UDPSocketRequest request,
+                                    mojom::UDPSocketReceiverPtr receiver) {
+  udp_socket_bindings_.AddBinding(
+      std::make_unique<UDPSocket>(std::move(receiver), net_log_),
+      std::move(request));
+}
+
+void SocketFactory::CreateTCPServerSocket(
+    const net::IPEndPoint& local_addr,
+    int backlog,
+    const net::NetworkTrafficAnnotationTag& traffic_annotation,
+    mojom::TCPServerSocketRequest request,
+    mojom::NetworkContext::CreateTCPServerSocketCallback callback) {
+  auto socket =
+      std::make_unique<TCPServerSocket>(this, net_log_, traffic_annotation);
+  net::IPEndPoint local_addr_out;
+  int result = socket->Listen(local_addr, backlog, &local_addr_out);
+  if (result != net::OK) {
+    std::move(callback).Run(result, base::nullopt);
+    return;
+  }
+  tcp_server_socket_bindings_.AddBinding(std::move(socket), std::move(request));
+  std::move(callback).Run(result, local_addr_out);
+}
+
+void SocketFactory::CreateTCPConnectedSocket(
+    const base::Optional<net::IPEndPoint>& local_addr,
+    const net::AddressList& remote_addr_list,
+    const net::NetworkTrafficAnnotationTag& traffic_annotation,
+    mojom::TCPConnectedSocketRequest request,
+    mojom::TCPConnectedSocketObserverPtr observer,
+    mojom::NetworkContext::CreateTCPConnectedSocketCallback callback) {
+  auto socket = std::make_unique<TCPConnectedSocket>(
+      std::move(observer), net_log_, traffic_annotation);
+  TCPConnectedSocket* socket_raw = socket.get();
+  tcp_connected_socket_bindings_.AddBinding(std::move(socket),
+                                            std::move(request));
+  socket_raw->Connect(local_addr, remote_addr_list, std::move(callback));
+}
+
+void SocketFactory::OnAccept(std::unique_ptr<TCPConnectedSocket> socket,
+                             mojom::TCPConnectedSocketRequest request) {
+  tcp_connected_socket_bindings_.AddBinding(std::move(socket),
+                                            std::move(request));
+}
+
+}  // namespace network
diff --git a/services/network/socket_factory.h b/services/network/socket_factory.h
new file mode 100644
index 0000000..59d1ac67
--- /dev/null
+++ b/services/network/socket_factory.h
@@ -0,0 +1,75 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SERVICES_NETWORK_SOCKET_FACTORY_H_
+#define SERVICES_NETWORK_SOCKET_FACTORY_H_
+
+#include <memory>
+#include <vector>
+
+#include "base/component_export.h"
+#include "base/macros.h"
+#include "mojo/public/cpp/bindings/strong_binding_set.h"
+#include "net/socket/tcp_socket.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
+#include "services/network/public/mojom/network_service.mojom.h"
+#include "services/network/public/mojom/tcp_socket.mojom.h"
+#include "services/network/public/mojom/udp_socket.mojom.h"
+#include "services/network/tcp_server_socket.h"
+
+namespace net {
+class NetLog;
+}  // namespace net
+
+namespace network {
+
+class UDPSocket;
+class TCPConnectedSocket;
+
+// Helper class that handles UDPSocketRequest. It takes care of destroying the
+// UDPSocket implementation instances when mojo pipes are broken.
+class COMPONENT_EXPORT(NETWORK_SERVICE) SocketFactory
+    : public TCPServerSocket::Delegate {
+ public:
+  // Constructs a SocketFactory. If |net_log| is non-null, it is used to
+  // log NetLog events when logging is enabled. |net_log| used to must outlive
+  // |this|.
+  explicit SocketFactory(net::NetLog* net_log);
+  virtual ~SocketFactory();
+
+  void CreateUDPSocket(mojom::UDPSocketRequest request,
+                       mojom::UDPSocketReceiverPtr receiver);
+  void CreateTCPServerSocket(
+      const net::IPEndPoint& local_addr,
+      int backlog,
+      const net::NetworkTrafficAnnotationTag& traffic_annotation,
+      mojom::TCPServerSocketRequest request,
+      mojom::NetworkContext::CreateTCPServerSocketCallback callback);
+  void CreateTCPConnectedSocket(
+      const base::Optional<net::IPEndPoint>& local_addr,
+      const net::AddressList& remote_addr_list,
+      const net::NetworkTrafficAnnotationTag& traffic_annotation,
+      mojom::TCPConnectedSocketRequest request,
+      mojom::TCPConnectedSocketObserverPtr observer,
+      mojom::NetworkContext::CreateTCPConnectedSocketCallback callback);
+
+ private:
+  // TCPServerSocket::Delegate implementation:
+  void OnAccept(std::unique_ptr<TCPConnectedSocket> socket,
+                mojom::TCPConnectedSocketRequest request) override;
+
+  void OnConnectCompleted(int result);
+
+  net::NetLog* net_log_;
+  mojo::StrongBindingSet<mojom::UDPSocket> udp_socket_bindings_;
+  mojo::StrongBindingSet<mojom::TCPServerSocket> tcp_server_socket_bindings_;
+  mojo::StrongBindingSet<mojom::TCPConnectedSocket>
+      tcp_connected_socket_bindings_;
+
+  DISALLOW_COPY_AND_ASSIGN(SocketFactory);
+};
+
+}  // namespace network
+
+#endif  // SERVICES_NETWORK_SOCKET_FACTORY_H_
diff --git a/services/network/tcp_connected_socket.cc b/services/network/tcp_connected_socket.cc
new file mode 100644
index 0000000..2962c9cf
--- /dev/null
+++ b/services/network/tcp_connected_socket.cc
@@ -0,0 +1,250 @@
+// 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 "services/network/tcp_connected_socket.h"
+
+#include <utility>
+
+#include "base/logging.h"
+#include "base/memory/ptr_util.h"
+#include "base/numerics/safe_conversions.h"
+#include "base/optional.h"
+#include "net/base/io_buffer.h"
+#include "net/base/net_errors.h"
+#include "net/log/net_log.h"
+
+namespace network {
+
+TCPConnectedSocket::TCPConnectedSocket(
+    mojom::TCPConnectedSocketObserverPtr observer,
+    net::NetLog* net_log,
+    const net::NetworkTrafficAnnotationTag& traffic_annotation)
+    : observer_(std::move(observer)),
+      net_log_(net_log),
+      readable_handle_watcher_(FROM_HERE,
+                               mojo::SimpleWatcher::ArmingPolicy::MANUAL),
+      writable_handle_watcher_(FROM_HERE,
+                               mojo::SimpleWatcher::ArmingPolicy::MANUAL),
+      traffic_annotation_(traffic_annotation) {
+  // TODO(xunjieli): Consider supporting null |observer_|, if there are
+  // consumers who do not care about read/write errors.
+  DCHECK(observer_);
+}
+
+TCPConnectedSocket::TCPConnectedSocket(
+    mojom::TCPConnectedSocketObserverPtr observer,
+    std::unique_ptr<net::StreamSocket> socket,
+    mojo::ScopedDataPipeProducerHandle receive_pipe_handle,
+    mojo::ScopedDataPipeConsumerHandle send_pipe_handle,
+    const net::NetworkTrafficAnnotationTag& traffic_annotation)
+    : observer_(std::move(observer)),
+      net_log_(nullptr),
+      socket_(std::move(socket)),
+      send_stream_(std::move(send_pipe_handle)),
+      readable_handle_watcher_(FROM_HERE,
+                               mojo::SimpleWatcher::ArmingPolicy::MANUAL),
+      receive_stream_(std::move(receive_pipe_handle)),
+      writable_handle_watcher_(FROM_HERE,
+                               mojo::SimpleWatcher::ArmingPolicy::MANUAL),
+      traffic_annotation_(traffic_annotation) {
+  StartWatching();
+}
+
+TCPConnectedSocket::~TCPConnectedSocket() {}
+
+void TCPConnectedSocket::Connect(
+    const base::Optional<net::IPEndPoint>& local_addr,
+    const net::AddressList& remote_addr_list,
+    mojom::NetworkContext::CreateTCPConnectedSocketCallback callback) {
+  DCHECK(!socket_);
+  DCHECK(callback);
+
+  auto socket = std::make_unique<net::TCPClientSocket>(
+      remote_addr_list, nullptr /*socket_performance_watcher*/, net_log_,
+      net::NetLogSource());
+  connect_callback_ = std::move(callback);
+  int result = net::OK;
+  if (local_addr)
+    result = socket->Bind(local_addr.value());
+  if (result == net::OK) {
+    result = socket->Connect(base::BindRepeating(
+        &TCPConnectedSocket::OnConnectCompleted, base::Unretained(this)));
+  }
+  socket_ = std::move(socket);
+  if (result == net::ERR_IO_PENDING)
+    return;
+  OnConnectCompleted(result);
+}
+
+void TCPConnectedSocket::GetLocalAddress(GetLocalAddressCallback callback) {
+  DCHECK(socket_);
+
+  net::IPEndPoint local_addr;
+  int result = socket_->GetLocalAddress(&local_addr);
+  if (result != net::OK) {
+    std::move(callback).Run(result, base::nullopt);
+    return;
+  }
+  std::move(callback).Run(result, local_addr);
+}
+
+void TCPConnectedSocket::OnConnectCompleted(int result) {
+  DCHECK(!connect_callback_.is_null());
+  DCHECK(!receive_stream_.is_valid());
+  DCHECK(!send_stream_.is_valid());
+
+  if (result != net::OK) {
+    std::move(connect_callback_)
+        .Run(result, mojo::ScopedDataPipeConsumerHandle(),
+             mojo::ScopedDataPipeProducerHandle());
+    return;
+  }
+  mojo::DataPipe send_pipe;
+  mojo::DataPipe receive_pipe;
+  receive_stream_ = std::move(receive_pipe.producer_handle);
+  send_stream_ = std::move(send_pipe.consumer_handle);
+
+  StartWatching();
+  std::move(connect_callback_)
+      .Run(net::OK, std::move(receive_pipe.consumer_handle),
+           std::move(send_pipe.producer_handle));
+}
+
+void TCPConnectedSocket::StartWatching() {
+  readable_handle_watcher_.Watch(
+      send_stream_.get(),
+      MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+      base::BindRepeating(&TCPConnectedSocket::OnSendStreamReadable,
+                          base::Unretained(this)));
+  writable_handle_watcher_.Watch(
+      receive_stream_.get(),
+      MOJO_HANDLE_SIGNAL_WRITABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+      base::BindRepeating(&TCPConnectedSocket::OnReceiveStreamWritable,
+                          base::Unretained(this)));
+  ReceiveMore();
+  SendMore();
+}
+
+void TCPConnectedSocket::ReceiveMore() {
+  DCHECK(receive_stream_.is_valid());
+  DCHECK(!pending_receive_);
+
+  uint32_t num_bytes;
+  MojoResult result = NetToMojoPendingBuffer::BeginWrite(
+      &receive_stream_, &pending_receive_, &num_bytes);
+  if (result == MOJO_RESULT_SHOULD_WAIT) {
+    writable_handle_watcher_.ArmOrNotify();
+    return;
+  }
+  if (result != MOJO_RESULT_OK) {
+    ShutdownReceive();
+    return;
+  }
+  DCHECK_EQ(MOJO_RESULT_OK, result);
+  DCHECK(pending_receive_);
+  scoped_refptr<net::IOBuffer> buf(
+      new NetToMojoIOBuffer(pending_receive_.get()));
+  int read_result = socket_->Read(
+      buf.get(), base::saturated_cast<int>(num_bytes),
+      base::BindRepeating(&TCPConnectedSocket::OnNetworkReadCompleted,
+                          base::Unretained(this)));
+  if (read_result == net::ERR_IO_PENDING)
+    return;
+  OnNetworkReadCompleted(read_result);
+}
+
+void TCPConnectedSocket::OnReceiveStreamWritable(MojoResult result) {
+  if (result != MOJO_RESULT_OK) {
+    ShutdownReceive();
+    return;
+  }
+  ReceiveMore();
+}
+
+void TCPConnectedSocket::OnNetworkReadCompleted(int bytes_read) {
+  DCHECK(pending_receive_);
+
+  if (bytes_read < 0)
+    observer_->OnReadError(bytes_read);
+
+  if (bytes_read <= 0) {
+    ShutdownReceive();
+    return;
+  }
+  if (bytes_read > 0) {
+    receive_stream_ = pending_receive_->Complete(bytes_read);
+    pending_receive_ = nullptr;
+    ReceiveMore();
+  }
+}
+
+void TCPConnectedSocket::ShutdownReceive() {
+  writable_handle_watcher_.Cancel();
+  pending_receive_ = nullptr;
+  receive_stream_.reset();
+}
+
+void TCPConnectedSocket::SendMore() {
+  DCHECK(send_stream_.is_valid());
+  DCHECK(!pending_send_);
+
+  uint32_t num_bytes = 0;
+  MojoResult result = MojoToNetPendingBuffer::BeginRead(
+      &send_stream_, &pending_send_, &num_bytes);
+  if (result == MOJO_RESULT_SHOULD_WAIT) {
+    readable_handle_watcher_.ArmOrNotify();
+    return;
+  }
+  if (result != MOJO_RESULT_OK) {
+    ShutdownSend();
+    return;
+  }
+  DCHECK_EQ(MOJO_RESULT_OK, result);
+  DCHECK(pending_send_);
+  scoped_refptr<net::IOBuffer> buf(
+      new net::WrappedIOBuffer(pending_send_->buffer()));
+  int write_result = socket_->Write(
+      buf.get(), static_cast<int>(num_bytes),
+      base::BindRepeating(&TCPConnectedSocket::OnNetworkWriteCompleted,
+                          base::Unretained(this)),
+      traffic_annotation_);
+  if (write_result == net::ERR_IO_PENDING)
+    return;
+  OnNetworkWriteCompleted(write_result);
+}
+
+void TCPConnectedSocket::OnSendStreamReadable(MojoResult result) {
+  if (result != MOJO_RESULT_OK) {
+    ShutdownSend();
+    return;
+  }
+  SendMore();
+}
+
+void TCPConnectedSocket::OnNetworkWriteCompleted(int bytes_written) {
+  DCHECK(pending_send_);
+
+  if (bytes_written < 0)
+    observer_->OnWriteError(bytes_written);
+  if (bytes_written <= 0) {
+    ShutdownSend();
+    return;
+  }
+
+  if (bytes_written > 0) {
+    // Partial write is possible.
+    pending_send_->CompleteRead(bytes_written);
+    send_stream_ = pending_send_->ReleaseHandle();
+    pending_send_ = nullptr;
+    SendMore();
+  }
+}
+
+void TCPConnectedSocket::ShutdownSend() {
+  readable_handle_watcher_.Cancel();
+  pending_send_ = nullptr;
+  send_stream_.reset();
+}
+
+}  // namespace network
diff --git a/services/network/tcp_connected_socket.h b/services/network/tcp_connected_socket.h
new file mode 100644
index 0000000..17665feb
--- /dev/null
+++ b/services/network/tcp_connected_socket.h
@@ -0,0 +1,106 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SERVICES_NETWORK_TCP_CONNECTED_SOCKET_H_
+#define SERVICES_NETWORK_TCP_CONNECTED_SOCKET_H_
+
+#include <memory>
+
+#include "base/component_export.h"
+#include "base/containers/span.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "mojo/public/cpp/system/data_pipe.h"
+#include "mojo/public/cpp/system/simple_watcher.h"
+#include "net/base/address_family.h"
+#include "net/base/completion_callback.h"
+#include "net/base/ip_endpoint.h"
+#include "net/interfaces/address_family.mojom.h"
+#include "net/interfaces/ip_endpoint.mojom.h"
+#include "net/socket/tcp_client_socket.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
+#include "services/network/public/cpp/net_adapters.h"
+#include "services/network/public/mojom/network_service.mojom.h"
+#include "services/network/public/mojom/tcp_socket.mojom.h"
+
+namespace net {
+class NetLog;
+class StreamSocket;
+}  // namespace net
+
+namespace network {
+
+class COMPONENT_EXPORT(NETWORK_SERVICE) TCPConnectedSocket
+    : public mojom::TCPConnectedSocket {
+ public:
+  TCPConnectedSocket(
+      mojom::TCPConnectedSocketObserverPtr observer,
+      net::NetLog* net_log,
+      const net::NetworkTrafficAnnotationTag& traffic_annotation);
+  TCPConnectedSocket(
+      mojom::TCPConnectedSocketObserverPtr observer,
+      std::unique_ptr<net::StreamSocket> socket,
+      mojo::ScopedDataPipeProducerHandle receive_pipe_handle,
+      mojo::ScopedDataPipeConsumerHandle send_pipe_handle,
+      const net::NetworkTrafficAnnotationTag& traffic_annotation);
+  ~TCPConnectedSocket() override;
+  void Connect(
+      const base::Optional<net::IPEndPoint>& local_addr,
+      const net::AddressList& remote_addr_list,
+      mojom::NetworkContext::CreateTCPConnectedSocketCallback callback);
+
+  // mojom::TCPConnectedSocket implementation.
+  void GetLocalAddress(GetLocalAddressCallback callback) override;
+
+ private:
+  // Invoked when net::TCPClientSocket::Connect() completes.
+  void OnConnectCompleted(int net_result);
+
+  // Helper to start watching |send_stream_| and |receive_stream_|.
+  void StartWatching();
+
+  // "Receiving" in this context means reading from |socket_| and writing to
+  // the Mojo |receive_stream_|.
+  void ReceiveMore();
+  void OnReceiveStreamWritable(MojoResult result);
+  void OnNetworkReadCompleted(int result);
+  void ShutdownReceive();
+
+  // "Writing" is reading from the Mojo |send_stream_| and writing to the
+  // |socket_|.
+  void SendMore();
+  void OnSendStreamReadable(MojoResult result);
+  void OnNetworkWriteCompleted(int result);
+  void ShutdownSend();
+
+  mojom::TCPConnectedSocketObserverPtr observer_;
+
+  net::NetLog* net_log_;
+
+  std::unique_ptr<net::StreamSocket> socket_;
+
+  mojom::NetworkContext::CreateTCPConnectedSocketCallback connect_callback_;
+
+  // The *stream handles will be null while there is an in-progress transation
+  // between net and mojo. During this time, the handle will be owned by the
+  // *PendingBuffer.
+
+  // For reading from the Mojo pipe and writing to the network.
+  mojo::ScopedDataPipeConsumerHandle send_stream_;
+  scoped_refptr<MojoToNetPendingBuffer> pending_send_;
+  mojo::SimpleWatcher readable_handle_watcher_;
+
+  // For reading from the network and writing to Mojo pipe.
+  mojo::ScopedDataPipeProducerHandle receive_stream_;
+  scoped_refptr<NetToMojoPendingBuffer> pending_receive_;
+  mojo::SimpleWatcher writable_handle_watcher_;
+
+  net::NetworkTrafficAnnotationTag traffic_annotation_;
+
+  DISALLOW_COPY_AND_ASSIGN(TCPConnectedSocket);
+};
+
+}  // namespace network
+
+#endif  // SERVICES_NETWORK_TCP_CONNECTED_SOCKET_H_
diff --git a/services/network/tcp_server_socket.cc b/services/network/tcp_server_socket.cc
new file mode 100644
index 0000000..e8f53dc
--- /dev/null
+++ b/services/network/tcp_server_socket.cc
@@ -0,0 +1,123 @@
+// 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 "services/network/tcp_server_socket.h"
+
+#include <utility>
+
+#include "base/logging.h"
+#include "base/memory/ptr_util.h"
+#include "base/numerics/safe_conversions.h"
+#include "base/optional.h"
+#include "net/base/io_buffer.h"
+#include "net/base/net_errors.h"
+#include "net/log/net_log.h"
+#include "net/socket/tcp_server_socket.h"
+#include "services/network/tcp_connected_socket.h"
+
+namespace network {
+
+TCPServerSocket::TCPServerSocket(
+    Delegate* delegate,
+    net::NetLog* net_log,
+    const net::NetworkTrafficAnnotationTag& traffic_annotation)
+    : delegate_(delegate),
+      socket_(
+          std::make_unique<net::TCPServerSocket>(net_log, net::NetLogSource())),
+      backlog_(0),
+      traffic_annotation_(traffic_annotation),
+      weak_factory_(this) {}
+
+TCPServerSocket::~TCPServerSocket() {}
+
+int TCPServerSocket::Listen(const net::IPEndPoint& local_addr,
+                            int backlog,
+                            net::IPEndPoint* local_addr_out) {
+  if (backlog == 0) {
+    // SocketPosix::Listen and TCPSocketWin::Listen DCHECKs on backlog > 0.
+    return net::ERR_INVALID_ARGUMENT;
+  }
+  backlog_ = backlog;
+  int net_error = socket_->Listen(local_addr, backlog);
+  if (net_error == net::OK)
+    socket_->GetLocalAddress(local_addr_out);
+  return net_error;
+}
+
+void TCPServerSocket::Accept(mojom::TCPConnectedSocketObserverPtr observer,
+                             AcceptCallback callback) {
+  if (pending_accepts_queue_.size() >= static_cast<size_t>(backlog_)) {
+    std::move(callback).Run(net::ERR_INSUFFICIENT_RESOURCES, base::nullopt,
+                            nullptr, mojo::ScopedDataPipeConsumerHandle(),
+                            mojo::ScopedDataPipeProducerHandle());
+    return;
+  }
+
+  pending_accepts_queue_.push_back(std::make_unique<PendingAccept>(
+      std::move(callback), std::move(observer)));
+  if (pending_accepts_queue_.size() == 1)
+    ProcessNextAccept();
+}
+
+void TCPServerSocket::SetSocketForTest(
+    std::unique_ptr<net::ServerSocket> socket) {
+  socket_ = std::move(socket);
+}
+
+TCPServerSocket::PendingAccept::PendingAccept(
+    AcceptCallback callback,
+    mojom::TCPConnectedSocketObserverPtr observer)
+    : callback(std::move(callback)), observer(std::move(observer)) {}
+
+TCPServerSocket::PendingAccept::~PendingAccept() {}
+
+void TCPServerSocket::OnAcceptCompleted(int result) {
+  DCHECK_NE(net::ERR_IO_PENDING, result);
+  DCHECK(!pending_accepts_queue_.empty());
+
+  auto pending_accept = std::move(pending_accepts_queue_.front());
+  pending_accepts_queue_.erase(pending_accepts_queue_.begin());
+
+  net::IPEndPoint peer_addr;
+  if (result == net::OK) {
+    DCHECK(accepted_socket_);
+    result = accepted_socket_->GetPeerAddress(&peer_addr);
+  }
+  if (result == net::OK) {
+    mojo::DataPipe send_pipe;
+    mojo::DataPipe receive_pipe;
+    mojom::TCPConnectedSocketPtr socket;
+    auto connected_socket = std::make_unique<TCPConnectedSocket>(
+        std::move(pending_accept->observer),
+        base::WrapUnique(accepted_socket_.release()),
+        std::move(receive_pipe.producer_handle),
+        std::move(send_pipe.consumer_handle), traffic_annotation_);
+    delegate_->OnAccept(std::move(connected_socket),
+                        mojo::MakeRequest(&socket));
+    std::move(pending_accept->callback)
+        .Run(result, peer_addr, std::move(socket),
+             std::move(receive_pipe.consumer_handle),
+             std::move(send_pipe.producer_handle));
+  } else {
+    std::move(pending_accept->callback)
+        .Run(result, base::nullopt, nullptr,
+             mojo::ScopedDataPipeConsumerHandle(),
+             mojo::ScopedDataPipeProducerHandle());
+  }
+  ProcessNextAccept();
+}
+
+void TCPServerSocket::ProcessNextAccept() {
+  if (pending_accepts_queue_.empty())
+    return;
+  int result =
+      socket_->Accept(&accepted_socket_,
+                      base::BindRepeating(&TCPServerSocket::OnAcceptCompleted,
+                                          base::Unretained(this)));
+  if (result == net::ERR_IO_PENDING)
+    return;
+  OnAcceptCompleted(result);
+}
+
+}  // namespace network
diff --git a/services/network/tcp_server_socket.h b/services/network/tcp_server_socket.h
new file mode 100644
index 0000000..0b52d11d
--- /dev/null
+++ b/services/network/tcp_server_socket.h
@@ -0,0 +1,91 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SERVICES_NETWORK_TCP_SERVER_SOCKET_H_
+#define SERVICES_NETWORK_TCP_SERVER_SOCKET_H_
+
+#include <memory>
+#include <vector>
+
+#include "base/component_export.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
+#include "mojo/public/cpp/bindings/interface_request.h"
+#include "net/base/ip_endpoint.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
+#include "services/network/public/mojom/tcp_socket.mojom.h"
+
+namespace net {
+class NetLog;
+class ServerSocket;
+class StreamSocket;
+}  // namespace net
+
+namespace network {
+class TCPConnectedSocket;
+
+class COMPONENT_EXPORT(NETWORK_SERVICE) TCPServerSocket
+    : public mojom::TCPServerSocket {
+ public:
+  // A delegate interface that is notified when new connections are established.
+  class Delegate {
+   public:
+    Delegate() {}
+    ~Delegate() {}
+
+    // Invoked when a new connection is accepted. The delegate should take
+    // ownership of |socket| and set up binding for |request|.
+    virtual void OnAccept(std::unique_ptr<TCPConnectedSocket> socket,
+                          mojom::TCPConnectedSocketRequest request) = 0;
+  };
+
+  // Constructs a TCPServerSocket. |delegate| must outlive |this|. When a new
+  // connection is accepted, |delegate| will be notified to take ownership of
+  // the connection.
+  TCPServerSocket(Delegate* delegate,
+                  net::NetLog* net_log,
+                  const net::NetworkTrafficAnnotationTag& traffic_annotation);
+  ~TCPServerSocket() override;
+
+  int Listen(const net::IPEndPoint& local_addr,
+             int backlog,
+             net::IPEndPoint* local_addr_out);
+
+  // TCPServerSocket implementation.
+  void Accept(mojom::TCPConnectedSocketObserverPtr observer,
+              AcceptCallback callback) override;
+
+  // Replaces the underlying socket implementation with |socket| in tests.
+  void SetSocketForTest(std::unique_ptr<net::ServerSocket> socket);
+
+ private:
+  struct PendingAccept {
+    PendingAccept(AcceptCallback callback,
+                  mojom::TCPConnectedSocketObserverPtr observer);
+    ~PendingAccept();
+
+    AcceptCallback callback;
+    mojom::TCPConnectedSocketObserverPtr observer;
+  };
+  // Invoked when socket_->Accept() completes.
+  void OnAcceptCompleted(int result);
+  // Process the next Accept() from |pending_accepts_queue_|.
+  void ProcessNextAccept();
+
+  Delegate* delegate_;
+  std::unique_ptr<net::ServerSocket> socket_;
+  int backlog_;
+  std::vector<std::unique_ptr<PendingAccept>> pending_accepts_queue_;
+  std::unique_ptr<net::StreamSocket> accepted_socket_;
+  net::NetworkTrafficAnnotationTag traffic_annotation_;
+
+  base::WeakPtrFactory<TCPServerSocket> weak_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(TCPServerSocket);
+};
+
+}  // namespace network
+
+#endif  // SERVICES_NETWORK_TCP_SERVER_SOCKET_H_
diff --git a/services/network/tcp_socket_unittest.cc b/services/network/tcp_socket_unittest.cc
new file mode 100644
index 0000000..dfb9bb1
--- /dev/null
+++ b/services/network/tcp_socket_unittest.cc
@@ -0,0 +1,939 @@
+// 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 <stdint.h>
+
+#include <utility>
+#include <vector>
+
+#include "base/callback_helpers.h"
+#include "base/location.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/run_loop.h"
+#include "base/test/scoped_task_environment.h"
+#include "base/threading/thread.h"
+#include "mojo/common/data_pipe_utils.h"
+#include "mojo/public/cpp/system/simple_watcher.h"
+#include "net/base/completion_callback.h"
+#include "net/base/completion_once_callback.h"
+#include "net/base/net_errors.h"
+#include "net/base/test_completion_callback.h"
+#include "net/socket/server_socket.h"
+#include "net/socket/socket_test_util.h"
+#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
+#include "services/network/public/mojom/network_service.mojom.h"
+#include "services/network/public/mojom/udp_socket.mojom.h"
+#include "services/network/socket_factory.h"
+#include "services/network/tcp_connected_socket.h"
+#include "services/network/tcp_server_socket.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace network {
+
+namespace {
+
+// A mock ServerSocket that completes Accept() using a specified result.
+class MockServerSocket : public net::ServerSocket {
+ public:
+  MockServerSocket() {}
+  ~MockServerSocket() override {}
+
+  // net::ServerSocket implementation.
+  int Listen(const net::IPEndPoint& address, int backlog) override {
+    return net::OK;
+  }
+
+  int GetLocalAddress(net::IPEndPoint* address) const override {
+    return net::OK;
+  }
+
+  int Accept(std::unique_ptr<net::StreamSocket>* socket,
+             const net::CompletionCallback& callback) override {
+    DCHECK(accept_callback_.is_null());
+    if (accept_result_ == net::OK && mode_ == net::SYNCHRONOUS)
+      *socket = CreateMockAcceptSocket();
+    if (mode_ == net::ASYNC || accept_result_ == net::ERR_IO_PENDING) {
+      accept_socket_ = socket;
+      accept_callback_ = callback;
+    }
+    run_loop_.Quit();
+
+    if (mode_ == net::ASYNC) {
+      base::ThreadTaskRunnerHandle::Get()->PostTask(
+          FROM_HERE, base::BindOnce(&MockServerSocket::CompleteAccept,
+                                    base::Unretained(this), accept_result_));
+      return net::ERR_IO_PENDING;
+    }
+    return accept_result_;
+  }
+
+  void SetAcceptResult(net::IoMode mode, int result) {
+    // It doesn't make sense to return net::ERR_IO_PENDING asynchronously.
+    DCHECK(!(mode == net::ASYNC && result == net::ERR_IO_PENDING));
+
+    mode_ = mode;
+    accept_result_ = result;
+  }
+
+  void WaitForFirstAccept() { run_loop_.Run(); }
+
+  void CompleteAccept(int result) {
+    DCHECK(!accept_callback_.is_null());
+    DCHECK_NE(net::ERR_IO_PENDING, result);
+
+    *accept_socket_ = CreateMockAcceptSocket();
+    accept_socket_ = nullptr;
+    base::ResetAndReturn(&accept_callback_).Run(result);
+  }
+
+ private:
+  // Must live longer than all SocketDataProviders.
+  const net::MockRead kReads[1] = {
+      net::MockRead(net::ASYNC, net::ERR_IO_PENDING)};
+
+  std::unique_ptr<net::StreamSocket> CreateMockAcceptSocket() {
+    auto data_provider = std::make_unique<net::StaticSocketDataProvider>(
+        kReads, arraysize(kReads), nullptr, 0);
+    data_provider->set_connect_data(
+        net::MockConnect(net::SYNCHRONOUS, net::OK));
+    auto mock_socket = std::make_unique<net::MockTCPClientSocket>(
+        net::AddressList(), nullptr /*netlog*/, data_provider.get());
+    data_providers_.push_back(std::move(data_provider));
+    EXPECT_EQ(net::OK, mock_socket->Connect(base::DoNothing()));
+    return std::move(mock_socket);
+  }
+
+  net::IoMode mode_ = net::SYNCHRONOUS;
+  int accept_result_ = net::OK;
+  net::CompletionCallback accept_callback_;
+  std::unique_ptr<net::StreamSocket>* accept_socket_;
+  base::RunLoop run_loop_;
+  std::vector<std::unique_ptr<net::StaticSocketDataProvider>> data_providers_;
+};
+
+class TestTCPConnectedSocketObserver
+    : public mojom::TCPConnectedSocketObserver {
+ public:
+  TestTCPConnectedSocketObserver() : binding_(this) {}
+  ~TestTCPConnectedSocketObserver() override {
+    EXPECT_EQ(net::OK, read_error_);
+    EXPECT_EQ(net::OK, write_error_);
+  }
+
+  // Returns a mojo pointer. This can only be called once.
+  mojom::TCPConnectedSocketObserverPtr GetObserverPtr() {
+    DCHECK(!binding_);
+    mojom::TCPConnectedSocketObserverPtr ptr;
+    binding_.Bind(mojo::MakeRequest(&ptr));
+    return ptr;
+  }
+
+  // Waits for Read and Write error. Returns the error observed.
+  int WaitForReadError() {
+    read_loop_.Run();
+    int error = read_error_;
+    read_error_ = net::OK;
+    return error;
+  }
+
+  int WaitForWriteError() {
+    write_loop_.Run();
+    int error = write_error_;
+    write_error_ = net::OK;
+    return error;
+  }
+
+ private:
+  // mojom::TCPConnectedSocketObserver implementation.
+  void OnReadError(int net_error) override {
+    read_error_ = net_error;
+    read_loop_.Quit();
+  }
+
+  void OnWriteError(int net_error) override {
+    write_error_ = net_error;
+    write_loop_.Quit();
+  }
+
+  int read_error_ = net::OK;
+  int write_error_ = net::OK;
+  base::RunLoop read_loop_;
+  base::RunLoop write_loop_;
+  mojo::Binding<mojom::TCPConnectedSocketObserver> binding_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestTCPConnectedSocketObserver);
+};
+
+// A server implemented using mojom::TCPServerSocket. It owns the server socket
+// pointer and as well as client connections. SendData() and StartReading()
+// operate on the newest client connection.
+class TestServer {
+ public:
+  TestServer()
+      : TestServer(net::IPEndPoint(net::IPAddress::IPv6Localhost(), 0)) {}
+  explicit TestServer(const net::IPEndPoint& server_addr)
+      : factory_(nullptr),
+        readable_handle_watcher_(FROM_HERE,
+                                 mojo::SimpleWatcher::ArmingPolicy::AUTOMATIC),
+        server_addr_(server_addr) {}
+  ~TestServer() {}
+
+  void Start(uint32_t backlog) {
+    int net_error = net::ERR_FAILED;
+    base::RunLoop run_loop;
+    factory_.CreateTCPServerSocket(
+        server_addr_, backlog, TRAFFIC_ANNOTATION_FOR_TESTS,
+        mojo::MakeRequest(&server_socket_),
+        base::BindOnce(
+            [](base::RunLoop* run_loop, int* result_out,
+               net::IPEndPoint* local_addr_out, int result,
+               const base::Optional<net::IPEndPoint>& local_addr) {
+              *result_out = result;
+              if (local_addr)
+                *local_addr_out = local_addr.value();
+              run_loop->Quit();
+            },
+            base::Unretained(&run_loop), base::Unretained(&net_error),
+            base::Unretained(&server_addr_)));
+    run_loop.Run();
+    EXPECT_EQ(net::OK, net_error);
+  }
+
+  // Accepts one connection. Upon successful completion, |callback| will be
+  // invoked.
+  void AcceptOneConnection(net::CompletionOnceCallback callback) {
+    observer_ = std::make_unique<TestTCPConnectedSocketObserver>();
+    server_socket_->Accept(
+        observer_->GetObserverPtr(),
+        base::BindOnce(&TestServer::OnAccept, base::Unretained(this),
+                       std::move(callback)));
+  }
+
+  // Sends data over the most recent connection that is established.
+  void SendData(const std::string& msg) {
+    EXPECT_TRUE(
+        mojo::common::BlockingCopyFromString(msg, server_socket_send_handle_));
+  }
+
+  // Starts reading. Can be called multiple times. It cancels any previous
+  // StartReading(). Once |expected_contents| is read, |callback| will be
+  // invoked. If an error occurs or the pipe is broken before read can
+  // complete, |callback| will be run, but ADD_FAILURE() will be called.
+  void StartReading(const std::string& expected_contents,
+                    base::OnceClosure callback) {
+    readable_handle_watcher_.Cancel();
+    received_contents_.clear();
+    expected_contents_ = expected_contents;
+    read_callback_ = std::move(callback);
+    readable_handle_watcher_.Watch(
+        server_socket_receive_handle_.get(),
+        MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+        base::BindRepeating(&TestServer::OnReadable, base::Unretained(this)));
+  }
+
+  void DestroyServerSocket() { server_socket_.reset(); }
+
+  const net::IPEndPoint& server_addr() { return server_addr_; }
+
+ private:
+  void OnAccept(net::CompletionOnceCallback callback,
+                int result,
+                const base::Optional<net::IPEndPoint>& remote_addr,
+                mojom::TCPConnectedSocketPtr connected_socket,
+                mojo::ScopedDataPipeConsumerHandle receive_pipe_handle,
+                mojo::ScopedDataPipeProducerHandle send_pipe_handle) {
+    connected_sockets_.push_back(std::move(connected_socket));
+    server_socket_receive_handle_ = std::move(receive_pipe_handle);
+    server_socket_send_handle_ = std::move(send_pipe_handle);
+    std::move(callback).Run(result);
+  }
+
+  void OnReadable(MojoResult result) {
+    if (result != MOJO_RESULT_OK) {
+      ADD_FAILURE() << "Unexpected broken pipe with error: " << result;
+      EXPECT_EQ(expected_contents_, received_contents_);
+      std::move(read_callback_).Run();
+      return;
+    }
+    char buffer[16];
+    uint32_t read_size = sizeof(buffer);
+    result = server_socket_receive_handle_->ReadData(buffer, &read_size,
+                                                     MOJO_READ_DATA_FLAG_NONE);
+    if (result == MOJO_RESULT_SHOULD_WAIT)
+      return;
+    if (result != MOJO_RESULT_OK) {
+      ADD_FAILURE() << "Unexpected read error: " << result;
+      EXPECT_EQ(expected_contents_, received_contents_);
+      std::move(read_callback_).Run();
+      return;
+    }
+
+    received_contents_.append(buffer, read_size);
+
+    if (received_contents_.size() == expected_contents_.size()) {
+      EXPECT_EQ(expected_contents_, received_contents_);
+      std::move(read_callback_).Run();
+    }
+  }
+
+  SocketFactory factory_;
+  mojom::TCPServerSocketPtr server_socket_;
+  std::vector<mojom::TCPConnectedSocketPtr> connected_sockets_;
+  std::unique_ptr<TestTCPConnectedSocketObserver> observer_;
+  mojo::ScopedDataPipeConsumerHandle server_socket_receive_handle_;
+  mojo::ScopedDataPipeProducerHandle server_socket_send_handle_;
+  mojo::SimpleWatcher readable_handle_watcher_;
+  net::IPEndPoint server_addr_;
+  std::string expected_contents_;
+  base::OnceClosure read_callback_;
+  std::string received_contents_;
+};
+
+}  // namespace
+
+class TCPSocketTest : public testing::Test {
+ public:
+  TCPSocketTest()
+      : scoped_task_environment_(
+            base::test::ScopedTaskEnvironment::MainThreadType::IO),
+        factory_(nullptr /*net_log*/) {}
+  ~TCPSocketTest() override {}
+
+  // Reads |num_bytes| from |handle| or reads until an error occurs. Returns the
+  // bytes read as a string.
+  std::string Read(mojo::ScopedDataPipeConsumerHandle* handle,
+                   size_t num_bytes) {
+    std::string received_contents;
+    while (received_contents.size() < num_bytes) {
+      base::RunLoop().RunUntilIdle();
+      std::vector<char> buffer(num_bytes);
+      uint32_t read_size = static_cast<uint32_t>(num_bytes);
+      MojoResult result = handle->get().ReadData(buffer.data(), &read_size,
+                                                 MOJO_READ_DATA_FLAG_NONE);
+      if (result == MOJO_RESULT_SHOULD_WAIT)
+        continue;
+      if (result != MOJO_RESULT_OK)
+        return received_contents;
+      received_contents.append(buffer.data(), read_size);
+    }
+    return received_contents;
+  }
+
+  // Creates a TCPServerSocket with the mock server socket, |socket|.
+  void CreateServerSocketWithMockSocket(
+      uint32_t backlog,
+      mojom::TCPServerSocketRequest request,
+      std::unique_ptr<net::ServerSocket> socket) {
+    auto server_socket_impl = std::make_unique<TCPServerSocket>(
+        &factory_, nullptr /*netlog*/, TRAFFIC_ANNOTATION_FOR_TESTS);
+    server_socket_impl->SetSocketForTest(std::move(socket));
+    net::IPEndPoint local_addr;
+    EXPECT_EQ(net::OK,
+              server_socket_impl->Listen(local_addr, backlog, &local_addr));
+    tcp_server_socket_bindings_.AddBinding(std::move(server_socket_impl),
+                                           std::move(request));
+  }
+
+  // Creates a TCPConnectedSocket with a mock client socket, |socket|.
+  // This can be only called once.
+  void CreateConnectedSocketWithMockSocket(
+      mojom::TCPConnectedSocketRequest request,
+      mojo::ScopedDataPipeProducerHandle receive_pipe_handle,
+      mojo::ScopedDataPipeConsumerHandle send_pipe_handle,
+      std::unique_ptr<net::MockTCPClientSocket> socket) {
+    net::TestCompletionCallback dummy_callback;
+    EXPECT_EQ(net::OK, socket->Connect(dummy_callback.callback()));
+    auto socket_impl = std::make_unique<TCPConnectedSocket>(
+        test_observer_.GetObserverPtr(), std::move(socket),
+        std::move(receive_pipe_handle), std::move(send_pipe_handle),
+        TRAFFIC_ANNOTATION_FOR_TESTS);
+    tcp_connected_socket_bindings_.AddBinding(std::move(socket_impl),
+                                              std::move(request));
+  }
+
+  int CreateTCPConnectedSocketSync(
+      mojom::TCPConnectedSocketRequest request,
+      mojom::TCPConnectedSocketObserverPtr observer,
+      const base::Optional<net::IPEndPoint>& local_addr,
+      const net::IPEndPoint& remote_addr,
+      mojo::ScopedDataPipeConsumerHandle* receive_pipe_handle_out,
+      mojo::ScopedDataPipeProducerHandle* send_pipe_handle_out) {
+    net::AddressList remote_addr_list(remote_addr);
+    base::RunLoop run_loop;
+    int net_error = net::ERR_FAILED;
+    factory_.CreateTCPConnectedSocket(
+        local_addr, remote_addr_list, TRAFFIC_ANNOTATION_FOR_TESTS,
+        std::move(request), std::move(observer),
+        base::BindOnce(
+            [](base::RunLoop* run_loop, int* result_out,
+               mojo::ScopedDataPipeConsumerHandle* consumer_handle,
+               mojo::ScopedDataPipeProducerHandle* producer_handle, int result,
+               mojo::ScopedDataPipeConsumerHandle receive_pipe_handle,
+               mojo::ScopedDataPipeProducerHandle send_pipe_handle) {
+              *result_out = result;
+              *consumer_handle = std::move(receive_pipe_handle);
+              *producer_handle = std::move(send_pipe_handle);
+              run_loop->Quit();
+            },
+            base::Unretained(&run_loop), base::Unretained(&net_error),
+            receive_pipe_handle_out, send_pipe_handle_out));
+    run_loop.Run();
+    return net_error;
+  }
+
+  TestTCPConnectedSocketObserver* observer() { return &test_observer_; }
+
+ private:
+  base::test::ScopedTaskEnvironment scoped_task_environment_;
+  SocketFactory factory_;
+  TestTCPConnectedSocketObserver test_observer_;
+  mojo::StrongBindingSet<mojom::TCPServerSocket> tcp_server_socket_bindings_;
+  mojo::StrongBindingSet<mojom::TCPConnectedSocket>
+      tcp_connected_socket_bindings_;
+
+  DISALLOW_COPY_AND_ASSIGN(TCPSocketTest);
+};
+
+TEST_F(TCPSocketTest, ReadAndWrite) {
+  const struct TestData {
+    base::Optional<net::IPEndPoint> client_addr;
+    net::IPEndPoint server_addr;
+  } kTestCases[] = {
+      {base::nullopt, net::IPEndPoint(net::IPAddress::IPv4Localhost(), 0)},
+      {base::nullopt, net::IPEndPoint(net::IPAddress::IPv6Localhost(), 0)},
+      {net::IPEndPoint(net::IPAddress::IPv4Localhost(), 0),
+       net::IPEndPoint(net::IPAddress::IPv4Localhost(), 0)},
+      {net::IPEndPoint(net::IPAddress::IPv6Localhost(), 0),
+       net::IPEndPoint(net::IPAddress::IPv6Localhost(), 0)},
+  };
+  for (auto test : kTestCases) {
+    TestServer server(test.server_addr);
+    server.Start(1 /*backlog*/);
+    net::TestCompletionCallback accept_callback;
+    server.AcceptOneConnection(accept_callback.callback());
+
+    mojo::ScopedDataPipeConsumerHandle client_socket_receive_handle;
+    mojo::ScopedDataPipeProducerHandle client_socket_send_handle;
+
+    mojom::TCPConnectedSocketPtr client_socket;
+    TestTCPConnectedSocketObserver observer;
+    EXPECT_EQ(net::OK,
+              CreateTCPConnectedSocketSync(
+                  mojo::MakeRequest(&client_socket), observer.GetObserverPtr(),
+                  test.client_addr, server.server_addr(),
+                  &client_socket_receive_handle, &client_socket_send_handle));
+    ASSERT_EQ(net::OK, accept_callback.WaitForResult());
+
+    // Test sending data from server to client.
+    const char kTestMsg[] = "hello";
+    server.SendData(kTestMsg);
+    EXPECT_EQ(kTestMsg,
+              Read(&client_socket_receive_handle, arraysize(kTestMsg) - 1));
+
+    // Test sending data from client to server.
+    base::RunLoop read_run_loop;
+    server.StartReading(kTestMsg, read_run_loop.QuitClosure());
+    EXPECT_TRUE(mojo::common::BlockingCopyFromString(
+        kTestMsg, client_socket_send_handle));
+    read_run_loop.Run();
+  }
+}
+
+TEST_F(TCPSocketTest, CannotConnectToWrongInterface) {
+  const struct TestData {
+    net::IPEndPoint client_addr;
+    net::IPEndPoint server_addr;
+  } kTestCases[] = {
+      {net::IPEndPoint(net::IPAddress::IPv6Localhost(), 0),
+       net::IPEndPoint(net::IPAddress::IPv4Localhost(), 0)},
+      {net::IPEndPoint(net::IPAddress::IPv4Localhost(), 0),
+       net::IPEndPoint(net::IPAddress::IPv6Localhost(), 0)},
+  };
+  for (auto test : kTestCases) {
+    mojo::ScopedDataPipeConsumerHandle client_socket_receive_handle;
+    mojo::ScopedDataPipeProducerHandle client_socket_send_handle;
+
+    TestTCPConnectedSocketObserver observer;
+    TestServer server(test.server_addr);
+    server.Start(1 /*backlog*/);
+    net::TestCompletionCallback accept_callback;
+    server.AcceptOneConnection(accept_callback.callback());
+
+    mojom::TCPConnectedSocketPtr client_socket;
+    int result = CreateTCPConnectedSocketSync(
+        mojo::MakeRequest(&client_socket), observer.GetObserverPtr(),
+        test.client_addr, server.server_addr(), &client_socket_receive_handle,
+        &client_socket_send_handle);
+    // Both net::ERR_INVALID_ARGUMENT and net::ERR_ADDRESS_UNREACHABLE can be
+    // returned. On Linux, for eample, the former is returned when talking ipv4
+    // to a ipv6 remote, and the latter is returned when talking ipv6 to a ipv4
+    // remote. net::ERR_CONNECTION_FAILED is returned on Windows.
+    EXPECT_TRUE(result == net::ERR_CONNECTION_FAILED ||
+                result == net::ERR_INVALID_ARGUMENT ||
+                result == net::ERR_ADDRESS_UNREACHABLE)
+        << "actual result: " << result;
+  }
+}
+
+// TODO(xunjieli): This test is flaky on MacOS crbug.com/821224.
+TEST_F(TCPSocketTest, DISABLED_ServerReceivesMultipleAccept) {
+  uint32_t backlog = 10;
+  TestServer server;
+  server.Start(backlog);
+
+  std::vector<std::unique_ptr<net::TestCompletionCallback>> accept_callbacks;
+  // Issue |backlog| Accepts(), so the queue is filled up.
+  for (size_t i = 0; i < backlog; ++i) {
+    auto callback = std::make_unique<net::TestCompletionCallback>();
+    server.AcceptOneConnection(callback->callback());
+    accept_callbacks.push_back(std::move(callback));
+  }
+  // Accept() beyond the queue size should fail immediately.
+  net::TestCompletionCallback callback;
+  server.AcceptOneConnection(callback.callback());
+  EXPECT_EQ(net::ERR_INSUFFICIENT_RESOURCES, callback.WaitForResult());
+
+  // After handling incoming connections, all callbacks should now complete.
+  for (size_t i = 0; i < backlog; ++i) {
+    TestTCPConnectedSocketObserver observer;
+    mojo::ScopedDataPipeConsumerHandle client_socket_receive_handle;
+    mojo::ScopedDataPipeProducerHandle client_socket_send_handle;
+    mojom::TCPConnectedSocketPtr client_socket;
+    EXPECT_EQ(net::OK,
+              CreateTCPConnectedSocketSync(
+                  mojo::MakeRequest(&client_socket), observer.GetObserverPtr(),
+                  base::nullopt /*local_addr*/, server.server_addr(),
+                  &client_socket_receive_handle, &client_socket_send_handle));
+  }
+  for (const auto& callback : accept_callbacks) {
+    EXPECT_EQ(net::OK, callback->WaitForResult());
+  }
+}
+
+// Tests that if a socket is closed, the other side can observe that the pipes
+// are broken.
+TEST_F(TCPSocketTest, SocketClosed) {
+  mojo::ScopedDataPipeConsumerHandle client_socket_receive_handle;
+  mojo::ScopedDataPipeProducerHandle client_socket_send_handle;
+  mojom::TCPConnectedSocketPtr client_socket;
+
+  TestTCPConnectedSocketObserver observer;
+  const char kTestMsg[] = "hello";
+  auto server = std::make_unique<TestServer>();
+  server->Start(1 /*backlog*/);
+  net::TestCompletionCallback accept_callback;
+  server->AcceptOneConnection(accept_callback.callback());
+
+  EXPECT_EQ(net::OK,
+            CreateTCPConnectedSocketSync(
+                mojo::MakeRequest(&client_socket), observer.GetObserverPtr(),
+                base::nullopt /*local_addr*/, server->server_addr(),
+                &client_socket_receive_handle, &client_socket_send_handle));
+  ASSERT_EQ(net::OK, accept_callback.WaitForResult());
+
+  // Send some data from server to client.
+  server->SendData(kTestMsg);
+  EXPECT_EQ(kTestMsg,
+            Read(&client_socket_receive_handle, arraysize(kTestMsg) - 1));
+  // Resetting the |server| destroys the TCPConnectedSocket ptr owned by the
+  // server.
+  server = nullptr;
+
+  // Read should return EOF.
+  EXPECT_EQ("", Read(&client_socket_receive_handle, 1));
+
+  // Read from |client_socket_receive_handle| again should return that the pipe
+  // is broken.
+  char buffer[16];
+  uint32_t read_size = sizeof(buffer);
+  MojoResult mojo_result = client_socket_receive_handle->ReadData(
+      buffer, &read_size, MOJO_READ_DATA_FLAG_NONE);
+  ASSERT_EQ(MOJO_RESULT_FAILED_PRECONDITION, mojo_result);
+  EXPECT_TRUE(client_socket_receive_handle->QuerySignalsState().peer_closed());
+
+  // Send pipe should be closed.
+  while (true) {
+    base::RunLoop().RunUntilIdle();
+    uint32_t size = arraysize(kTestMsg);
+    MojoResult r = client_socket_send_handle->WriteData(
+        kTestMsg, &size, MOJO_WRITE_DATA_FLAG_ALL_OR_NONE);
+    if (r == MOJO_RESULT_SHOULD_WAIT)
+      continue;
+    if (r == MOJO_RESULT_FAILED_PRECONDITION)
+      break;
+  }
+  EXPECT_TRUE(client_socket_send_handle->QuerySignalsState().peer_closed());
+  int result = observer.WaitForWriteError();
+  EXPECT_TRUE(result == net::ERR_CONNECTION_RESET ||
+              result == net::ERR_CONNECTION_ABORTED)
+      << "actual result: " << result;
+}
+
+TEST_F(TCPSocketTest, ReadPipeClosed) {
+  TestTCPConnectedSocketObserver observer;
+  const char kTestMsg[] = "hello";
+  TestServer server;
+  server.Start(1 /*backlog*/);
+  net::TestCompletionCallback accept_callback;
+  server.AcceptOneConnection(accept_callback.callback());
+
+  mojo::ScopedDataPipeConsumerHandle client_socket_receive_handle;
+  mojo::ScopedDataPipeProducerHandle client_socket_send_handle;
+  mojom::TCPConnectedSocketPtr client_socket;
+  EXPECT_EQ(net::OK,
+            CreateTCPConnectedSocketSync(
+                mojo::MakeRequest(&client_socket), observer.GetObserverPtr(),
+                base::nullopt /*local_addr*/, server.server_addr(),
+                &client_socket_receive_handle, &client_socket_send_handle));
+  ASSERT_EQ(net::OK, accept_callback.WaitForResult());
+
+  // Close |client_socket_receive_handle|. The socket should remain open.
+  client_socket_receive_handle.reset();
+
+  // Send should proceed as normal.
+  base::RunLoop read_run_loop;
+  server.StartReading(kTestMsg, read_run_loop.QuitClosure());
+  EXPECT_TRUE(mojo::common::BlockingCopyFromString(kTestMsg,
+                                                   client_socket_send_handle));
+  read_run_loop.Run();
+}
+
+TEST_F(TCPSocketTest, WritePipeClosed) {
+  TestTCPConnectedSocketObserver observer;
+  const char kTestMsg[] = "hello";
+  TestServer server;
+  server.Start(1 /*backlog*/);
+  net::TestCompletionCallback accept_callback;
+  server.AcceptOneConnection(accept_callback.callback());
+
+  mojo::ScopedDataPipeConsumerHandle client_socket_receive_handle;
+  mojo::ScopedDataPipeProducerHandle client_socket_send_handle;
+  mojom::TCPConnectedSocketPtr client_socket;
+  EXPECT_EQ(net::OK,
+            CreateTCPConnectedSocketSync(
+                mojo::MakeRequest(&client_socket), observer.GetObserverPtr(),
+                base::nullopt /*local_addr*/, server.server_addr(),
+                &client_socket_receive_handle, &client_socket_send_handle));
+  ASSERT_EQ(net::OK, accept_callback.WaitForResult());
+
+  // Close |client_socket_send_handle|. The socket should remain open.
+  client_socket_send_handle.reset();
+
+  // Receive should proceed as normal.
+  server.SendData(kTestMsg);
+  EXPECT_EQ(kTestMsg,
+            Read(&client_socket_receive_handle, arraysize(kTestMsg) - 1));
+}
+
+// Tests that if the server socket is destroyed, any connected sockets that it
+// handed out remain alive.
+TEST_F(TCPSocketTest, ServerSocketClosedAcceptedSocketAlive) {
+  mojo::ScopedDataPipeConsumerHandle client_socket_receive_handle;
+  mojo::ScopedDataPipeProducerHandle client_socket_send_handle;
+
+  TestTCPConnectedSocketObserver observer;
+  const char kTestMsg[] = "hello";
+  TestServer server;
+  server.Start(1 /*backlog*/);
+  net::TestCompletionCallback accept_callback;
+  server.AcceptOneConnection(accept_callback.callback());
+
+  mojom::TCPConnectedSocketPtr client_socket;
+  EXPECT_EQ(net::OK,
+            CreateTCPConnectedSocketSync(
+                mojo::MakeRequest(&client_socket), observer.GetObserverPtr(),
+                base::nullopt /*local_addr*/, server.server_addr(),
+                &client_socket_receive_handle, &client_socket_send_handle));
+  ASSERT_EQ(net::OK, accept_callback.WaitForResult());
+
+  // Now destroys the server socket.
+  server.DestroyServerSocket();
+  base::RunLoop().RunUntilIdle();
+
+  // Sending and receiving should still work.
+  server.SendData(kTestMsg);
+  EXPECT_EQ(kTestMsg,
+            Read(&client_socket_receive_handle, arraysize(kTestMsg) - 1));
+
+  base::RunLoop read_run_loop;
+  server.StartReading(kTestMsg, read_run_loop.QuitClosure());
+  EXPECT_TRUE(mojo::common::BlockingCopyFromString(kTestMsg,
+                                                   client_socket_send_handle));
+  read_run_loop.Run();
+}
+
+// Tests both async and sync cases.
+class TCPSocketWithMockSocketTest
+    : public TCPSocketTest,
+      public ::testing::WithParamInterface<net::IoMode> {};
+
+INSTANTIATE_TEST_CASE_P(/* no prefix */,
+                        TCPSocketWithMockSocketTest,
+                        testing::Values(net::SYNCHRONOUS, net::ASYNC));
+
+// Tests that a server socket handles Accept() correctly when the underlying
+// implementation completes Accept() in sync and async mode.
+TEST_P(TCPSocketWithMockSocketTest,
+       ServerAcceptClientConnectionWithMockSocket) {
+  net::IoMode mode = GetParam();
+  auto mock_server_socket = std::make_unique<MockServerSocket>();
+  MockServerSocket* mock_server_socket_raw = mock_server_socket.get();
+  mojom::TCPServerSocketPtr server_socket;
+  uint32_t kBacklog = 10;
+  // Use a mock socket to control net::ServerSocket::Accept() behavior.
+  CreateServerSocketWithMockSocket(kBacklog, mojo::MakeRequest(&server_socket),
+                                   std::move(mock_server_socket));
+
+  // Complete first Accept() using manual completion via CompleteAccept().
+  mock_server_socket_raw->SetAcceptResult(net::SYNCHRONOUS,
+                                          net::ERR_IO_PENDING);
+  std::vector<std::unique_ptr<net::TestCompletionCallback>> accept_callbacks;
+  for (size_t i = 0; i < kBacklog; ++i) {
+    auto callback = std::make_unique<net::TestCompletionCallback>();
+    TestTCPConnectedSocketObserver observer;
+    server_socket->Accept(
+        observer.GetObserverPtr(),
+        base::BindOnce(
+            [](net::CompletionOnceCallback callback, int result,
+               const base::Optional<net::IPEndPoint>& remote_addr,
+               mojom::TCPConnectedSocketPtr connected_socket,
+               mojo::ScopedDataPipeConsumerHandle receive_pipe_handle,
+               mojo::ScopedDataPipeProducerHandle send_pipe_handle) {
+              std::move(callback).Run(result);
+            },
+            std::move(callback->callback())));
+    accept_callbacks.push_back(std::move(callback));
+  }
+
+  mock_server_socket_raw->WaitForFirstAccept();
+  mock_server_socket_raw->SetAcceptResult(mode, net::OK);
+  mock_server_socket_raw->CompleteAccept(net::OK);
+
+  // First net::ServerSocket::Accept() will complete asynchronously
+  // internally. Other queued Accept() will complete
+  // synchronously/asynchronously depending on |mode| internally.
+  for (const auto& callback : accept_callbacks) {
+    EXPECT_EQ(net::OK, callback->WaitForResult());
+  }
+
+  // New Accept() should complete synchronously internally. Make sure this is
+  // okay.
+  auto callback = std::make_unique<net::TestCompletionCallback>();
+  TestTCPConnectedSocketObserver observer;
+  server_socket->Accept(
+      observer.GetObserverPtr(),
+      base::BindOnce(
+          [](net::CompletionOnceCallback callback, int result,
+             const base::Optional<net::IPEndPoint>& remote_addr,
+             mojom::TCPConnectedSocketPtr connected_socket,
+             mojo::ScopedDataPipeConsumerHandle receive_pipe_handle,
+             mojo::ScopedDataPipeProducerHandle send_pipe_handle) {
+            std::move(callback).Run(result);
+          },
+          std::move(callback->callback())));
+  EXPECT_EQ(net::OK, callback->WaitForResult());
+}
+
+TEST_P(TCPSocketWithMockSocketTest, ReadAndWriteMultiple) {
+  mojo::DataPipe send_pipe;
+  mojo::DataPipe receive_pipe;
+  mojo::ScopedDataPipeConsumerHandle client_socket_receive_handle =
+      std::move(receive_pipe.consumer_handle);
+  mojo::ScopedDataPipeProducerHandle client_socket_send_handle =
+      std::move(send_pipe.producer_handle);
+
+  mojom::TCPConnectedSocketPtr client_socket;
+  const char kTestMsg[] = "abcdefghij";
+  const size_t kMsgSize = arraysize(kTestMsg) - 1;
+  const int kNumIterations = 3;
+  std::vector<net::MockRead> reads;
+  std::vector<net::MockWrite> writes;
+  int sequence_number = 0;
+  net::IoMode mode = GetParam();
+  for (int j = 0; j < kNumIterations; ++j) {
+    for (size_t i = 0; i < kMsgSize; ++i) {
+      reads.push_back(net::MockRead(mode, &kTestMsg[i], 1, sequence_number++));
+    }
+    if (j == kNumIterations - 1) {
+      reads.push_back(net::MockRead(mode, net::OK, sequence_number++));
+    }
+    for (size_t i = 0; i < kMsgSize; ++i) {
+      writes.push_back(
+          net::MockWrite(mode, &kTestMsg[i], 1, sequence_number++));
+    }
+  }
+  net::StaticSocketDataProvider data_provider(reads.data(), reads.size(),
+                                              writes.data(), writes.size());
+  data_provider.set_connect_data(net::MockConnect(net::SYNCHRONOUS, net::OK));
+  auto mock_socket = std::make_unique<net::MockTCPClientSocket>(
+      net::AddressList(), nullptr /*netlog*/, &data_provider);
+
+  CreateConnectedSocketWithMockSocket(mojo::MakeRequest(&client_socket),
+                                      std::move(receive_pipe.producer_handle),
+                                      std::move(send_pipe.consumer_handle),
+                                      std::move(mock_socket));
+
+  // Loop kNumIterations times to test that writes can follow reads, and reads
+  // can follow writes.
+  for (int j = 0; j < kNumIterations; ++j) {
+    // Reading kMsgSize should coalesce the 1-byte mock reads.
+    EXPECT_EQ(kTestMsg, Read(&client_socket_receive_handle, kMsgSize));
+    // Write multiple times.
+    for (size_t i = 0; i < kMsgSize; ++i) {
+      uint32_t num_bytes = 1;
+      EXPECT_EQ(MOJO_RESULT_OK,
+                client_socket_send_handle->WriteData(
+                    &kTestMsg[i], &num_bytes, MOJO_WRITE_DATA_FLAG_NONE));
+      // Flush the 1 byte write.
+      base::RunLoop().RunUntilIdle();
+    }
+  }
+  EXPECT_TRUE(data_provider.AllReadDataConsumed());
+  EXPECT_TRUE(data_provider.AllWriteDataConsumed());
+}
+
+TEST_P(TCPSocketWithMockSocketTest, PartialStreamSocketWrite) {
+  mojo::DataPipe send_pipe;
+  mojo::DataPipe receive_pipe;
+  mojo::ScopedDataPipeConsumerHandle client_socket_receive_handle =
+      std::move(receive_pipe.consumer_handle);
+  mojo::ScopedDataPipeProducerHandle client_socket_send_handle =
+      std::move(send_pipe.producer_handle);
+
+  mojom::TCPConnectedSocketPtr client_socket;
+  const char kTestMsg[] = "abcdefghij";
+  const size_t kMsgSize = arraysize(kTestMsg) - 1;
+  const int kNumIterations = 3;
+  std::vector<net::MockRead> reads;
+  std::vector<net::MockWrite> writes;
+  int sequence_number = 0;
+  net::IoMode mode = GetParam();
+  for (int j = 0; j < kNumIterations; ++j) {
+    for (size_t i = 0; i < kMsgSize; ++i) {
+      reads.push_back(net::MockRead(mode, &kTestMsg[i], 1, sequence_number++));
+    }
+    if (j == kNumIterations - 1) {
+      reads.push_back(net::MockRead(mode, net::OK, sequence_number++));
+    }
+    for (size_t i = 0; i < kMsgSize; ++i) {
+      writes.push_back(
+          net::MockWrite(mode, &kTestMsg[i], 1, sequence_number++));
+    }
+  }
+  net::StaticSocketDataProvider data_provider(reads.data(), reads.size(),
+                                              writes.data(), writes.size());
+  data_provider.set_connect_data(net::MockConnect(net::SYNCHRONOUS, net::OK));
+  auto mock_socket = std::make_unique<net::MockTCPClientSocket>(
+      net::AddressList(), nullptr /*netlog*/, &data_provider);
+
+  CreateConnectedSocketWithMockSocket(mojo::MakeRequest(&client_socket),
+                                      std::move(receive_pipe.producer_handle),
+                                      std::move(send_pipe.consumer_handle),
+                                      std::move(mock_socket));
+
+  // Loop kNumIterations times to test that writes can follow reads, and reads
+  // can follow writes.
+  for (int j = 0; j < kNumIterations; ++j) {
+    // Reading kMsgSize should coalesce the 1-byte mock reads.
+    EXPECT_EQ(kTestMsg, Read(&client_socket_receive_handle, kMsgSize));
+    // Write twice, each with kMsgSize/2 bytes which is bigger than the 1-byte
+    // MockWrite(). This is to exercise that StreamSocket::Write() can do
+    // partial write.
+    uint32_t first_write_size = kMsgSize / 2;
+    EXPECT_EQ(MOJO_RESULT_OK,
+              client_socket_send_handle->WriteData(
+                  &kTestMsg[0], &first_write_size, MOJO_WRITE_DATA_FLAG_NONE));
+    // Flush the kMsgSize/2 byte write.
+    base::RunLoop().RunUntilIdle();
+    uint32_t second_write_size = kMsgSize - first_write_size;
+    EXPECT_EQ(MOJO_RESULT_OK,
+              client_socket_send_handle->WriteData(&kTestMsg[first_write_size],
+                                                   &second_write_size,
+                                                   MOJO_WRITE_DATA_FLAG_NONE));
+    // Flush the kMsgSize/2 byte write.
+    base::RunLoop().RunUntilIdle();
+  }
+  EXPECT_TRUE(data_provider.AllReadDataConsumed());
+  EXPECT_TRUE(data_provider.AllWriteDataConsumed());
+}
+
+TEST_P(TCPSocketWithMockSocketTest, ReadError) {
+  mojo::DataPipe send_pipe;
+  mojo::DataPipe receive_pipe;
+  mojo::ScopedDataPipeConsumerHandle client_socket_receive_handle =
+      std::move(receive_pipe.consumer_handle);
+  mojo::ScopedDataPipeProducerHandle client_socket_send_handle =
+      std::move(send_pipe.producer_handle);
+
+  mojom::TCPConnectedSocketPtr client_socket;
+  net::IoMode mode = GetParam();
+  net::MockRead reads[] = {net::MockRead(mode, net::ERR_FAILED)};
+  const char kTestMsg[] = "hello!";
+  net::MockWrite writes[] = {
+      net::MockWrite(mode, kTestMsg, arraysize(kTestMsg) - 1, 0)};
+  net::StaticSocketDataProvider data_provider(reads, arraysize(reads), writes,
+                                              arraysize(writes));
+  data_provider.set_connect_data(net::MockConnect(net::SYNCHRONOUS, net::OK));
+  auto mock_socket = std::make_unique<net::MockTCPClientSocket>(
+      net::AddressList(), nullptr /*netlog*/, &data_provider);
+
+  CreateConnectedSocketWithMockSocket(mojo::MakeRequest(&client_socket),
+                                      std::move(receive_pipe.producer_handle),
+                                      std::move(send_pipe.consumer_handle),
+                                      std::move(mock_socket));
+
+  EXPECT_EQ("", Read(&client_socket_receive_handle, 1));
+  EXPECT_EQ(net::ERR_FAILED, observer()->WaitForReadError());
+  // Writes can proceed even though there is a read error.
+  uint32_t num_bytes = arraysize(kTestMsg) - 1;
+  EXPECT_EQ(MOJO_RESULT_OK,
+            client_socket_send_handle->WriteData(&kTestMsg, &num_bytes,
+                                                 MOJO_WRITE_DATA_FLAG_NONE));
+
+  base::RunLoop().RunUntilIdle();
+  EXPECT_TRUE(data_provider.AllReadDataConsumed());
+  EXPECT_TRUE(data_provider.AllWriteDataConsumed());
+}
+
+TEST_P(TCPSocketWithMockSocketTest, WriteError) {
+  mojo::DataPipe send_pipe;
+  mojo::DataPipe receive_pipe;
+  mojo::ScopedDataPipeConsumerHandle client_socket_receive_handle =
+      std::move(receive_pipe.consumer_handle);
+  mojo::ScopedDataPipeProducerHandle client_socket_send_handle =
+      std::move(send_pipe.producer_handle);
+
+  mojom::TCPConnectedSocketPtr client_socket;
+  net::IoMode mode = GetParam();
+  const char kTestMsg[] = "hello!";
+  net::MockRead reads[] = {
+      net::MockRead(mode, kTestMsg, arraysize(kTestMsg) - 1, 0),
+      net::MockRead(mode, net::OK)};
+  net::MockWrite writes[] = {net::MockWrite(mode, net::ERR_FAILED)};
+  net::StaticSocketDataProvider data_provider(reads, arraysize(reads), writes,
+                                              arraysize(writes));
+  data_provider.set_connect_data(net::MockConnect(net::SYNCHRONOUS, net::OK));
+  auto mock_socket = std::make_unique<net::MockTCPClientSocket>(
+      net::AddressList(), nullptr /*netlog*/, &data_provider);
+
+  CreateConnectedSocketWithMockSocket(mojo::MakeRequest(&client_socket),
+                                      std::move(receive_pipe.producer_handle),
+                                      std::move(send_pipe.consumer_handle),
+                                      std::move(mock_socket));
+
+  uint32_t num_bytes = arraysize(kTestMsg) - 1;
+  EXPECT_EQ(MOJO_RESULT_OK,
+            client_socket_send_handle->WriteData(&kTestMsg, &num_bytes,
+                                                 MOJO_WRITE_DATA_FLAG_NONE));
+  EXPECT_EQ(net::ERR_FAILED, observer()->WaitForWriteError());
+  // Reads can proceed even though there is a read error.
+  EXPECT_EQ(kTestMsg, Read(&client_socket_receive_handle, arraysize(kTestMsg)));
+
+  base::RunLoop().RunUntilIdle();
+  EXPECT_TRUE(data_provider.AllReadDataConsumed());
+  EXPECT_TRUE(data_provider.AllWriteDataConsumed());
+}
+
+}  // namespace network
diff --git a/services/network/udp_socket.cc b/services/network/udp_socket.cc
index 4a19c98..e43690f 100644
--- a/services/network/udp_socket.cc
+++ b/services/network/udp_socket.cc
@@ -137,22 +137,15 @@
 
 UDPSocket::PendingSendRequest::~PendingSendRequest() {}
 
-UDPSocket::UDPSocket(mojom::UDPSocketRequest request,
-                     mojom::UDPSocketReceiverPtr receiver)
-    : is_bound_(false),
+UDPSocket::UDPSocket(mojom::UDPSocketReceiverPtr receiver, net::NetLog* net_log)
+    : net_log_(net_log),
+      is_bound_(false),
       is_connected_(false),
       receiver_(std::move(receiver)),
-      remaining_recv_slots_(0),
-      binding_(this) {
-  binding_.Bind(std::move(request));
-}
+      remaining_recv_slots_(0) {}
 
 UDPSocket::~UDPSocket() {}
 
-void UDPSocket::set_connection_error_handler(base::OnceClosure handler) {
-  binding_.set_connection_error_handler(std::move(handler));
-}
-
 void UDPSocket::Connect(const net::IPEndPoint& remote_addr,
                         mojom::UDPSocketOptionsPtr options,
                         ConnectCallback callback) {
@@ -295,7 +288,7 @@
     const {
   return std::make_unique<SocketWrapperImpl>(
       net::DatagramSocket::RANDOM_BIND, base::BindRepeating(&base::RandInt),
-      nullptr, net::NetLogSource());
+      net_log_, net::NetLogSource());
 }
 
 bool UDPSocket::IsConnectedOrBound() const {
diff --git a/services/network/udp_socket.h b/services/network/udp_socket.h
index 8f5ae10..b5b627a 100644
--- a/services/network/udp_socket.h
+++ b/services/network/udp_socket.h
@@ -13,8 +13,6 @@
 #include "base/containers/span.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
-#include "mojo/public/cpp/bindings/binding.h"
-#include "mojo/public/cpp/bindings/interface_request.h"
 #include "net/base/address_family.h"
 #include "net/base/completion_callback.h"
 #include "net/base/ip_endpoint.h"
@@ -26,6 +24,7 @@
 namespace net {
 class IOBuffer;
 class IOBufferWithSize;
+class NetLog;
 }  // namespace net
 
 namespace network {
@@ -70,13 +69,9 @@
                          const net::CompletionCallback& callback) = 0;
   };
 
-  UDPSocket(mojom::UDPSocketRequest request,
-            mojom::UDPSocketReceiverPtr receiver);
+  UDPSocket(mojom::UDPSocketReceiverPtr receiver, net::NetLog* net_log);
   ~UDPSocket() override;
 
-  // Sets connection error handler.
-  void set_connection_error_handler(base::OnceClosure handler);
-
   // UDPSocket implementation.
   void Connect(const net::IPEndPoint& remote_addr,
                mojom::UDPSocketOptionsPtr options,
@@ -137,6 +132,8 @@
   void OnRecvFromCompleted(uint32_t buffer_size, int net_result);
   void OnSendToCompleted(int net_result);
 
+  net::NetLog* net_log_;
+
   // Whether a Bind() has been successfully executed.
   bool is_bound_;
 
@@ -166,8 +163,6 @@
   base::circular_deque<std::unique_ptr<PendingSendRequest>>
       pending_send_requests_;
 
-  mojo::Binding<mojom::UDPSocket> binding_;
-
   DISALLOW_COPY_AND_ASSIGN(UDPSocket);
 };
 
diff --git a/services/network/udp_socket_factory.cc b/services/network/udp_socket_factory.cc
deleted file mode 100644
index 54ac3e4..0000000
--- a/services/network/udp_socket_factory.cc
+++ /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.
-
-#include "services/network/udp_socket_factory.h"
-
-#include <utility>
-
-#include "base/memory/ptr_util.h"
-#include "base/optional.h"
-#include "net/base/net_errors.h"
-#include "services/network/udp_socket.h"
-
-namespace network {
-
-UDPSocketFactory::UDPSocketFactory() {}
-
-UDPSocketFactory::~UDPSocketFactory() {}
-
-void UDPSocketFactory::CreateUDPSocket(mojom::UDPSocketRequest request,
-                                       mojom::UDPSocketReceiverPtr receiver) {
-  auto socket =
-      std::make_unique<UDPSocket>(std::move(request), std::move(receiver));
-  // base::Unretained is safe as the destruction of |this| will also destroy
-  // |udp_sockets_| which owns this socket.
-  socket->set_connection_error_handler(
-      base::BindOnce(&UDPSocketFactory::OnPipeBroken, base::Unretained(this),
-                     base::Unretained(socket.get())));
-  udp_sockets_.push_back(std::move(socket));
-}
-
-void UDPSocketFactory::OnPipeBroken(UDPSocket* socket) {
-  udp_sockets_.erase(
-      std::find_if(udp_sockets_.begin(), udp_sockets_.end(),
-                   [socket](const std::unique_ptr<network::UDPSocket>& ptr) {
-                     return ptr.get() == socket;
-                   }));
-}
-
-}  // namespace network
diff --git a/services/network/udp_socket_factory.h b/services/network/udp_socket_factory.h
deleted file mode 100644
index 58d47e8..0000000
--- a/services/network/udp_socket_factory.h
+++ /dev/null
@@ -1,41 +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 SERVICES_NETWORK_UDP_SOCKET_FACTORY_H_
-#define SERVICES_NETWORK_UDP_SOCKET_FACTORY_H_
-
-#include <memory>
-#include <vector>
-
-#include "base/component_export.h"
-#include "base/macros.h"
-#include "services/network/public/mojom/udp_socket.mojom.h"
-
-namespace network {
-
-class UDPSocket;
-
-// Helper class that handles UDPSocketRequest. It takes care of destroying the
-// UDPSocket implementation instances when mojo pipes are broken.
-class COMPONENT_EXPORT(NETWORK_SERVICE) UDPSocketFactory {
- public:
-  UDPSocketFactory();
-  virtual ~UDPSocketFactory();
-
-  void CreateUDPSocket(mojom::UDPSocketRequest request,
-                       mojom::UDPSocketReceiverPtr receiver);
-
- protected:
-  // Handles connection errors. This is virtual for testing.
-  virtual void OnPipeBroken(UDPSocket* client);
-
- private:
-  std::vector<std::unique_ptr<UDPSocket>> udp_sockets_;
-
-  DISALLOW_COPY_AND_ASSIGN(UDPSocketFactory);
-};
-
-}  // namespace network
-
-#endif  // SERVICES_NETWORK_UDP_SOCKET_FACTORY_H_
diff --git a/services/network/udp_socket_factory_unittest.cc b/services/network/udp_socket_factory_unittest.cc
deleted file mode 100644
index 2076e6e5..0000000
--- a/services/network/udp_socket_factory_unittest.cc
+++ /dev/null
@@ -1,63 +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 <utility>
-
-#include "services/network/udp_socket_factory.h"
-
-#include "base/logging.h"
-#include "base/macros.h"
-#include "base/run_loop.h"
-#include "base/test/scoped_task_environment.h"
-#include "net/base/net_errors.h"
-#include "services/network/public/mojom/udp_socket.mojom.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace network {
-
-class UDPSocketFactoryTest : public testing::Test {
- public:
-  UDPSocketFactoryTest() {}
-  ~UDPSocketFactoryTest() override {}
-
- private:
-  base::test::ScopedTaskEnvironment scoped_task_environment_;
-
-  DISALLOW_COPY_AND_ASSIGN(UDPSocketFactoryTest);
-};
-
-class TestUDPSocketFactory : public UDPSocketFactory {
- public:
-  TestUDPSocketFactory() {}
-  ~TestUDPSocketFactory() override {}
-
-  void WaitUntilPipeBroken() { run_loop_.Run(); }
-
- private:
-  // UDPSocketFactory implementation:
-  void OnPipeBroken(UDPSocket* client) override {
-    UDPSocketFactory::OnPipeBroken(client);
-    run_loop_.Quit();
-  }
-
-  base::RunLoop run_loop_;
-};
-// Tests that when client end of the pipe is closed, the factory implementation
-// cleans up the server side of the pipe.
-TEST_F(UDPSocketFactoryTest, ConnectionError) {
-  TestUDPSocketFactory factory;
-
-  mojom::UDPSocketReceiverPtr receiver_interface_ptr;
-  mojom::UDPSocketPtr socket_ptr;
-
-  factory.CreateUDPSocket(mojo::MakeRequest(&socket_ptr),
-                          std::move(receiver_interface_ptr));
-
-  // Close client side of the pipe.
-  socket_ptr.reset();
-
-  factory.WaitUntilPipeBroken();
-}
-
-}  // namespace network
diff --git a/services/network/udp_socket_unittest.cc b/services/network/udp_socket_unittest.cc
index 0fa16b75..7ca3552 100644
--- a/services/network/udp_socket_unittest.cc
+++ b/services/network/udp_socket_unittest.cc
@@ -21,6 +21,7 @@
 #include "net/traffic_annotation/network_traffic_annotation.h"
 #include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
 #include "services/network/public/mojom/udp_socket.mojom.h"
+#include "services/network/socket_factory.h"
 #include "services/network/udp_socket_test_util.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -199,8 +200,9 @@
 };
 
 TEST_F(UDPSocketTest, Settings) {
+  SocketFactory factory(nullptr /*net_log*/);
   mojom::UDPSocketPtr socket_ptr;
-  UDPSocket impl(mojo::MakeRequest(&socket_ptr), nullptr);
+  factory.CreateUDPSocket(mojo::MakeRequest(&socket_ptr), nullptr);
   net::IPEndPoint server_addr;
   net::IPEndPoint any_port(GetLocalHostWithAnyPort());
 
@@ -217,8 +219,9 @@
 // Tests that Send() is used after Bind() is not supported. Send() should only
 // be used after Connect().
 TEST_F(UDPSocketTest, TestSendWithBind) {
+  SocketFactory factory(nullptr /*net_log*/);
   mojom::UDPSocketPtr socket_ptr;
-  UDPSocket impl(mojo::MakeRequest(&socket_ptr), nullptr);
+  factory.CreateUDPSocket(mojo::MakeRequest(&socket_ptr), nullptr);
 
   net::IPEndPoint server_addr(GetLocalHostWithAnyPort());
 
@@ -235,6 +238,7 @@
 // Tests that when SendTo() is used after Connect() is not supported. SendTo()
 // should only be used after Bind().
 TEST_F(UDPSocketTest, TestSendToWithConnect) {
+  SocketFactory factory(nullptr /*net_log*/);
   // Create a server socket to listen for incoming datagrams.
   test::UDPSocketReceiverImpl receiver;
   mojo::Binding<mojom::UDPSocketReceiver> receiver_binding(&receiver);
@@ -242,8 +246,8 @@
   receiver_binding.Bind(mojo::MakeRequest(&receiver_interface_ptr));
 
   mojom::UDPSocketPtr server_socket;
-  UDPSocket impl(mojo::MakeRequest(&server_socket),
-                 std::move(receiver_interface_ptr));
+  factory.CreateUDPSocket(mojo::MakeRequest(&server_socket),
+                          std::move(receiver_interface_ptr));
 
   net::IPEndPoint server_addr(GetLocalHostWithAnyPort());
   test::UDPSocketTestHelper helper(&server_socket);
@@ -251,7 +255,7 @@
 
   // Create a client socket to send datagrams.
   mojom::UDPSocketPtr client_socket;
-  UDPSocket client_impl(mojo::MakeRequest(&client_socket), nullptr);
+  factory.CreateUDPSocket(mojo::MakeRequest(&client_socket), nullptr);
   net::IPEndPoint client_addr(GetLocalHostWithAnyPort());
   test::UDPSocketTestHelper client_helper(&client_socket);
   ASSERT_EQ(net::OK,
@@ -265,8 +269,9 @@
 // Tests that the sequence of calling Bind()/Connect() and setters is
 // important.
 TEST_F(UDPSocketTest, TestUnexpectedSequences) {
+  SocketFactory factory(nullptr /*net_log*/);
   mojom::UDPSocketPtr socket_ptr;
-  UDPSocket impl(mojo::MakeRequest(&socket_ptr), nullptr);
+  factory.CreateUDPSocket(mojo::MakeRequest(&socket_ptr), nullptr);
   test::UDPSocketTestHelper helper(&socket_ptr);
   net::IPEndPoint local_addr(GetLocalHostWithAnyPort());
 
@@ -291,7 +296,9 @@
 // ERR_IO_PENDING, udp_socket.cc doesn't free the send buffer.
 TEST_F(UDPSocketTest, TestBufferValid) {
   mojom::UDPSocketPtr socket_ptr;
-  UDPSocket impl(mojo::MakeRequest(&socket_ptr), nullptr);
+  UDPSocket impl(nullptr /*receiver*/, nullptr /*net_log*/);
+  mojo::Binding<mojom::UDPSocket> binding(&impl);
+  binding.Bind(mojo::MakeRequest(&socket_ptr));
 
   net::IPEndPoint server_addr(GetLocalHostWithAnyPort());
   test::UDPSocketTestHelper helper(&socket_ptr);
@@ -329,7 +336,9 @@
 // ERR_INSUFFICIENT_RESOURCES is returned appropriately.
 TEST_F(UDPSocketTest, TestInsufficientResources) {
   mojom::UDPSocketPtr socket_ptr;
-  UDPSocket impl(mojo::MakeRequest(&socket_ptr), nullptr);
+  UDPSocket impl(nullptr /*receiver*/, nullptr /*net_log*/);
+  mojo::Binding<mojom::UDPSocket> binding(&impl);
+  binding.Bind(mojo::MakeRequest(&socket_ptr));
 
   const size_t kQueueSize = UDPSocket::kMaxPendingSendRequests;
 
@@ -376,8 +385,9 @@
   receiver_binding.Bind(mojo::MakeRequest(&receiver_interface_ptr));
 
   mojom::UDPSocketPtr server_socket;
-  UDPSocket impl(mojo::MakeRequest(&server_socket),
-                 std::move(receiver_interface_ptr));
+  UDPSocket impl(std::move(receiver_interface_ptr), nullptr /*net_log*/);
+  mojo::Binding<mojom::UDPSocket> binding(&impl);
+  binding.Bind(mojo::MakeRequest(&server_socket));
 
   net::IPEndPoint server_addr(GetLocalHostWithAnyPort());
   test::UDPSocketTestHelper helper(&server_socket);
@@ -392,6 +402,7 @@
 }
 
 TEST_F(UDPSocketTest, TestReadSend) {
+  SocketFactory factory(nullptr /*net_log*/);
   // Create a server socket to listen for incoming datagrams.
   test::UDPSocketReceiverImpl receiver;
   mojo::Binding<mojom::UDPSocketReceiver> receiver_binding(&receiver);
@@ -399,8 +410,8 @@
   receiver_binding.Bind(mojo::MakeRequest(&receiver_interface_ptr));
 
   mojom::UDPSocketPtr server_socket;
-  UDPSocket impl(mojo::MakeRequest(&server_socket),
-                 std::move(receiver_interface_ptr));
+  factory.CreateUDPSocket(mojo::MakeRequest(&server_socket),
+                          std::move(receiver_interface_ptr));
 
   net::IPEndPoint server_addr(GetLocalHostWithAnyPort());
   test::UDPSocketTestHelper helper(&server_socket);
@@ -408,7 +419,7 @@
 
   // Create a client socket to send datagrams.
   mojom::UDPSocketPtr client_socket;
-  UDPSocket client_impl(mojo::MakeRequest(&client_socket), nullptr);
+  factory.CreateUDPSocket(mojo::MakeRequest(&client_socket), nullptr);
   net::IPEndPoint client_addr(GetLocalHostWithAnyPort());
   test::UDPSocketTestHelper client_helper(&client_socket);
   ASSERT_EQ(net::OK,
@@ -461,9 +472,10 @@
 }
 
 TEST_F(UDPSocketTest, TestReadSendTo) {
+  SocketFactory factory(nullptr /*net_log*/);
   // Create a server socket to send data.
   mojom::UDPSocketPtr server_socket;
-  UDPSocket impl(mojo::MakeRequest(&server_socket), nullptr);
+  factory.CreateUDPSocket(mojo::MakeRequest(&server_socket), nullptr);
 
   net::IPEndPoint server_addr(GetLocalHostWithAnyPort());
   test::UDPSocketTestHelper helper(&server_socket);
@@ -476,8 +488,8 @@
   receiver_binding.Bind(mojo::MakeRequest(&client_receiver_ptr));
 
   mojom::UDPSocketPtr client_socket;
-  UDPSocket client_impl(mojo::MakeRequest(&client_socket),
-                        std::move(client_receiver_ptr));
+  factory.CreateUDPSocket(mojo::MakeRequest(&client_socket),
+                          std::move(client_receiver_ptr));
   net::IPEndPoint client_addr(GetLocalHostWithAnyPort());
   test::UDPSocketTestHelper client_helper(&client_socket);
   ASSERT_EQ(net::OK,
@@ -527,6 +539,7 @@
 }
 
 TEST_F(UDPSocketTest, TestReceiveMoreWithBufferSize) {
+  SocketFactory factory(nullptr /*net_log*/);
   // Create a server socket to listen for incoming datagrams.
   test::UDPSocketReceiverImpl receiver;
   mojo::Binding<mojom::UDPSocketReceiver> receiver_binding(&receiver);
@@ -534,8 +547,8 @@
   receiver_binding.Bind(mojo::MakeRequest(&receiver_interface_ptr));
 
   mojom::UDPSocketPtr server_socket;
-  UDPSocket impl(mojo::MakeRequest(&server_socket),
-                 std::move(receiver_interface_ptr));
+  factory.CreateUDPSocket(mojo::MakeRequest(&server_socket),
+                          std::move(receiver_interface_ptr));
 
   net::IPEndPoint server_addr(GetLocalHostWithAnyPort());
   test::UDPSocketTestHelper helper(&server_socket);
@@ -543,7 +556,7 @@
 
   // Create a client socket to send datagrams.
   mojom::UDPSocketPtr client_socket;
-  UDPSocket client_impl(mojo::MakeRequest(&client_socket), nullptr);
+  factory.CreateUDPSocket(mojo::MakeRequest(&client_socket), nullptr);
   net::IPEndPoint client_addr(GetLocalHostWithAnyPort());
   test::UDPSocketTestHelper client_helper(&client_socket);
   ASSERT_EQ(net::OK,
@@ -578,8 +591,9 @@
 // Make sure passing an invalid net::IPEndPoint will be detected by
 // serialization/deserialization in mojo.
 TEST_F(UDPSocketTest, TestSendToInvalidAddress) {
+  SocketFactory factory(nullptr /*net_log*/);
   mojom::UDPSocketPtr server_socket;
-  UDPSocket impl(mojo::MakeRequest(&server_socket), nullptr);
+  factory.CreateUDPSocket(mojo::MakeRequest(&server_socket), nullptr);
 
   net::IPEndPoint server_addr(GetLocalHostWithAnyPort());
   test::UDPSocketTestHelper helper(&server_socket);
@@ -611,8 +625,9 @@
   receiver_binding.Bind(mojo::MakeRequest(&receiver_interface_ptr));
 
   mojom::UDPSocketPtr socket_ptr;
-  UDPSocket impl(mojo::MakeRequest(&socket_ptr),
-                 std::move(receiver_interface_ptr));
+  UDPSocket impl(std::move(receiver_interface_ptr), nullptr /*net_log*/);
+  mojo::Binding<mojom::UDPSocket> binding(&impl);
+  binding.Bind(mojo::MakeRequest(&socket_ptr));
 
   net::IPEndPoint server_addr(GetLocalHostWithAnyPort());
   test::UDPSocketTestHelper helper(&socket_ptr);
@@ -640,6 +655,7 @@
 #define MAYBE_JoinMulticastGroup JoinMulticastGroup
 #endif  // defined(OS_ANDROID)
 TEST_F(UDPSocketTest, MAYBE_JoinMulticastGroup) {
+  SocketFactory factory(nullptr /*net_log*/);
   const char kGroup[] = "237.132.100.17";
 
   net::IPAddress group_ip;
@@ -649,7 +665,8 @@
   test::UDPSocketReceiverImpl receiver;
   mojo::Binding<mojom::UDPSocketReceiver> receiver_binding(&receiver);
   receiver_binding.Bind(mojo::MakeRequest(&receiver_ptr));
-  UDPSocket impl(mojo::MakeRequest(&socket_ptr), std::move(receiver_ptr));
+  factory.CreateUDPSocket(mojo::MakeRequest(&socket_ptr),
+                          std::move(receiver_ptr));
 
   test::UDPSocketTestHelper helper(&socket_ptr);
 
@@ -685,7 +702,7 @@
 
   // Create a second socket to send a packet to multicast group.
   mojom::UDPSocketPtr second_socket_ptr;
-  UDPSocket second_socket_impl(mojo::MakeRequest(&second_socket_ptr), nullptr);
+  factory.CreateUDPSocket(mojo::MakeRequest(&second_socket_ptr), nullptr);
   test::UDPSocketTestHelper second_socket_helper(&second_socket_ptr);
   net::IPEndPoint second_socket_address(bind_ip_address, 0);
   ASSERT_EQ(net::OK,
@@ -716,15 +733,16 @@
 }
 
 TEST_F(UDPSocketTest, ErrorHappensDuringSocketOptionsConfiguration) {
+  SocketFactory factory(nullptr /*net_log*/);
   mojom::UDPSocketPtr server_socket_ptr;
-  UDPSocket server_impl(mojo::MakeRequest(&server_socket_ptr), nullptr);
+  factory.CreateUDPSocket(mojo::MakeRequest(&server_socket_ptr), nullptr);
   test::UDPSocketTestHelper server_helper(&server_socket_ptr);
   net::IPEndPoint server_addr(GetLocalHostWithAnyPort());
   ASSERT_EQ(net::OK,
             server_helper.BindSync(server_addr, nullptr, &server_addr));
 
   mojom::UDPSocketPtr socket_ptr;
-  UDPSocket impl(mojo::MakeRequest(&socket_ptr), nullptr);
+  factory.CreateUDPSocket(mojo::MakeRequest(&socket_ptr), nullptr);
   test::UDPSocketTestHelper helper(&socket_ptr);
 
   // Invalid options.
diff --git a/services/network/url_loader.cc b/services/network/url_loader.cc
index 36b5bfd..7828aebe 100644
--- a/services/network/url_loader.cc
+++ b/services/network/url_loader.cc
@@ -47,7 +47,6 @@
   response->head.headers = request->response_headers();
   request->GetCharset(&response->head.charset);
   response->head.content_length = request->GetExpectedContentSize();
-  response->head.was_cached = request->was_cached();
   request->GetMimeType(&response->head.mime_type);
   net::HttpResponseInfo response_info = request->response_info();
   response->head.was_fetched_via_spdy = response_info.was_fetched_via_spdy;
@@ -689,6 +688,7 @@
 
   URLLoaderCompletionStatus status;
   status.error_code = error_code;
+  status.exists_in_cache = url_request_->response_info().was_cached;
   status.completion_time = base::TimeTicks::Now();
   status.encoded_data_length = url_request_->GetTotalReceivedBytes();
   status.encoded_body_length = url_request_->GetRawBodyBytes();
diff --git a/services/network/url_loader_factory.cc b/services/network/url_loader_factory.cc
index ca2faee..45bb3ad 100644
--- a/services/network/url_loader_factory.cc
+++ b/services/network/url_loader_factory.cc
@@ -89,6 +89,7 @@
       if (client) {
         URLLoaderCompletionStatus status;
         status.error_code = net::ERR_INSUFFICIENT_RESOURCES;
+        status.exists_in_cache = false;
         status.completion_time = base::TimeTicks::Now();
         client->OnComplete(status);
       }
diff --git a/services/resource_coordinator/public/cpp/memory_instrumentation/os_metrics_win.cc b/services/resource_coordinator/public/cpp/memory_instrumentation/os_metrics_win.cc
index dfd08fa..26ed309f 100644
--- a/services/resource_coordinator/public/cpp/memory_instrumentation/os_metrics_win.cc
+++ b/services/resource_coordinator/public/cpp/memory_instrumentation/os_metrics_win.cc
@@ -43,15 +43,6 @@
   if (!base::win::GetLoadedModulesSnapshot(::GetCurrentProcess(), &modules))
     return maps;
 
-  auto process_metrics = base::ProcessMetrics::CreateCurrentProcessMetrics();
-  uint64_t pss_bytes = 0;
-  bool res = process_metrics->GetProportionalSetSizeBytes(&pss_bytes);
-  if (res) {
-    mojom::VmRegionPtr region = mojom::VmRegion::New();
-    region->byte_stats_proportional_resident = pss_bytes;
-    maps.push_back(std::move(region));
-  }
-
   // Query the base address for each module, and attach it to the dump.
   for (size_t i = 0; i < modules.size(); ++i) {
     wchar_t module_name[MAX_PATH];
diff --git a/services/ui/ws/display_manager.cc b/services/ui/ws/display_manager.cc
index 9503df2..e580213 100644
--- a/services/ui/ws/display_manager.cc
+++ b/services/ui/ws/display_manager.cc
@@ -37,11 +37,11 @@
 namespace ui {
 namespace ws {
 
-DisplayManager::DisplayManager(WindowServer* window_server)
+DisplayManager::DisplayManager(WindowServer* window_server, bool is_hosting_viz)
     : window_server_(window_server),
       cursor_location_manager_(std::make_unique<CursorLocationManager>()) {
 #if defined(OS_CHROMEOS)
-  if (window_server->is_hosting_viz()) {
+  if (is_hosting_viz) {
     // TODO: http://crbug.com/701468 fix function key preferences and sticky
     // keys.
     ui::EventRewriterChromeOS::Delegate* delegate = nullptr;
diff --git a/services/ui/ws/display_manager.h b/services/ui/ws/display_manager.h
index abb91d9..00b48484 100644
--- a/services/ui/ws/display_manager.h
+++ b/services/ui/ws/display_manager.h
@@ -34,7 +34,7 @@
 // those that do.
 class DisplayManager : public display::ScreenManagerDelegate {
  public:
-  explicit DisplayManager(WindowServer* window_server);
+  DisplayManager(WindowServer* window_server, bool is_hosting_viz);
   ~DisplayManager() override;
 
   // Called once WindowServer::display_creation_config() has been determined.
diff --git a/services/ui/ws/window_server.cc b/services/ui/ws/window_server.cc
index fdf7d39..bf92ce8d 100644
--- a/services/ui/ws/window_server.cc
+++ b/services/ui/ws/window_server.cc
@@ -135,7 +135,7 @@
 WindowServer::WindowServer(WindowServerDelegate* delegate, bool should_host_viz)
     : delegate_(delegate),
       next_client_id_(kWindowServerClientId + 1),
-      display_manager_(std::make_unique<DisplayManager>(this)),
+      display_manager_(std::make_unique<DisplayManager>(this, should_host_viz)),
       current_operation_(nullptr),
       in_destructor_(false),
       next_wm_change_id_(0),
diff --git a/storage/browser/fileapi/file_system_url.cc b/storage/browser/fileapi/file_system_url.cc
index 7074e203..184c475 100644
--- a/storage/browser/fileapi/file_system_url.cc
+++ b/storage/browser/fileapi/file_system_url.cc
@@ -26,6 +26,12 @@
 
 FileSystemURL::FileSystemURL(const FileSystemURL& other) = default;
 
+FileSystemURL::FileSystemURL(FileSystemURL&& other) noexcept = default;
+
+FileSystemURL& FileSystemURL::operator=(FileSystemURL&& rhs) = default;
+
+FileSystemURL& FileSystemURL::operator=(const FileSystemURL& rhs) = default;
+
 // static
 FileSystemURL FileSystemURL::CreateForTest(const GURL& url) {
   return FileSystemURL(url);
diff --git a/storage/browser/fileapi/file_system_url.h b/storage/browser/fileapi/file_system_url.h
index b9e8a99..eaedb23 100644
--- a/storage/browser/fileapi/file_system_url.h
+++ b/storage/browser/fileapi/file_system_url.h
@@ -79,8 +79,17 @@
  public:
   FileSystemURL();
   FileSystemURL(const FileSystemURL& other);
+  // Constructs FileSystemURL with the contents of |other|, which is left in
+  // valid but unspecified state.
+  FileSystemURL(FileSystemURL&& other) noexcept;
   ~FileSystemURL();
 
+  // Replaces the contents with those of |rhs|, which is left in valid but
+  // unspecified state.
+  FileSystemURL& operator=(FileSystemURL&& rhs);
+
+  FileSystemURL& operator=(const FileSystemURL& rhs);
+
   // Methods for creating FileSystemURL without attempting to crack them.
   // Should be used only in tests.
   static FileSystemURL CreateForTest(const GURL& url);
diff --git a/storage/browser/fileapi/file_system_url_unittest.cc b/storage/browser/fileapi/file_system_url_unittest.cc
index ef13cf10..71e0488c3 100644
--- a/storage/browser/fileapi/file_system_url_unittest.cc
+++ b/storage/browser/fileapi/file_system_url_unittest.cc
@@ -6,6 +6,8 @@
 
 #include <stddef.h>
 
+#include <utility>
+
 #include "base/files/file_path.h"
 #include "base/macros.h"
 #include "storage/common/fileapi/file_system_types.h"
@@ -221,4 +223,29 @@
   EXPECT_FALSE(url_foo_temp_a.IsInSameFileSystem(url_bar_perm_a));
 }
 
+TEST(FileSystemURLTest, ValidAfterMoves) {
+  // Move constructor.
+  {
+    FileSystemURL original = FileSystemURL::CreateForTest(
+        GURL("http://foo"), kFileSystemTypeTemporary,
+        base::FilePath::FromUTF8Unsafe("a"));
+    EXPECT_TRUE(original.is_valid());
+    FileSystemURL new_url(std::move(original));
+    EXPECT_TRUE(new_url.is_valid());
+    EXPECT_TRUE(original.is_valid());
+  }
+
+  // Move operator.
+  {
+    FileSystemURL original = FileSystemURL::CreateForTest(
+        GURL("http://foo"), kFileSystemTypeTemporary,
+        base::FilePath::FromUTF8Unsafe("a"));
+    EXPECT_TRUE(original.is_valid());
+    FileSystemURL new_url;
+    new_url = std::move(std::move(original));
+    EXPECT_TRUE(new_url.is_valid());
+    EXPECT_TRUE(original.is_valid());
+  }
+}
+
 }  // namespace content
diff --git a/testing/android/native_test/java/src/org/chromium/native_test/NativeTestApplication.java b/testing/android/native_test/java/src/org/chromium/native_test/NativeTestApplication.java
index 80ca421..c5f29d48 100644
--- a/testing/android/native_test/java/src/org/chromium/native_test/NativeTestApplication.java
+++ b/testing/android/native_test/java/src/org/chromium/native_test/NativeTestApplication.java
@@ -18,7 +18,7 @@
     protected void attachBaseContext(Context base) {
         super.attachBaseContext(base);
         assert getBaseContext() != null;
-        if (BuildConfig.isMultidexEnabled()) {
+        if (BuildConfig.IS_MULTIDEX_ENABLED) {
             ChromiumMultiDexInstaller.install(this);
         }
     }
diff --git a/testing/buildbot/chromium.perf.json b/testing/buildbot/chromium.perf.json
index 4848b5e1..780198e 100644
--- a/testing/buildbot/chromium.perf.json
+++ b/testing/buildbot/chromium.perf.json
@@ -44276,7 +44276,7 @@
             {
               "gpu": "8086:1616",
               "id": "build118-b1",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -44308,7 +44308,7 @@
             {
               "gpu": "8086:1616",
               "id": "build118-b1",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -44338,7 +44338,7 @@
             {
               "gpu": "8086:1616",
               "id": "build118-b1",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -44370,7 +44370,7 @@
             {
               "gpu": "8086:1616",
               "id": "build118-b1",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -44400,7 +44400,7 @@
             {
               "gpu": "8086:1616",
               "id": "build180-b4",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -44432,7 +44432,7 @@
             {
               "gpu": "8086:1616",
               "id": "build180-b4",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -44462,7 +44462,7 @@
             {
               "gpu": "8086:1616",
               "id": "build117-b1",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -44494,7 +44494,7 @@
             {
               "gpu": "8086:1616",
               "id": "build117-b1",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -44524,7 +44524,7 @@
             {
               "gpu": "8086:1616",
               "id": "build180-b4",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -44556,7 +44556,7 @@
             {
               "gpu": "8086:1616",
               "id": "build180-b4",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -44586,7 +44586,7 @@
             {
               "gpu": "8086:1616",
               "id": "build118-b1",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -44618,7 +44618,7 @@
             {
               "gpu": "8086:1616",
               "id": "build118-b1",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -44648,7 +44648,7 @@
             {
               "gpu": "8086:1616",
               "id": "build119-b1",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -44680,7 +44680,7 @@
             {
               "gpu": "8086:1616",
               "id": "build119-b1",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -44710,7 +44710,7 @@
             {
               "gpu": "8086:1616",
               "id": "build118-b1",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -44742,7 +44742,7 @@
             {
               "gpu": "8086:1616",
               "id": "build118-b1",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -44772,7 +44772,7 @@
             {
               "gpu": "8086:1616",
               "id": "build117-b1",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -44804,7 +44804,7 @@
             {
               "gpu": "8086:1616",
               "id": "build117-b1",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -44834,7 +44834,7 @@
             {
               "gpu": "8086:1616",
               "id": "build120-b1",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -44866,7 +44866,7 @@
             {
               "gpu": "8086:1616",
               "id": "build120-b1",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -44896,7 +44896,7 @@
             {
               "gpu": "8086:1616",
               "id": "build180-b4",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -44928,7 +44928,7 @@
             {
               "gpu": "8086:1616",
               "id": "build180-b4",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -44958,7 +44958,7 @@
             {
               "gpu": "8086:1616",
               "id": "build120-b1",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -44990,7 +44990,7 @@
             {
               "gpu": "8086:1616",
               "id": "build120-b1",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -45020,7 +45020,7 @@
             {
               "gpu": "8086:1616",
               "id": "build119-b1",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -45052,7 +45052,7 @@
             {
               "gpu": "8086:1616",
               "id": "build119-b1",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -45082,7 +45082,7 @@
             {
               "gpu": "8086:1616",
               "id": "build118-b1",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -45114,7 +45114,7 @@
             {
               "gpu": "8086:1616",
               "id": "build118-b1",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -45144,7 +45144,7 @@
             {
               "gpu": "8086:1616",
               "id": "build118-b1",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -45176,7 +45176,7 @@
             {
               "gpu": "8086:1616",
               "id": "build118-b1",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -45206,7 +45206,7 @@
             {
               "gpu": "8086:1616",
               "id": "build117-b1",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -45238,7 +45238,7 @@
             {
               "gpu": "8086:1616",
               "id": "build117-b1",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -45268,7 +45268,7 @@
             {
               "gpu": "8086:1616",
               "id": "build120-b1",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -45300,7 +45300,7 @@
             {
               "gpu": "8086:1616",
               "id": "build120-b1",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -45330,7 +45330,7 @@
             {
               "gpu": "8086:1616",
               "id": "build180-b4",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -45362,7 +45362,7 @@
             {
               "gpu": "8086:1616",
               "id": "build180-b4",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -45392,7 +45392,7 @@
             {
               "gpu": "8086:1616",
               "id": "build118-b1",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -45422,7 +45422,7 @@
             {
               "gpu": "8086:1616",
               "id": "build180-b4",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -45454,7 +45454,7 @@
             {
               "gpu": "8086:1616",
               "id": "build180-b4",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -45484,7 +45484,7 @@
             {
               "gpu": "8086:1616",
               "id": "build120-b1",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -45516,7 +45516,7 @@
             {
               "gpu": "8086:1616",
               "id": "build120-b1",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -45546,7 +45546,7 @@
             {
               "gpu": "8086:1616",
               "id": "build119-b1",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -45578,7 +45578,7 @@
             {
               "gpu": "8086:1616",
               "id": "build119-b1",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -45608,7 +45608,7 @@
             {
               "gpu": "8086:1616",
               "id": "build180-b4",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -45640,7 +45640,7 @@
             {
               "gpu": "8086:1616",
               "id": "build180-b4",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -45670,7 +45670,7 @@
             {
               "gpu": "8086:1616",
               "id": "build118-b1",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -45702,7 +45702,7 @@
             {
               "gpu": "8086:1616",
               "id": "build118-b1",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -45732,7 +45732,7 @@
             {
               "gpu": "8086:1616",
               "id": "build118-b1",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -45764,7 +45764,7 @@
             {
               "gpu": "8086:1616",
               "id": "build118-b1",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -45794,7 +45794,7 @@
             {
               "gpu": "8086:1616",
               "id": "build118-b1",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -45824,7 +45824,7 @@
             {
               "gpu": "8086:1616",
               "id": "build180-b4",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -45856,7 +45856,7 @@
             {
               "gpu": "8086:1616",
               "id": "build180-b4",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -45886,7 +45886,7 @@
             {
               "gpu": "8086:1616",
               "id": "build119-b1",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -45918,7 +45918,7 @@
             {
               "gpu": "8086:1616",
               "id": "build119-b1",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -45948,7 +45948,7 @@
             {
               "gpu": "8086:1616",
               "id": "build117-b1",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -45980,7 +45980,7 @@
             {
               "gpu": "8086:1616",
               "id": "build117-b1",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -46010,7 +46010,7 @@
             {
               "gpu": "8086:1616",
               "id": "build119-b1",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -46042,7 +46042,7 @@
             {
               "gpu": "8086:1616",
               "id": "build119-b1",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -46072,7 +46072,7 @@
             {
               "gpu": "8086:1616",
               "id": "build120-b1",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -46104,7 +46104,7 @@
             {
               "gpu": "8086:1616",
               "id": "build120-b1",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -46134,7 +46134,7 @@
             {
               "gpu": "8086:1616",
               "id": "build180-b4",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -46166,7 +46166,7 @@
             {
               "gpu": "8086:1616",
               "id": "build180-b4",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -46196,7 +46196,7 @@
             {
               "gpu": "8086:1616",
               "id": "build180-b4",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -46228,7 +46228,7 @@
             {
               "gpu": "8086:1616",
               "id": "build180-b4",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -46258,7 +46258,7 @@
             {
               "gpu": "8086:1616",
               "id": "build119-b1",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -46290,7 +46290,7 @@
             {
               "gpu": "8086:1616",
               "id": "build119-b1",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -46320,7 +46320,7 @@
             {
               "gpu": "8086:1616",
               "id": "build119-b1",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -46352,7 +46352,7 @@
             {
               "gpu": "8086:1616",
               "id": "build119-b1",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -46382,7 +46382,7 @@
             {
               "gpu": "8086:1616",
               "id": "build117-b1",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -46414,7 +46414,7 @@
             {
               "gpu": "8086:1616",
               "id": "build117-b1",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -46444,7 +46444,7 @@
             {
               "gpu": "8086:1616",
               "id": "build180-b4",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -46476,7 +46476,7 @@
             {
               "gpu": "8086:1616",
               "id": "build180-b4",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -46506,7 +46506,7 @@
             {
               "gpu": "8086:1616",
               "id": "build118-b1",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -46538,7 +46538,7 @@
             {
               "gpu": "8086:1616",
               "id": "build118-b1",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -46568,7 +46568,7 @@
             {
               "gpu": "8086:1616",
               "id": "build117-b1",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -46600,7 +46600,7 @@
             {
               "gpu": "8086:1616",
               "id": "build117-b1",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -46630,7 +46630,7 @@
             {
               "gpu": "8086:1616",
               "id": "build180-b4",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -46662,7 +46662,7 @@
             {
               "gpu": "8086:1616",
               "id": "build180-b4",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -46692,7 +46692,7 @@
             {
               "gpu": "8086:1616",
               "id": "build120-b1",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -46724,7 +46724,7 @@
             {
               "gpu": "8086:1616",
               "id": "build120-b1",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -46754,7 +46754,7 @@
             {
               "gpu": "8086:1616",
               "id": "build119-b1",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -46786,7 +46786,7 @@
             {
               "gpu": "8086:1616",
               "id": "build119-b1",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -46816,7 +46816,7 @@
             {
               "gpu": "8086:1616",
               "id": "build117-b1",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -46848,7 +46848,7 @@
             {
               "gpu": "8086:1616",
               "id": "build117-b1",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -46878,7 +46878,7 @@
             {
               "gpu": "8086:1616",
               "id": "build119-b1",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -46910,7 +46910,7 @@
             {
               "gpu": "8086:1616",
               "id": "build119-b1",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -46940,7 +46940,7 @@
             {
               "gpu": "8086:1616",
               "id": "build119-b1",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -46972,7 +46972,7 @@
             {
               "gpu": "8086:1616",
               "id": "build119-b1",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -47002,7 +47002,7 @@
             {
               "gpu": "8086:1616",
               "id": "build180-b4",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -47034,7 +47034,7 @@
             {
               "gpu": "8086:1616",
               "id": "build180-b4",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -47064,7 +47064,7 @@
             {
               "gpu": "8086:1616",
               "id": "build180-b4",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -47096,7 +47096,7 @@
             {
               "gpu": "8086:1616",
               "id": "build180-b4",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -47126,7 +47126,7 @@
             {
               "gpu": "8086:1616",
               "id": "build118-b1",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -47158,7 +47158,7 @@
             {
               "gpu": "8086:1616",
               "id": "build118-b1",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -47188,7 +47188,7 @@
             {
               "gpu": "8086:1616",
               "id": "build119-b1",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -47218,7 +47218,7 @@
             {
               "gpu": "8086:1616",
               "id": "build120-b1",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -47250,7 +47250,7 @@
             {
               "gpu": "8086:1616",
               "id": "build120-b1",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -47282,7 +47282,7 @@
             {
               "gpu": "8086:1616",
               "id": "build119-b1",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -47312,7 +47312,7 @@
             {
               "gpu": "8086:1616",
               "id": "build119-b1",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -47342,7 +47342,7 @@
             {
               "gpu": "8086:1616",
               "id": "build120-b1",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -47374,7 +47374,7 @@
             {
               "gpu": "8086:1616",
               "id": "build120-b1",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -47406,7 +47406,7 @@
             {
               "gpu": "8086:1616",
               "id": "build119-b1",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -47436,7 +47436,7 @@
             {
               "gpu": "8086:1616",
               "id": "build180-b4",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -47468,7 +47468,7 @@
             {
               "gpu": "8086:1616",
               "id": "build180-b4",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -47498,7 +47498,7 @@
             {
               "gpu": "8086:1616",
               "id": "build117-b1",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -47530,7 +47530,7 @@
             {
               "gpu": "8086:1616",
               "id": "build117-b1",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -47560,7 +47560,7 @@
             {
               "gpu": "8086:1616",
               "id": "build119-b1",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -47592,7 +47592,7 @@
             {
               "gpu": "8086:1616",
               "id": "build119-b1",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -47622,7 +47622,7 @@
             {
               "gpu": "8086:1616",
               "id": "build119-b1",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -47654,7 +47654,7 @@
             {
               "gpu": "8086:1616",
               "id": "build119-b1",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -47684,7 +47684,7 @@
             {
               "gpu": "8086:1616",
               "id": "build118-b1",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -47716,7 +47716,7 @@
             {
               "gpu": "8086:1616",
               "id": "build118-b1",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -47746,7 +47746,7 @@
             {
               "gpu": "8086:1616",
               "id": "build118-b1",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -47778,7 +47778,7 @@
             {
               "gpu": "8086:1616",
               "id": "build118-b1",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -47808,7 +47808,7 @@
             {
               "gpu": "8086:1616",
               "id": "build120-b1",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -47838,7 +47838,7 @@
             {
               "gpu": "8086:1616",
               "id": "build119-b1",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -47870,7 +47870,7 @@
             {
               "gpu": "8086:1616",
               "id": "build119-b1",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -47902,7 +47902,7 @@
             {
               "gpu": "8086:1616",
               "id": "build120-b1",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -47932,7 +47932,7 @@
             {
               "gpu": "8086:1616",
               "id": "build120-b1",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -47964,7 +47964,7 @@
             {
               "gpu": "8086:1616",
               "id": "build120-b1",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -47994,7 +47994,7 @@
             {
               "gpu": "8086:1616",
               "id": "build117-b1",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -48024,7 +48024,7 @@
             {
               "gpu": "8086:1616",
               "id": "build119-b1",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -48056,7 +48056,7 @@
             {
               "gpu": "8086:1616",
               "id": "build119-b1",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -48086,7 +48086,7 @@
             {
               "gpu": "8086:1616",
               "id": "build120-b1",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -48118,7 +48118,7 @@
             {
               "gpu": "8086:1616",
               "id": "build120-b1",
-              "os": "Windows-10-16299.248",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -48152,7 +48152,7 @@
             {
               "gpu": "102b:0534",
               "id": "build133-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -48184,7 +48184,7 @@
             {
               "gpu": "102b:0534",
               "id": "build133-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -48214,7 +48214,7 @@
             {
               "gpu": "102b:0534",
               "id": "build133-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -48246,7 +48246,7 @@
             {
               "gpu": "102b:0534",
               "id": "build133-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -48276,7 +48276,7 @@
             {
               "gpu": "102b:0534",
               "id": "build136-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -48308,7 +48308,7 @@
             {
               "gpu": "102b:0534",
               "id": "build136-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -48338,7 +48338,7 @@
             {
               "gpu": "102b:0534",
               "id": "build132-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -48370,7 +48370,7 @@
             {
               "gpu": "102b:0534",
               "id": "build132-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -48400,7 +48400,7 @@
             {
               "gpu": "102b:0534",
               "id": "build136-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -48432,7 +48432,7 @@
             {
               "gpu": "102b:0534",
               "id": "build136-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -48462,7 +48462,7 @@
             {
               "gpu": "102b:0534",
               "id": "build133-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -48494,7 +48494,7 @@
             {
               "gpu": "102b:0534",
               "id": "build133-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -48524,7 +48524,7 @@
             {
               "gpu": "102b:0534",
               "id": "build134-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -48556,7 +48556,7 @@
             {
               "gpu": "102b:0534",
               "id": "build134-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -48586,7 +48586,7 @@
             {
               "gpu": "102b:0534",
               "id": "build133-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -48618,7 +48618,7 @@
             {
               "gpu": "102b:0534",
               "id": "build133-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -48648,7 +48648,7 @@
             {
               "gpu": "102b:0534",
               "id": "build132-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -48680,7 +48680,7 @@
             {
               "gpu": "102b:0534",
               "id": "build132-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -48710,7 +48710,7 @@
             {
               "gpu": "102b:0534",
               "id": "build135-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -48742,7 +48742,7 @@
             {
               "gpu": "102b:0534",
               "id": "build135-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -48772,7 +48772,7 @@
             {
               "gpu": "102b:0534",
               "id": "build136-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -48804,7 +48804,7 @@
             {
               "gpu": "102b:0534",
               "id": "build136-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -48834,7 +48834,7 @@
             {
               "gpu": "102b:0534",
               "id": "build135-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -48866,7 +48866,7 @@
             {
               "gpu": "102b:0534",
               "id": "build135-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -48896,7 +48896,7 @@
             {
               "gpu": "102b:0534",
               "id": "build134-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -48928,7 +48928,7 @@
             {
               "gpu": "102b:0534",
               "id": "build134-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -48958,7 +48958,7 @@
             {
               "gpu": "102b:0534",
               "id": "build133-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -48990,7 +48990,7 @@
             {
               "gpu": "102b:0534",
               "id": "build133-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -49020,7 +49020,7 @@
             {
               "gpu": "102b:0534",
               "id": "build133-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -49052,7 +49052,7 @@
             {
               "gpu": "102b:0534",
               "id": "build133-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -49082,7 +49082,7 @@
             {
               "gpu": "102b:0534",
               "id": "build132-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -49114,7 +49114,7 @@
             {
               "gpu": "102b:0534",
               "id": "build132-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -49144,7 +49144,7 @@
             {
               "gpu": "102b:0534",
               "id": "build135-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -49176,7 +49176,7 @@
             {
               "gpu": "102b:0534",
               "id": "build135-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -49206,7 +49206,7 @@
             {
               "gpu": "102b:0534",
               "id": "build136-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -49238,7 +49238,7 @@
             {
               "gpu": "102b:0534",
               "id": "build136-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -49268,7 +49268,7 @@
             {
               "gpu": "102b:0534",
               "id": "build133-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -49298,7 +49298,7 @@
             {
               "gpu": "102b:0534",
               "id": "build136-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -49330,7 +49330,7 @@
             {
               "gpu": "102b:0534",
               "id": "build136-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -49351,7 +49351,7 @@
             {
               "gpu": "102b:0534",
               "id": "build134-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -49381,7 +49381,7 @@
             {
               "gpu": "102b:0534",
               "id": "build135-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -49413,7 +49413,7 @@
             {
               "gpu": "102b:0534",
               "id": "build135-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -49443,7 +49443,7 @@
             {
               "gpu": "102b:0534",
               "id": "build134-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -49475,7 +49475,7 @@
             {
               "gpu": "102b:0534",
               "id": "build134-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -49505,7 +49505,7 @@
             {
               "gpu": "102b:0534",
               "id": "build136-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -49537,7 +49537,7 @@
             {
               "gpu": "102b:0534",
               "id": "build136-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -49567,7 +49567,7 @@
             {
               "gpu": "102b:0534",
               "id": "build133-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -49599,7 +49599,7 @@
             {
               "gpu": "102b:0534",
               "id": "build133-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -49629,7 +49629,7 @@
             {
               "gpu": "102b:0534",
               "id": "build133-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -49661,7 +49661,7 @@
             {
               "gpu": "102b:0534",
               "id": "build133-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -49691,7 +49691,7 @@
             {
               "gpu": "102b:0534",
               "id": "build133-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -49721,7 +49721,7 @@
             {
               "gpu": "102b:0534",
               "id": "build136-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -49753,7 +49753,7 @@
             {
               "gpu": "102b:0534",
               "id": "build136-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -49783,7 +49783,7 @@
             {
               "gpu": "102b:0534",
               "id": "build134-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -49815,7 +49815,7 @@
             {
               "gpu": "102b:0534",
               "id": "build134-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -49845,7 +49845,7 @@
             {
               "gpu": "102b:0534",
               "id": "build132-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -49877,7 +49877,7 @@
             {
               "gpu": "102b:0534",
               "id": "build132-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -49907,7 +49907,7 @@
             {
               "gpu": "102b:0534",
               "id": "build134-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -49939,7 +49939,7 @@
             {
               "gpu": "102b:0534",
               "id": "build134-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -49969,7 +49969,7 @@
             {
               "gpu": "102b:0534",
               "id": "build135-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -50001,7 +50001,7 @@
             {
               "gpu": "102b:0534",
               "id": "build135-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -50031,7 +50031,7 @@
             {
               "gpu": "102b:0534",
               "id": "build136-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -50063,7 +50063,7 @@
             {
               "gpu": "102b:0534",
               "id": "build136-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -50093,7 +50093,7 @@
             {
               "gpu": "102b:0534",
               "id": "build136-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -50125,7 +50125,7 @@
             {
               "gpu": "102b:0534",
               "id": "build136-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -50155,7 +50155,7 @@
             {
               "gpu": "102b:0534",
               "id": "build134-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -50187,7 +50187,7 @@
             {
               "gpu": "102b:0534",
               "id": "build134-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -50217,7 +50217,7 @@
             {
               "gpu": "102b:0534",
               "id": "build134-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -50249,7 +50249,7 @@
             {
               "gpu": "102b:0534",
               "id": "build134-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -50279,7 +50279,7 @@
             {
               "gpu": "102b:0534",
               "id": "build132-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -50311,7 +50311,7 @@
             {
               "gpu": "102b:0534",
               "id": "build132-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -50341,7 +50341,7 @@
             {
               "gpu": "102b:0534",
               "id": "build136-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -50373,7 +50373,7 @@
             {
               "gpu": "102b:0534",
               "id": "build136-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -50403,7 +50403,7 @@
             {
               "gpu": "102b:0534",
               "id": "build133-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -50435,7 +50435,7 @@
             {
               "gpu": "102b:0534",
               "id": "build133-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -50465,7 +50465,7 @@
             {
               "gpu": "102b:0534",
               "id": "build132-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -50497,7 +50497,7 @@
             {
               "gpu": "102b:0534",
               "id": "build132-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -50527,7 +50527,7 @@
             {
               "gpu": "102b:0534",
               "id": "build135-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -50559,7 +50559,7 @@
             {
               "gpu": "102b:0534",
               "id": "build135-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -50589,7 +50589,7 @@
             {
               "gpu": "102b:0534",
               "id": "build135-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -50621,7 +50621,7 @@
             {
               "gpu": "102b:0534",
               "id": "build135-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -50651,7 +50651,7 @@
             {
               "gpu": "102b:0534",
               "id": "build134-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -50683,7 +50683,7 @@
             {
               "gpu": "102b:0534",
               "id": "build134-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -50713,7 +50713,7 @@
             {
               "gpu": "102b:0534",
               "id": "build132-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -50745,7 +50745,7 @@
             {
               "gpu": "102b:0534",
               "id": "build132-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -50775,7 +50775,7 @@
             {
               "gpu": "102b:0534",
               "id": "build134-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -50807,7 +50807,7 @@
             {
               "gpu": "102b:0534",
               "id": "build134-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -50837,7 +50837,7 @@
             {
               "gpu": "102b:0534",
               "id": "build134-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -50869,7 +50869,7 @@
             {
               "gpu": "102b:0534",
               "id": "build134-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -50899,7 +50899,7 @@
             {
               "gpu": "102b:0534",
               "id": "build136-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -50931,7 +50931,7 @@
             {
               "gpu": "102b:0534",
               "id": "build136-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -50961,7 +50961,7 @@
             {
               "gpu": "102b:0534",
               "id": "build136-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -50993,7 +50993,7 @@
             {
               "gpu": "102b:0534",
               "id": "build136-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -51023,7 +51023,7 @@
             {
               "gpu": "102b:0534",
               "id": "build133-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -51055,7 +51055,7 @@
             {
               "gpu": "102b:0534",
               "id": "build133-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -51085,7 +51085,7 @@
             {
               "gpu": "102b:0534",
               "id": "build134-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -51115,7 +51115,7 @@
             {
               "gpu": "102b:0534",
               "id": "build135-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -51147,7 +51147,7 @@
             {
               "gpu": "102b:0534",
               "id": "build135-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -51179,7 +51179,7 @@
             {
               "gpu": "102b:0534",
               "id": "build134-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -51209,7 +51209,7 @@
             {
               "gpu": "102b:0534",
               "id": "build134-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -51239,7 +51239,7 @@
             {
               "gpu": "102b:0534",
               "id": "build135-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -51271,7 +51271,7 @@
             {
               "gpu": "102b:0534",
               "id": "build135-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -51303,7 +51303,7 @@
             {
               "gpu": "102b:0534",
               "id": "build134-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -51333,7 +51333,7 @@
             {
               "gpu": "102b:0534",
               "id": "build136-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -51365,7 +51365,7 @@
             {
               "gpu": "102b:0534",
               "id": "build136-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -51395,7 +51395,7 @@
             {
               "gpu": "102b:0534",
               "id": "build132-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -51427,7 +51427,7 @@
             {
               "gpu": "102b:0534",
               "id": "build132-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -51457,7 +51457,7 @@
             {
               "gpu": "102b:0534",
               "id": "build134-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -51489,7 +51489,7 @@
             {
               "gpu": "102b:0534",
               "id": "build134-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -51519,7 +51519,7 @@
             {
               "gpu": "102b:0534",
               "id": "build134-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -51551,7 +51551,7 @@
             {
               "gpu": "102b:0534",
               "id": "build134-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -51581,7 +51581,7 @@
             {
               "gpu": "102b:0534",
               "id": "build133-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -51613,7 +51613,7 @@
             {
               "gpu": "102b:0534",
               "id": "build133-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -51643,7 +51643,7 @@
             {
               "gpu": "102b:0534",
               "id": "build133-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -51675,7 +51675,7 @@
             {
               "gpu": "102b:0534",
               "id": "build133-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -51705,7 +51705,7 @@
             {
               "gpu": "102b:0534",
               "id": "build135-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -51735,7 +51735,7 @@
             {
               "gpu": "102b:0534",
               "id": "build134-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -51767,7 +51767,7 @@
             {
               "gpu": "102b:0534",
               "id": "build134-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -51799,7 +51799,7 @@
             {
               "gpu": "102b:0534",
               "id": "build135-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -51829,7 +51829,7 @@
             {
               "gpu": "102b:0534",
               "id": "build135-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -51861,7 +51861,7 @@
             {
               "gpu": "102b:0534",
               "id": "build135-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -51891,7 +51891,7 @@
             {
               "gpu": "102b:0534",
               "id": "build132-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -51912,7 +51912,7 @@
             {
               "gpu": "102b:0534",
               "id": "build135-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -51942,7 +51942,7 @@
             {
               "gpu": "102b:0534",
               "id": "build134-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -51974,7 +51974,7 @@
             {
               "gpu": "102b:0534",
               "id": "build134-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -52004,7 +52004,7 @@
             {
               "gpu": "102b:0534",
               "id": "build133-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
@@ -52036,7 +52036,7 @@
             {
               "gpu": "102b:0534",
               "id": "build133-m1",
-              "os": "Windows-10-10240",
+              "os": "Windows-10",
               "pool": "Chrome-perf"
             }
           ],
diff --git a/testing/buildbot/filters/mojo.fyi.network_browser_tests.filter b/testing/buildbot/filters/mojo.fyi.network_browser_tests.filter
index e2053c3..60e7b70 100644
--- a/testing/buildbot/filters/mojo.fyi.network_browser_tests.filter
+++ b/testing/buildbot/filters/mojo.fyi.network_browser_tests.filter
@@ -60,8 +60,6 @@
 -WebViewTests/WebViewTest.ClearPersistentCookies/1
 -WebViewTests/WebViewTest.ClearSessionCookies/0
 -WebViewTests/WebViewTest.ClearSessionCookies/1
--WebViewTests/WebViewTest.DownloadCookieIsolation/0
--WebViewTests/WebViewTest.DownloadCookieIsolation/1
 -WebViewTests/WebViewTest.DownloadCookieIsolation_CrossSession/0
 -WebViewTests/WebViewTest.DownloadCookieIsolation_CrossSession/1
 -WebViewTests/WebViewTest.StoragePersistence/0
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index c5b71e7..706b970 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -2108,6 +2108,25 @@
             ]
         }
     ],
+    "NavigationMojoResponse": [
+        {
+            "platforms": [
+                "android",
+                "chromeos",
+                "linux",
+                "mac",
+                "win"
+            ],
+            "experiments": [
+                {
+                    "name": "NavigationMojoResponse",
+                    "enable_features": [
+                        "NavigationMojoResponse"
+                    ]
+                }
+            ]
+        }
+    ],
     "NetAdaptiveProxyConnectionTimeout": [
         {
             "platforms": [
diff --git a/third_party/WebKit/LayoutTests/MSANExpectations b/third_party/WebKit/LayoutTests/MSANExpectations
index ad6dfa693..52ec24d1 100644
--- a/third_party/WebKit/LayoutTests/MSANExpectations
+++ b/third_party/WebKit/LayoutTests/MSANExpectations
@@ -36,8 +36,11 @@
 crbug.com/462190 [ Linux ] inspector-protocol/heap-profiler/heap-samples-in-snapshot.js [ Timeout ]
 crbug.com/462190 [ Linux ] inspector-protocol/heap-profiler/heap-snapshot-merged-nodes.js [ Timeout ]
 crbug.com/462190 [ Linux ] inspector-protocol/heap-profiler/heap-snapshot-with-active-dom-object.js [ Timeout ]
+crbug.com/462190 [ Linux ] inspector-protocol/heap-profiler/heap-snapshot-with-detached-dom-tree.js [ Timeout ]
+crbug.com/462190 [ Linux ] inspector-protocol/heap-profiler/heap-snapshot-with-detached-iframe.js [ Timeout ]
 crbug.com/462190 [ Linux ] inspector-protocol/heap-profiler/heap-snapshot-with-event-listener.js [ Timeout ]
 crbug.com/462190 [ Linux ] inspector-protocol/heap-profiler/heap-snapshot-with-multiple-retainers.js [ Timeout ]
+crbug.com/462190 [ Linux ] inspector-protocol/heap-profiler/heap-snapshot-with-no-detached-iframe.js [ Timeout ]
 
 crbug.com/667560 [ Linux ] http/tests/devtools/startup/console/console-format-startup.js [ Timeout Pass ]
 crbug.com/751906 [ Linux ] http/tests/devtools/console/console-correct-suggestions.js [ Timeout Pass ]
diff --git a/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json b/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
index 4313256..846f5b2d 100644
--- a/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
+++ b/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
@@ -82445,6 +82445,90 @@
      {}
     ]
    ],
+   "css/vendor-imports/mozilla/mozilla-central-reftests/color4/background-color-hsl-001.html": [
+    [
+     "/css/vendor-imports/mozilla/mozilla-central-reftests/color4/background-color-hsl-001.html",
+     [
+      [
+       "/css/vendor-imports/mozilla/mozilla-central-reftests/color4/background-color-hsl-001-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/vendor-imports/mozilla/mozilla-central-reftests/color4/background-color-hsl-002.html": [
+    [
+     "/css/vendor-imports/mozilla/mozilla-central-reftests/color4/background-color-hsl-002.html",
+     [
+      [
+       "/css/vendor-imports/mozilla/mozilla-central-reftests/color4/background-color-hsl-002-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/vendor-imports/mozilla/mozilla-central-reftests/color4/background-color-hsl-003.html": [
+    [
+     "/css/vendor-imports/mozilla/mozilla-central-reftests/color4/background-color-hsl-003.html",
+     [
+      [
+       "/css/vendor-imports/mozilla/mozilla-central-reftests/color4/background-color-hsl-003-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/vendor-imports/mozilla/mozilla-central-reftests/color4/background-color-hsl-004.html": [
+    [
+     "/css/vendor-imports/mozilla/mozilla-central-reftests/color4/background-color-hsl-004.html",
+     [
+      [
+       "/css/vendor-imports/mozilla/mozilla-central-reftests/color4/background-color-hsl-004-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/vendor-imports/mozilla/mozilla-central-reftests/color4/background-color-rgb-001.html": [
+    [
+     "/css/vendor-imports/mozilla/mozilla-central-reftests/color4/background-color-rgb-001.html",
+     [
+      [
+       "/css/vendor-imports/mozilla/mozilla-central-reftests/color4/background-color-rgb-001-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/vendor-imports/mozilla/mozilla-central-reftests/color4/background-color-rgb-002.html": [
+    [
+     "/css/vendor-imports/mozilla/mozilla-central-reftests/color4/background-color-rgb-002.html",
+     [
+      [
+       "/css/vendor-imports/mozilla/mozilla-central-reftests/color4/background-color-rgb-002-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/vendor-imports/mozilla/mozilla-central-reftests/color4/background-color-rgb-003.html": [
+    [
+     "/css/vendor-imports/mozilla/mozilla-central-reftests/color4/background-color-rgb-003.html",
+     [
+      [
+       "/css/vendor-imports/mozilla/mozilla-central-reftests/color4/background-color-rgb-003-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/vendor-imports/mozilla/mozilla-central-reftests/counter-styles-3/dependent-builtin.html": [
     [
      "/css/vendor-imports/mozilla/mozilla-central-reftests/counter-styles-3/dependent-builtin.html",
@@ -107941,6 +108025,11 @@
      {}
     ]
    ],
+   "css/css-font-loading/idlharness.https-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "css/css-fonts/OWNERS": [
     [
      {}
@@ -124026,6 +124115,11 @@
      {}
     ]
    ],
+   "css/css-typed-om/the-stylepropertymap/properties/flex-basis-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "css/css-typed-om/the-stylepropertymap/properties/font-style-expected.txt": [
     [
      {}
@@ -131306,6 +131400,41 @@
      {}
     ]
    ],
+   "css/vendor-imports/mozilla/mozilla-central-reftests/color4/background-color-hsl-001-ref.html": [
+    [
+     {}
+    ]
+   ],
+   "css/vendor-imports/mozilla/mozilla-central-reftests/color4/background-color-hsl-002-ref.html": [
+    [
+     {}
+    ]
+   ],
+   "css/vendor-imports/mozilla/mozilla-central-reftests/color4/background-color-hsl-003-ref.html": [
+    [
+     {}
+    ]
+   ],
+   "css/vendor-imports/mozilla/mozilla-central-reftests/color4/background-color-hsl-004-ref.html": [
+    [
+     {}
+    ]
+   ],
+   "css/vendor-imports/mozilla/mozilla-central-reftests/color4/background-color-rgb-001-ref.html": [
+    [
+     {}
+    ]
+   ],
+   "css/vendor-imports/mozilla/mozilla-central-reftests/color4/background-color-rgb-002-ref.html": [
+    [
+     {}
+    ]
+   ],
+   "css/vendor-imports/mozilla/mozilla-central-reftests/color4/background-color-rgb-003-ref.html": [
+    [
+     {}
+    ]
+   ],
    "css/vendor-imports/mozilla/mozilla-central-reftests/counter-styles-3/dependent-builtin-ref.html": [
     [
      {}
@@ -149961,6 +150090,11 @@
      {}
     ]
    ],
+   "interfaces/css-font-loading.idl": [
+    [
+     {}
+    ]
+   ],
    "interfaces/css-typed-om.idl": [
     [
      {}
@@ -178897,6 +179031,12 @@
      {}
     ]
    ],
+   "css/css-font-loading/idlharness.https.html": [
+    [
+     "/css/css-font-loading/idlharness.https.html",
+     {}
+    ]
+   ],
    "css/css-fonts/calc-in-font-variation-settings.html": [
     [
      "/css/css-fonts/calc-in-font-variation-settings.html",
@@ -182845,6 +182985,12 @@
      {}
     ]
    ],
+   "css/css-typed-om/stylevalue-subclasses/cssKeywordValue-value.html": [
+    [
+     "/css/css-typed-om/stylevalue-subclasses/cssKeywordValue-value.html",
+     {}
+    ]
+   ],
    "css/css-typed-om/stylevalue-subclasses/cssKeywordValue.html": [
     [
      "/css/css-typed-om/stylevalue-subclasses/cssKeywordValue.html",
@@ -183403,6 +183549,48 @@
      {}
     ]
    ],
+   "css/css-typed-om/the-stylepropertymap/properties/flex-basis.html": [
+    [
+     "/css/css-typed-om/the-stylepropertymap/properties/flex-basis.html",
+     {}
+    ]
+   ],
+   "css/css-typed-om/the-stylepropertymap/properties/flex-direction.html": [
+    [
+     "/css/css-typed-om/the-stylepropertymap/properties/flex-direction.html",
+     {}
+    ]
+   ],
+   "css/css-typed-om/the-stylepropertymap/properties/flex-flow.html": [
+    [
+     "/css/css-typed-om/the-stylepropertymap/properties/flex-flow.html",
+     {}
+    ]
+   ],
+   "css/css-typed-om/the-stylepropertymap/properties/flex-grow.html": [
+    [
+     "/css/css-typed-om/the-stylepropertymap/properties/flex-grow.html",
+     {}
+    ]
+   ],
+   "css/css-typed-om/the-stylepropertymap/properties/flex-shrink.html": [
+    [
+     "/css/css-typed-om/the-stylepropertymap/properties/flex-shrink.html",
+     {}
+    ]
+   ],
+   "css/css-typed-om/the-stylepropertymap/properties/flex-wrap.html": [
+    [
+     "/css/css-typed-om/the-stylepropertymap/properties/flex-wrap.html",
+     {}
+    ]
+   ],
+   "css/css-typed-om/the-stylepropertymap/properties/flex.html": [
+    [
+     "/css/css-typed-om/the-stylepropertymap/properties/flex.html",
+     {}
+    ]
+   ],
    "css/css-typed-om/the-stylepropertymap/properties/float.html": [
     [
      "/css/css-typed-om/the-stylepropertymap/properties/float.html",
@@ -277130,6 +277318,14 @@
    "ad355c3d5220c1b938182241a8e8abe030ace699",
    "testharness"
   ],
+  "css/css-font-loading/idlharness.https-expected.txt": [
+   "2711c37911c9d0547173d0ebb4215745017d43fb",
+   "support"
+  ],
+  "css/css-font-loading/idlharness.https.html": [
+   "00399ffcb0ff8000e79ab4aeefdb90cabdb0fd4d",
+   "testharness"
+  ],
   "css/css-fonts/OWNERS": [
    "18aa6fb5e88093cc3ddbe9b22d2b008a3c3a6477",
    "support"
@@ -303023,11 +303219,15 @@
    "testharness"
   ],
   "css/css-typed-om/stylevalue-subclasses/cssKeywordValue-invalid.html": [
-   "63600cc74e62ecbaf98bf786de17362764ec947e",
+   "b20c888c2ecc5dc7f87a2fa7114141a86a63598d",
+   "testharness"
+  ],
+  "css/css-typed-om/stylevalue-subclasses/cssKeywordValue-value.html": [
+   "55f20761cbbe3dc27c718621d3e4d57eae041e8a",
    "testharness"
   ],
   "css/css-typed-om/stylevalue-subclasses/cssKeywordValue.html": [
-   "236520d8ac6199066d1e082b9860f2381ff61be6",
+   "d2ab852da57ca24e9675fd670a0bf3546063fa69",
    "testharness"
   ],
   "css/css-typed-om/stylevalue-subclasses/cssMatrixComponent.tentative.html": [
@@ -303422,6 +303622,38 @@
    "d7424e7fb7c27cfa31fb0e40ee9045129ed96c03",
    "testharness"
   ],
+  "css/css-typed-om/the-stylepropertymap/properties/flex-basis-expected.txt": [
+   "d68571702188ba3bf28ea394e618f7ff0d8fe5d8",
+   "support"
+  ],
+  "css/css-typed-om/the-stylepropertymap/properties/flex-basis.html": [
+   "87f3eed7306a43a312c95fd8b525fcd5d3e167cc",
+   "testharness"
+  ],
+  "css/css-typed-om/the-stylepropertymap/properties/flex-direction.html": [
+   "a27187c16080fe2daacd1c0a99657773a2b8c2d0",
+   "testharness"
+  ],
+  "css/css-typed-om/the-stylepropertymap/properties/flex-flow.html": [
+   "7cc29cb60930ad904ac6a90ed6fad5673b84ed81",
+   "testharness"
+  ],
+  "css/css-typed-om/the-stylepropertymap/properties/flex-grow.html": [
+   "7882699c2414306523501d253115198622a18cc9",
+   "testharness"
+  ],
+  "css/css-typed-om/the-stylepropertymap/properties/flex-shrink.html": [
+   "8025e8905f2547ebdad41159c1872e6c9d868458",
+   "testharness"
+  ],
+  "css/css-typed-om/the-stylepropertymap/properties/flex-wrap.html": [
+   "1f57e275b4c9d195e9f82ead41410f0954fdff86",
+   "testharness"
+  ],
+  "css/css-typed-om/the-stylepropertymap/properties/flex.html": [
+   "3bfc9c981b2131ed480f5d0bc2b90f76743e2b28",
+   "testharness"
+  ],
   "css/css-typed-om/the-stylepropertymap/properties/float.html": [
    "1dfca0045c2b57f36d5165139087301ffe54c63a",
    "testharness"
@@ -316306,6 +316538,62 @@
    "8a2dd4d9df36e30405b98391b37c34bf7a9626e8",
    "reftest"
   ],
+  "css/vendor-imports/mozilla/mozilla-central-reftests/color4/background-color-hsl-001-ref.html": [
+   "62aefeb96bc6427e444c5f8f9d3ca4e5db75cbde",
+   "support"
+  ],
+  "css/vendor-imports/mozilla/mozilla-central-reftests/color4/background-color-hsl-001.html": [
+   "22e5a0e050237ea6f8842951f65045e468fa1e13",
+   "reftest"
+  ],
+  "css/vendor-imports/mozilla/mozilla-central-reftests/color4/background-color-hsl-002-ref.html": [
+   "2908851b1673cb8e365b268fbd5efb8884e8fb8a",
+   "support"
+  ],
+  "css/vendor-imports/mozilla/mozilla-central-reftests/color4/background-color-hsl-002.html": [
+   "66dc81e18b0e14b28599da60495eee949559e6e4",
+   "reftest"
+  ],
+  "css/vendor-imports/mozilla/mozilla-central-reftests/color4/background-color-hsl-003-ref.html": [
+   "b63a415a9d01779265c284b5e0ab96126f81be29",
+   "support"
+  ],
+  "css/vendor-imports/mozilla/mozilla-central-reftests/color4/background-color-hsl-003.html": [
+   "204143162d5bb402c034ab9137a2c7d0c7d9d773",
+   "reftest"
+  ],
+  "css/vendor-imports/mozilla/mozilla-central-reftests/color4/background-color-hsl-004-ref.html": [
+   "09ee47b125984cd56db2bd55c69c70ec8fffc574",
+   "support"
+  ],
+  "css/vendor-imports/mozilla/mozilla-central-reftests/color4/background-color-hsl-004.html": [
+   "b6dffeba5007d6031be409bfc369bb4d7cb212de",
+   "reftest"
+  ],
+  "css/vendor-imports/mozilla/mozilla-central-reftests/color4/background-color-rgb-001-ref.html": [
+   "cc8960069089b49e2483d56d741ead5fd6d1dc0f",
+   "support"
+  ],
+  "css/vendor-imports/mozilla/mozilla-central-reftests/color4/background-color-rgb-001.html": [
+   "6b198e21da4b54d421b4085de81886ba1aa7e3e7",
+   "reftest"
+  ],
+  "css/vendor-imports/mozilla/mozilla-central-reftests/color4/background-color-rgb-002-ref.html": [
+   "adfe9c5e9d5a9beefae3028c568605150f4c4b0b",
+   "support"
+  ],
+  "css/vendor-imports/mozilla/mozilla-central-reftests/color4/background-color-rgb-002.html": [
+   "8bc4299480079e93164f1a4010b3d65617f96984",
+   "reftest"
+  ],
+  "css/vendor-imports/mozilla/mozilla-central-reftests/color4/background-color-rgb-003-ref.html": [
+   "37d8c2c639214cb8532426a7cae297246d95dc1b",
+   "support"
+  ],
+  "css/vendor-imports/mozilla/mozilla-central-reftests/color4/background-color-rgb-003.html": [
+   "c287e46a8dd6df43f302f8049c8d03afde211494",
+   "reftest"
+  ],
   "css/vendor-imports/mozilla/mozilla-central-reftests/counter-styles-3/dependent-builtin-ref.html": [
    "d69196dab17976f19490ad2df62117f0317ecb32",
    "support"
@@ -346102,6 +346390,10 @@
    "0d74ef8e7681fddddfb786b75075a1dd0ddb9147",
    "support"
   ],
+  "interfaces/css-font-loading.idl": [
+   "a0d53cc4e88f38cce9fd45759963e5da9a6f3dc3",
+   "support"
+  ],
   "interfaces/css-typed-om.idl": [
    "3c918afebfb20266dd4003e71a008ed19c448fbc",
    "support"
diff --git a/third_party/WebKit/LayoutTests/external/wpt/client-hints/accept_ch.http.html b/third_party/WebKit/LayoutTests/external/wpt/client-hints/accept_ch.http.html
new file mode 100644
index 0000000..447dd28
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/client-hints/accept_ch.http.html
@@ -0,0 +1,33 @@
+<html>
+<body>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<script>
+
+// When the response for the HTML file contains "Accept-CH" in the response
+// headers, then the browser should not attach the specified client hints in
+// the HTTP request headers if the response was delivered by an insecure HTTP
+// server. Test this functionality by fetching an XHR from this page hosted on
+// an insecure HTTP server. The response headers for this page include
+// "Accept-CH: device-memory, dpr, viewport-width".
+//
+// echo_client_hints_received.py includes "device-memory-received",
+// "dpr-received" and "viewport-width-received" in the response headers
+// depending on the set of client hints it receives in the request headers.
+
+  promise_test(t => {
+  return fetch("/client-hints/echo_client_hints_received.py").then(r => {
+    assert_equals(r.status, 200)
+    // Verify that the browser does not include client hints in the headers
+    // when fetching the XHR from an insecure HTTP server.
+    assert_false(r.headers.has("device-memory-received"));
+    assert_false(r.headers.has("dpr-received"));
+    assert_false(r.headers.has("viewport-width-received"));
+  });
+}, "Accept-CH header test");
+
+</script>
+
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/client-hints/accept_ch.http.html.headers b/third_party/WebKit/LayoutTests/external/wpt/client-hints/accept_ch.http.html.headers
new file mode 100644
index 0000000..38f4f33
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/client-hints/accept_ch.http.html.headers
@@ -0,0 +1 @@
+Accept-CH: device-memory, dpr, viewport-width
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/client-hints/accept_ch.https.html b/third_party/WebKit/LayoutTests/external/wpt/client-hints/accept_ch.https.html
deleted file mode 100644
index c0f0581..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/client-hints/accept_ch.https.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<html>
-<body>
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-
-<script>
-
-// If the response for the HTML file contains "Accept-CH: device-memory" in
-// the response headers, then the browser should attach device-memory client
-// hint in the HTTP request headers. Test this functionality by fetching an
-// XHR from this page. The response headers for this page include
-// "Accept-CH: device-memory".
-//
-// echo_device_memory_header_received.py includes "device-memory-received" in
-// the response headers only if the request included "device-memory" in the
-// headers.
-
-  promise_test(t => {
-  return fetch("/client-hints/echo_device_memory_header_received.py").then(r => {
-    assert_equals(r.status, 200)
-    // Verify that the browser included "device-memory" in the headers when
-    // fetching the XHR.
-    assert_true(r.headers.has("device-memory-received"));
-  });
-}, "Accept-CH header test");
-
-</script>
-
-</body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/client-hints/accept_ch.https.html.headers b/third_party/WebKit/LayoutTests/external/wpt/client-hints/accept_ch.https.html.headers
deleted file mode 100644
index 401e1af..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/client-hints/accept_ch.https.html.headers
+++ /dev/null
@@ -1 +0,0 @@
-Accept-CH: device-memory
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/client-hints/accept_ch.sub.https.html b/third_party/WebKit/LayoutTests/external/wpt/client-hints/accept_ch.sub.https.html
new file mode 100644
index 0000000..6826326
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/client-hints/accept_ch.sub.https.html
@@ -0,0 +1,32 @@
+<html>
+<body>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<script>
+
+// If the response for the HTML file contains "Accept-CH" in the response
+// headers, then the browser should attach the specified client hints in the
+// HTTP request headers. Test this functionality by fetching an
+// XHR from this page. The response headers for this page include
+// "Accept-CH: device-memory, dpr, viewport-width".
+//
+// echo_client_hints_received.py includes "device-memory-received",
+// "dpr-received" and "viewport-width-received" in the response headers
+// depending on the set of client hints it receives in the request headers.
+
+  promise_test(t => {
+  return fetch("https://{{domains[]}}:{{ports[https][0]}}/client-hints/echo_client_hints_received.py", {"mode": "no-cors"}).then(r => {
+    assert_equals(r.status, 200)
+    // Verify that the browser includes client hints in the headers when
+    // fetching the XHR.
+    assert_true(r.headers.has("device-memory-received"), "device-memory-received");
+    assert_true(r.headers.has("dpr-received"), "dpr-received");
+    assert_true(r.headers.has("viewport-width-received"), "viewport-width-received");
+  });
+}, "Accept-CH header test");
+
+</script>
+
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/client-hints/accept_ch.sub.https.html.headers b/third_party/WebKit/LayoutTests/external/wpt/client-hints/accept_ch.sub.https.html.headers
new file mode 100644
index 0000000..38f4f33
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/client-hints/accept_ch.sub.https.html.headers
@@ -0,0 +1 @@
+Accept-CH: device-memory, dpr, viewport-width
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/client-hints/echo_client_hints_received.py b/third_party/WebKit/LayoutTests/external/wpt/client-hints/echo_client_hints_received.py
new file mode 100644
index 0000000..a787fed
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/client-hints/echo_client_hints_received.py
@@ -0,0 +1,12 @@
+def main(request, response):
+    """
+    Simple handler that sets a response header based on if device-memory
+    request header was received or not.
+    """
+
+    if "device-memory" in request.headers:
+            response.headers.set("device-memory-received", "true")
+    if "dpr" in request.headers:
+            response.headers.set("dpr-received", "true")
+    if "viewport-width" in request.headers:
+            response.headers.set("viewport-width-received", "true")
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/client-hints/echo_device_memory_header_received.py b/third_party/WebKit/LayoutTests/external/wpt/client-hints/echo_device_memory_header_received.py
deleted file mode 100644
index 0ab4368..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/client-hints/echo_device_memory_header_received.py
+++ /dev/null
@@ -1,8 +0,0 @@
-def main(request, response):
-    """
-    Simple handler that sets a response header based on if device-memory
-    request header was received or not.
-    """
-
-    if "device-memory" in request.headers:
-            response.headers.set("device-memory-received", "true")
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-font-loading/idlharness.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/css/css-font-loading/idlharness.https-expected.txt
new file mode 100644
index 0000000..61a0d30
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-font-loading/idlharness.https-expected.txt
@@ -0,0 +1,78 @@
+frame (anonymous) - didStartProvisionalLoadForFrame
+frame (anonymous) - didCommitLoadForFrame
+main frame - didReceiveTitle: Font Loading API IDL tests
+main frame - didFinishDocumentLoadForFrame
+main frame - didHandleOnloadEventsForFrame
+main frame - didFinishLoadForFrame
+This is a testharness.js-based test.
+PASS Test IDL implementation of CSS Font Loading
+PASS Document interface: attribute fonts
+PASS Unscopable handled correctly for fonts property on Document
+PASS Document interface: document must inherit property "fonts" with the proper type
+PASS WorkerGlobalScope interface: existence and properties of interface object
+PASS FontFace interface: existence and properties of interface object
+PASS FontFace interface object length
+PASS FontFace interface object name
+PASS FontFace interface: existence and properties of interface prototype object
+PASS FontFace interface: existence and properties of interface prototype object's "constructor" property
+PASS FontFace interface: existence and properties of interface prototype object's @@unscopables property
+PASS FontFace interface: attribute family
+PASS Unscopable handled correctly for family property on FontFace
+PASS FontFace interface: attribute style
+PASS Unscopable handled correctly for style property on FontFace
+PASS FontFace interface: attribute weight
+PASS Unscopable handled correctly for weight property on FontFace
+PASS FontFace interface: attribute stretch
+PASS Unscopable handled correctly for stretch property on FontFace
+PASS FontFace interface: attribute unicodeRange
+PASS Unscopable handled correctly for unicodeRange property on FontFace
+PASS FontFace interface: attribute variant
+PASS Unscopable handled correctly for variant property on FontFace
+PASS FontFace interface: attribute featureSettings
+PASS Unscopable handled correctly for featureSettings property on FontFace
+FAIL FontFace interface: attribute variationSettings assert_true: The prototype object must have a property "variationSettings" expected true got false
+PASS Unscopable handled correctly for variationSettings property on FontFace
+PASS FontFace interface: attribute display
+PASS Unscopable handled correctly for display property on FontFace
+PASS FontFace interface: attribute status
+PASS Unscopable handled correctly for status property on FontFace
+PASS FontFace interface: operation load()
+PASS Unscopable handled correctly for load() on FontFace
+PASS FontFace interface: attribute loaded
+PASS Unscopable handled correctly for loaded property on FontFace
+PASS FontFaceSetLoadEvent interface: existence and properties of interface object
+PASS FontFaceSetLoadEvent interface object length
+PASS FontFaceSetLoadEvent interface object name
+PASS FontFaceSetLoadEvent interface: existence and properties of interface prototype object
+PASS FontFaceSetLoadEvent interface: existence and properties of interface prototype object's "constructor" property
+PASS FontFaceSetLoadEvent interface: existence and properties of interface prototype object's @@unscopables property
+PASS FontFaceSetLoadEvent interface: attribute fontfaces
+PASS Unscopable handled correctly for fontfaces property on FontFaceSetLoadEvent
+FAIL FontFaceSet interface: existence and properties of interface object assert_own_property: self does not have own property "FontFaceSet" expected property "FontFaceSet" missing
+FAIL FontFaceSet interface object length assert_own_property: self does not have own property "FontFaceSet" expected property "FontFaceSet" missing
+FAIL FontFaceSet interface object name assert_own_property: self does not have own property "FontFaceSet" expected property "FontFaceSet" missing
+FAIL FontFaceSet interface: existence and properties of interface prototype object assert_own_property: self does not have own property "FontFaceSet" expected property "FontFaceSet" missing
+FAIL FontFaceSet interface: existence and properties of interface prototype object's "constructor" property assert_own_property: self does not have own property "FontFaceSet" expected property "FontFaceSet" missing
+FAIL FontFaceSet interface: existence and properties of interface prototype object's @@unscopables property assert_own_property: self does not have own property "FontFaceSet" expected property "FontFaceSet" missing
+FAIL FontFaceSet interface: operation add(FontFace) assert_own_property: self does not have own property "FontFaceSet" expected property "FontFaceSet" missing
+PASS Unscopable handled correctly for add(FontFace) on FontFaceSet
+FAIL FontFaceSet interface: operation delete(FontFace) assert_own_property: self does not have own property "FontFaceSet" expected property "FontFaceSet" missing
+PASS Unscopable handled correctly for delete(FontFace) on FontFaceSet
+FAIL FontFaceSet interface: operation clear() assert_own_property: self does not have own property "FontFaceSet" expected property "FontFaceSet" missing
+PASS Unscopable handled correctly for clear() on FontFaceSet
+FAIL FontFaceSet interface: attribute onloading assert_own_property: self does not have own property "FontFaceSet" expected property "FontFaceSet" missing
+PASS Unscopable handled correctly for onloading property on FontFaceSet
+FAIL FontFaceSet interface: attribute onloadingdone assert_own_property: self does not have own property "FontFaceSet" expected property "FontFaceSet" missing
+PASS Unscopable handled correctly for onloadingdone property on FontFaceSet
+FAIL FontFaceSet interface: attribute onloadingerror assert_own_property: self does not have own property "FontFaceSet" expected property "FontFaceSet" missing
+PASS Unscopable handled correctly for onloadingerror property on FontFaceSet
+FAIL FontFaceSet interface: operation load(CSSOMString, CSSOMString) assert_own_property: self does not have own property "FontFaceSet" expected property "FontFaceSet" missing
+PASS Unscopable handled correctly for load(CSSOMString, CSSOMString) on FontFaceSet
+FAIL FontFaceSet interface: operation check(CSSOMString, CSSOMString) assert_own_property: self does not have own property "FontFaceSet" expected property "FontFaceSet" missing
+PASS Unscopable handled correctly for check(CSSOMString, CSSOMString) on FontFaceSet
+FAIL FontFaceSet interface: attribute ready assert_own_property: self does not have own property "FontFaceSet" expected property "FontFaceSet" missing
+PASS Unscopable handled correctly for ready property on FontFaceSet
+FAIL FontFaceSet interface: attribute status assert_own_property: self does not have own property "FontFaceSet" expected property "FontFaceSet" missing
+PASS Unscopable handled correctly for status property on FontFaceSet
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-font-loading/idlharness.https.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-font-loading/idlharness.https.html
new file mode 100644
index 0000000..037e62f9
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-font-loading/idlharness.https.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<title>Font Loading API IDL tests</title>
+<link rel="help" href="https://drafts.csswg.org/css-font-loading/#fontfacesetloadevent">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/WebIDLParser.js"></script>
+<script src="/resources/idlharness.js"></script>
+<script>
+"use strict";
+
+function doTest([dom, cssfontloading]) {
+  const idl_array = new IdlArray();
+  idl_array.add_untested_idls(dom);
+  idl_array.add_untested_idls("[Exposed=Worker] interface WorkerGlobalScope : EventTarget { };");
+  idl_array.add_objects({Document: ["document"]});
+  idl_array.add_idls(cssfontloading);
+  idl_array.test();
+}
+
+function fetchText(url) {
+  return fetch(url).then((response) => response.text());
+}
+
+promise_test(() => {
+  return Promise.all([
+    "/interfaces/dom.idl",
+    "/interfaces/css-font-loading.idl",
+  ].map(fetchText)).then(doTest);
+}, "Test IDL implementation of CSS Font Loading");
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/color4/background-color-hsl-001-ref.html b/third_party/WebKit/LayoutTests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/color4/background-color-hsl-001-ref.html
new file mode 100644
index 0000000..f37a73d
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/color4/background-color-hsl-001-ref.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title>CSS-Color-4: hsla() syntax accepts comma-less expressions (and comments as separators), percentage alpha and omitting of alpha component - ref</title>
+    <link rel="author" title="Jerry Shih" href="mailto:bignose1007@gmail.com" />
+    <link rel="author" title="Mozilla" href="http://www.mozilla.org/" />
+    <style type="text/css">
+      #p1 { background-color: hsla(120, 75%, 50%, 0.2); }
+      #p2 { background-color: hsla(120, 75%, 50%, 0.4); }
+      #p3 { background-color: hsla(120, 75%, 50%, 0.6); }
+      #p4 { background-color: hsl(120, 75%, 50%); }
+      #p5 { background-color: hsl(120, 75%, 50%); }
+      #p6 { background-color: hsl(120, 75%, 50%); }
+      #p7 { background-color: hsl(120, 75%, 50%); }
+      #p8 { background-color: hsl(120, 75%, 50%); }
+      #p9 { background-color: hsl(120, 75%, 50%); }
+      #p10 { background-color: hsl(120, 75%, 50%); }
+    </style>
+  </head>
+  <body>
+    <p id="p1">color</p>
+    <p id="p2">color</p>
+    <p id="p3">color</p>
+    <p id="p4">color</p>
+    <p id="p5">color</p>
+    <p id="p6">color</p>
+    <p id="p7">color</p>
+    <p id="p8">color</p>
+    <p id="p9">color</p>
+    <p id="p10">color</p>
+  </body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/color4/background-color-hsl-001.html b/third_party/WebKit/LayoutTests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/color4/background-color-hsl-001.html
new file mode 100644
index 0000000..2b8c7d31
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/color4/background-color-hsl-001.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title>CSS-Color-4: hsla() syntax accepts comma-less expressions (and comments as separators), percentage alpha and omitting of alpha component - test</title>
+    <link rel="author" title="Jerry Shih" href="mailto:bignose1007@gmail.com" />
+    <link rel="author" title="Mozilla" href="http://www.mozilla.org/" />
+    <link rel="help" href="https://drafts.csswg.org/css-color-4/#the-hsl-notation" />
+    <meta name="assert" content="hsla() should accept comma-less expressions (and comments as separators), percentage alpha and omitting of alpha component." />
+    <link rel="match" href="background-color-hsl-001-ref.html" />
+    <style type="text/css">
+      #p1 { background-color: hsla(120.0, 75%, 50%, 20%); }
+      #p2 { background-color: hsla(120, 75%, 50%, 0.4); }
+      #p3 { background-color: hsla(120 75% 50% / 60%); }
+      #p4 { background-color: hsla(120.0 75% 50% / 1.0); }
+      #p5 { background-color: hsla(120/* comment */75%/* comment */50%/1.0); }
+      #p6 { background-color: hsla(120,/* comment */75%,/* comment */50%,100%); }
+      #p7 { background-color: hsla(120.0, 75%, 50%); }
+      #p8 { background-color: hsla(120 75% 50%); }
+      #p9 { background-color: hsla(120/* comment */75%/* comment */50%); }
+      #p10 { background-color: hsla(120/* comment */,75%,/* comment */50%); }
+    </style>
+  </head>
+  <body>
+    <p id="p1">color</p>
+    <p id="p2">color</p>
+    <p id="p3">color</p>
+    <p id="p4">color</p>
+    <p id="p5">color</p>
+    <p id="p6">color</p>
+    <p id="p7">color</p>
+    <p id="p8">color</p>
+    <p id="p9">color</p>
+    <p id="p10">color</p>
+  </body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/color4/background-color-hsl-002-ref.html b/third_party/WebKit/LayoutTests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/color4/background-color-hsl-002-ref.html
new file mode 100644
index 0000000..90284b9
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/color4/background-color-hsl-002-ref.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title>CSS-Color-4: hsl() syntax accepts comma-less expressions (and comments as separators) and alpha component (and percentage alpha) - ref</title>
+    <link rel="author" title="Jerry Shih" href="mailto:bignose1007@gmail.com" />
+    <link rel="author" title="Mozilla" href="http://www.mozilla.org/" />
+    <style type="text/css">
+      #p1 { background-color: hsla(120, 75%, 50%, 0.2); }
+      #p2 { background-color: hsla(120, 75%, 50%, 0.4); }
+      #p3 { background-color: hsla(120, 75%, 50%, 0.6); }
+      #p4 { background-color: hsla(120, 75%, 50%, 0.8); }
+      #p5 { background-color: hsla(120.0, 75%, 50%, 1.0); }
+      #p6 { background-color: hsla(120.0, 75%, 50%, 1.0); }
+      #p7 { background-color: hsla(120.0, 75%, 50%, 1.0); }
+      #p8 { background-color: hsla(120, 75%, 50%, 1.0); }
+      #p9 { background-color: hsla(120, 75%, 50%, 1.0); }
+      #p10 { background-color: hsla(120, 75%, 50%, 1.0); }
+    </style>
+  </head>
+  <body>
+    <p id="p1">color</p>
+    <p id="p2">color</p>
+    <p id="p3">color</p>
+    <p id="p4">color</p>
+    <p id="p5">color</p>
+    <p id="p6">color</p>
+    <p id="p7">color</p>
+    <p id="p8">color</p>
+    <p id="p9">color</p>
+    <p id="p10">color</p>
+  </body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/color4/background-color-hsl-002.html b/third_party/WebKit/LayoutTests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/color4/background-color-hsl-002.html
new file mode 100644
index 0000000..a1e9a012
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/color4/background-color-hsl-002.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title>CSS-Color-4: hsl() syntax accepts comma-less expressions (and comments as separators) and alpha component (and percentage alpha) - test</title>
+    <link rel="author" title="Jerry Shih" href="mailto:bignose1007@gmail.com" />
+    <link rel="author" title="Mozilla" href="http://www.mozilla.org/" />
+    <link rel="help" href="https://drafts.csswg.org/css-color-4/#the-hsl-notation" />
+    <meta name="assert" content="hsl() should accept comma-less expressions (and comments as separators) and alpha component (and percentage alpha)." />
+    <link rel="match" href="background-color-hsl-002-ref.html" />
+    <style type="text/css">
+      #p1 { background-color: hsl(120, 75%, 50%, 0.2); }
+      #p2 { background-color: hsl(120, 75%, 50%, 40%); }
+      #p3 { background-color: hsl(120 75% 50% / 0.6); }
+      #p4 { background-color: hsl(120 75% 50% / 80%); }
+      #p5 { background-color: hsl(120/* comment */75%/* comment */50%/1.0); }
+      #p6 { background-color: hsl(120/* comment */75%/* comment */50%/100%); }
+      #p7 { background-color: hsl(120,/* comment */75%,/* comment */50%,1.0); }
+      #p8 { background-color: hsl(120,/* comment */75%,/* comment */50%,100%); }
+      #p9 { background-color: hsl(120/* comment */75%/* comment */50%); }
+      #p10 { background-color: hsl(120/* comment */,75%,/* comment */50%); }
+    </style>
+  </head>
+  <body>
+    <p id="p1">color</p>
+    <p id="p2">color</p>
+    <p id="p3">color</p>
+    <p id="p4">color</p>
+    <p id="p5">color</p>
+    <p id="p6">color</p>
+    <p id="p7">color</p>
+    <p id="p8">color</p>
+    <p id="p9">color</p>
+    <p id="p10">color</p>
+  </body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/color4/background-color-hsl-003-ref.html b/third_party/WebKit/LayoutTests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/color4/background-color-hsl-003-ref.html
new file mode 100644
index 0000000..e0db417
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/color4/background-color-hsl-003-ref.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title>CSS-Color-4: support <angle> value for hsl()/hsla() hue component - ref</title>
+    <link rel="author" title="Jerry Shih" href="mailto:bignose1007@gmail.com" />
+    <link rel="author" title="Mozilla" href="http://www.mozilla.org/" />
+    <style type="text/css">
+      #p1 { background-color: hsla(120, 75%, 50%, 0.2); }
+      #p2 { background-color: hsla(120.0, 75%, 50%, 0.4); }
+      #p3 { background-color: hsla(1.2e2, 75%, 50%, 0.6); }
+      #p4 { background-color: hsla(120, 75%, 50%, 0.8); }
+      #p5 { background-color: hsla(120, 75%, 50%, 1.0); }
+      #p6 { background-color: hsl(240, 75%, 50%); }
+      #p7 { background-color: hsl(600.0, 75%, 50%); }
+      #p8 { background-color: hsl(9.6e2, 75%, 50%); }
+      #p9 { background-color: hsl(600, 75%, 50%); }
+      #p10 { background-color: hsl(240, 75%, 50%); }
+    </style>
+  </head>
+  <body>
+    <p id="p1">color</p>
+    <p id="p2">color</p>
+    <p id="p3">color</p>
+    <p id="p4">color</p>
+    <p id="p5">color</p>
+    <p id="p6">color</p>
+    <p id="p7">color</p>
+    <p id="p8">color</p>
+    <p id="p9">color</p>
+    <p id="p10">color</p>
+  </body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/color4/background-color-hsl-003.html b/third_party/WebKit/LayoutTests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/color4/background-color-hsl-003.html
new file mode 100644
index 0000000..f9c256e17
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/color4/background-color-hsl-003.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title>CSS-Color-4: support <angle> value for hsl()/hsla() hue component - test</title>
+    <link rel="author" title="Jerry Shih" href="mailto:bignose1007@gmail.com" />
+    <link rel="author" title="Mozilla" href="http://www.mozilla.org/" />
+    <link rel="help" href="https://drafts.csswg.org/css-color-4/#the-hsl-notation" />
+    <meta name="assert" content="hsl()/hsla() hue component should support <angle> value." />
+    <link rel="match" href="background-color-hsl-003-ref.html" />
+    <style type="text/css">
+      #p1 { background-color: hsla(120, 75%, 50%, 0.2); }
+      #p2 { background-color: hsla(120deg, 75%, 50%, 0.4); }
+      #p3 { background-color: hsla(133.33333333grad, 75%, 50%, 0.6); }
+      #p4 { background-color: hsla(2.0943951024rad, 75%, 50%, 0.8); }
+      #p5 { background-color: hsla(0.3333333333turn, 75%, 50%, 1.0); }
+      #p6 { background-color: hsl(240, 75%, 50%); }
+      #p7 { background-color: hsl(600deg, 75%, 50%); }
+      #p8 { background-color: hsl(1066.66666666grad, 75%, 50%); }
+      #p9 { background-color: hsl(10.4719755118rad, 75%, 50%); }
+      #p10 { background-color: hsl(2.6666666666turn, 75%, 50%); }
+    </style>
+  </head>
+  <body>
+    <p id="p1">color</p>
+    <p id="p2">color</p>
+    <p id="p3">color</p>
+    <p id="p4">color</p>
+    <p id="p5">color</p>
+    <p id="p6">color</p>
+    <p id="p7">color</p>
+    <p id="p8">color</p>
+    <p id="p9">color</p>
+    <p id="p10">color</p>
+  </body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/color4/background-color-hsl-004-ref.html b/third_party/WebKit/LayoutTests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/color4/background-color-hsl-004-ref.html
new file mode 100644
index 0000000..f630740f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/color4/background-color-hsl-004-ref.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title>CSS-Color-4: hsla() and hsl() are aliases of each other - ref</title>
+    <link rel="author" title="Jerry Shih" href="mailto:bignose1007@gmail.com" />
+    <link rel="author" title="Mozilla" href="http://www.mozilla.org/" />
+    <style type="text/css">
+      #p1 { background-color: hsl(120, 75%, 50%); }
+      #p2 { background-color: hsl(120.0, 75%, 50%); }
+      #p3 { background-color: hsl(1.2e2, 75%, 50%); }
+      #p4 { background-color: hsl(1.2E2, 75%, 50%); }
+      #p5 { background-color: hsl(60, 75%, 50%); }
+      #p6 { background-color: hsla(120, 75%, 50%, 0.2); }
+      #p7 { background-color: hsla(120.0, 75%, 50%, 0.4); }
+      #p8 { background-color: hsla(1.2e2, 75%, 50%, 0.6); }
+      #p9 { background-color: hsla(1.2E2, 75%, 50%, 0.8); }
+      #p10 { background-color: hsla(60.0, 75%, 50%, 1.0); }
+    </style>
+  </head>
+  <body>
+    <p id="p1">color</p>
+    <p id="p2">color</p>
+    <p id="p3">color</p>
+    <p id="p4">color</p>
+    <p id="p5">color</p>
+    <p id="p6">color</p>
+    <p id="p7">color</p>
+    <p id="p8">color</p>
+    <p id="p9">color</p>
+    <p id="p10">color</p>
+  </body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/color4/background-color-hsl-004.html b/third_party/WebKit/LayoutTests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/color4/background-color-hsl-004.html
new file mode 100644
index 0000000..1cd6684
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/color4/background-color-hsl-004.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title>CSS-Color-4: hsla() and hsl() are aliases of each other - test</title>
+    <link rel="author" title="Jerry Shih" href="mailto:bignose1007@gmail.com" />
+    <link rel="author" title="Mozilla" href="http://www.mozilla.org/" />
+    <link rel="help" href="https://drafts.csswg.org/css-color-4/#the-hsl-notation" />
+    <meta name="assert" content="hsla() should have the identical grammar and behavior to hsl()." />
+    <link rel="match" href="background-color-hsl-004-ref.html" />
+    <style type="text/css">
+      #p1 { background-color: hsla(120, 75%, 50%); }
+      #p2 { background-color: hsla(120.0, 75%, 50%); }
+      #p3 { background-color: hsla(1.2e2, 75%, 50%); }
+      #p4 { background-color: hsla(1.2E2, 75%, 50%); }
+      #p5 { background-color: hsla(60, 75%, 50%); }
+      #p6 { background-color: hsl(120, 75%, 50%, 0.2); }
+      #p7 { background-color: hsl(120.0, 75%, 50%, 0.4); }
+      #p8 { background-color: hsl(1.2e2, 75%, 50%, 0.6); }
+      #p9 { background-color: hsl(1.2E2, 75%, 50%, 0.8); }
+      #p10 { background-color: hsl(60.0, 75%, 50%, 1.0); }
+    </style>
+  </head>
+  <body>
+    <p id="p1">color</p>
+    <p id="p2">color</p>
+    <p id="p3">color</p>
+    <p id="p4">color</p>
+    <p id="p5">color</p>
+    <p id="p6">color</p>
+    <p id="p7">color</p>
+    <p id="p8">color</p>
+    <p id="p9">color</p>
+    <p id="p10">color</p>
+  </body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/color4/background-color-rgb-001-ref.html b/third_party/WebKit/LayoutTests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/color4/background-color-rgb-001-ref.html
new file mode 100644
index 0000000..b03f0a3f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/color4/background-color-rgb-001-ref.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title>CSS-Color-4: rgb() syntax accepts alpha component (and percentage alpha value), non-integer components and comma-less expressions (and comments as separators) - ref</title>
+    <link rel="author" title="Jerry Shih" href="mailto:bignose1007@gmail.com" />
+    <link rel="author" title="Mozilla" href="http://www.mozilla.org/" />
+    <style type="text/css">
+      #p1 { background-color: rgba(10%, 60%, 10%, 0.2); }
+      #p2 { background-color: rgba(10, 175, 10, 0.4); }
+      #p3 { background-color: rgba(10, 175, 10, 0.6); }
+      #p4 { background-color: rgba(10, 175, 10, 0.8); }
+      #p5 { background-color: rgba(10, 175, 10, 1.0); }
+      #p6 { background-color: rgba(10, 150, 50, 1.0); }
+      #p7 { background-color: rgba(10%, 60%, 10%, 1.0); }
+      #p8 { background-color: rgb(10, 100, 100); }
+      #p9 { background-color: rgb(10, 75, 125); }
+      #p10 { background-color: rgb(10, 50, 150); }
+    </style>
+  </head>
+  <body>
+    <p id="p1">color</p>
+    <p id="p2">color</p>
+    <p id="p3">color</p>
+    <p id="p4">color</p>
+    <p id="p5">color</p>
+    <p id="p6">color</p>
+    <p id="p7">color</p>
+    <p id="p8">color</p>
+    <p id="p9">color</p>
+    <p id="p10">color</p>
+  </body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/color4/background-color-rgb-001.html b/third_party/WebKit/LayoutTests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/color4/background-color-rgb-001.html
new file mode 100644
index 0000000..061eeac
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/color4/background-color-rgb-001.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title>CSS-Color-4: rgb() syntax accepts alpha component (and percentage alpha value), non-integer components and comma-less expressions (and comments as separators) - test</title>
+    <link rel="author" title="Jerry Shih" href="mailto:bignose1007@gmail.com" />
+    <link rel="author" title="Mozilla" href="http://www.mozilla.org/" />
+    <link rel="help" href="https://drafts.csswg.org/css-color-4/#rgb-functions" />
+    <meta name="assert" content="rgb() should accept alpha component (and percentage alpha value), non-integer components and comma-less expressions (and comments as separators)." />
+    <link rel="match" href="background-color-rgb-001-ref.html" />
+    <style type="text/css">
+      #p1 { background-color: rgb(10%, 60%, 10%, 20%); }
+      #p2 { background-color: rgb(10, 175, 10, 0.4); }
+      #p3 { background-color: rgb(10 175 10 / 60%); }
+      #p4 { background-color: rgb(10.0 175.0 10.0 / 0.8); }
+      #p5 { background-color: rgb(10/* comment */175/* comment */10/100%); }
+      #p6 { background-color: rgb(10,/* comment */150,/* comment */50); }
+      #p7 { background-color: rgb(10%, 60%, 10%); }
+      #p8 { background-color: rgb(10.0 100.0 100.0); }
+      #p9 { background-color: rgb(10/* comment */75/* comment */125); }
+      #p10 { background-color: rgb(10.0, 50.0, 150.0); }
+    </style>
+  </head>
+  <body>
+    <p id="p1">color</p>
+    <p id="p2">color</p>
+    <p id="p3">color</p>
+    <p id="p4">color</p>
+    <p id="p5">color</p>
+    <p id="p6">color</p>
+    <p id="p7">color</p>
+    <p id="p8">color</p>
+    <p id="p9">color</p>
+    <p id="p10">color</p>
+  </body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/color4/background-color-rgb-002-ref.html b/third_party/WebKit/LayoutTests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/color4/background-color-rgb-002-ref.html
new file mode 100644
index 0000000..be29c86c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/color4/background-color-rgb-002-ref.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title>CSS-Color-4: rgba() syntax accepts non-integer components, comma-less expressions (and comments as separators), percentage alpha and omitting of alpha component - ref</title>
+    <link rel="author" title="Jerry Shih" href="mailto:bignose1007@gmail.com" />
+    <link rel="author" title="Mozilla" href="http://www.mozilla.org/" />
+    <style type="text/css">
+      #p1 { background-color: rgba(10, 175, 10, 0.2); }
+      #p2 { background-color: rgba(10, 175, 10, 0.4); }
+      #p3 { background-color: rgba(10%, 75%, 10%, 0.6); }
+      #p4 { background-color: rgba(10, 175, 10, 0.8); }
+      #p5 { background-color: rgb(10, 175, 10); }
+      #p6 { background-color: rgb(10, 150, 50); }
+      #p7 { background-color: rgb(10, 125, 75); }
+      #p8 { background-color: rgb(10%, 45%, 45%); }
+      #p9 { background-color: rgb(10, 75, 125); }
+      #p10 { background-color: rgb(10, 50, 150); }
+    </style>
+  </head>
+  <body>
+    <p id="p1">color</p>
+    <p id="p2">color</p>
+    <p id="p3">color</p>
+    <p id="p4">color</p>
+    <p id="p5">color</p>
+    <p id="p6">color</p>
+    <p id="p7">color</p>
+    <p id="p8">color</p>
+    <p id="p9">color</p>
+    <p id="p10">color</p>
+  </body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/color4/background-color-rgb-002.html b/third_party/WebKit/LayoutTests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/color4/background-color-rgb-002.html
new file mode 100644
index 0000000..8919f0e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/color4/background-color-rgb-002.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title>CSS-Color-4: rgba() syntax accepts non-integer components, comma-less expressions (and comments as separators), percentage alpha and omitting of alpha component - test</title>
+    <link rel="author" title="Jerry Shih" href="mailto:bignose1007@gmail.com" />
+    <link rel="author" title="Mozilla" href="http://www.mozilla.org/" />
+    <link rel="help" href="https://drafts.csswg.org/css-color-4/#rgb-functions" />
+    <meta name="assert" content="rgba() should accept non-integer components, comma-less expressions (and comments as separators), percentage alpha and omitting of alpha." />
+    <link rel="match" href="background-color-rgb-002-ref.html" />
+    <style type="text/css">
+      #p1 { background-color: rgba(10.0, 175.0, 10.0, 0.2); }
+      #p2 { background-color: rgba(10, 175, 10, 40%); }
+      #p3 { background-color: rgba(10% 75% 10% / 0.6); }
+      #p4 { background-color: rgba(10 175 10 / 80%); }
+      #p5 { background-color: rgba(10/* comment */175/* comment */10/100%); }
+      #p6 { background-color: rgba(10,/* comment */150,/* comment */50); }
+      #p7 { background-color: rgba(10.0, 125.0, 75.0); }
+      #p8 { background-color: rgba(10%, 45%, 45%); }
+      #p9 { background-color: rgba(10/* comment */75/* comment */125); }
+      #p10 { background-color: rgba(10.0, 50.0, 150.0); }
+    </style>
+  </head>
+  <body>
+    <p id="p1">color</p>
+    <p id="p2">color</p>
+    <p id="p3">color</p>
+    <p id="p4">color</p>
+    <p id="p5">color</p>
+    <p id="p6">color</p>
+    <p id="p7">color</p>
+    <p id="p8">color</p>
+    <p id="p9">color</p>
+    <p id="p10">color</p>
+  </body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/color4/background-color-rgb-003-ref.html b/third_party/WebKit/LayoutTests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/color4/background-color-rgb-003-ref.html
new file mode 100644
index 0000000..70227ad
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/color4/background-color-rgb-003-ref.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title>CSS-Color-4: rgb() and rgba() are aliases of each other - ref</title>
+    <link rel="author" title="Jerry Shih" href="mailto:bignose1007@gmail.com" />
+    <link rel="author" title="Mozilla" href="http://www.mozilla.org/" />
+    <style type="text/css">
+      #p1 { background-color: rgba(10, 175, 10, 0.2); }
+      #p2 { background-color: rgba(10, 175, 10, 0.4); }
+      #p3 { background-color: rgba(10, 175, 10, 0.6); }
+      #p4 { background-color: rgba(10%, 70%, 10%, 0.8); }
+      #p5 { background-color: rgba(10%, 70%, 10%, 1.0); }
+      #p6 { background-color: rgb(10, 150, 50); }
+      #p7 { background-color: rgb(10, 125, 75); }
+      #p8 { background-color: rgb(10%,40%, 40%); }
+      #p9 { background-color: rgb(10%, 45%, 50%); }
+      #p10 { background-color: rgb(10%, 50%, 60%); }
+    </style>
+  </head>
+  <body>
+    <p id="p1">color</p>
+    <p id="p2">color</p>
+    <p id="p3">color</p>
+    <p id="p4">color</p>
+    <p id="p5">color</p>
+    <p id="p6">color</p>
+    <p id="p7">color</p>
+    <p id="p8">color</p>
+    <p id="p9">color</p>
+    <p id="p10">color</p>
+  </body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/color4/background-color-rgb-003.html b/third_party/WebKit/LayoutTests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/color4/background-color-rgb-003.html
new file mode 100644
index 0000000..6a22ba0
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/color4/background-color-rgb-003.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title>CSS-Color-4: rgb() and rgba() are aliases of each other - test</title>
+    <link rel="author" title="Jerry Shih" href="mailto:bignose1007@gmail.com" />
+    <link rel="author" title="Mozilla" href="http://www.mozilla.org/" />
+    <link rel="help" href="https://drafts.csswg.org/css-color-4/#rgb-functions" />
+    <meta name="assert" content="rgb() should have the identical grammar and behavior to rgba()." />
+    <link rel="match" href="background-color-rgb-003-ref.html" />
+    <style type="text/css">
+      #p1 { background-color: rgb(10, 175, 10, 0.2); }
+      #p2 { background-color: rgb(10, 175, 10, 0.4); }
+      #p3 { background-color: rgb(10, 175, 10, 0.6); }
+      #p4 { background-color: rgb(10%, 70%, 10%, 0.8); }
+      #p5 { background-color: rgb(10%, 70%, 10%, 1.0); }
+      #p6 { background-color: rgba(10, 150, 50); }
+      #p7 { background-color: rgba(10, 125, 75); }
+      #p8 { background-color: rgba(10%,40%, 40%); }
+      #p9 { background-color: rgba(10%, 45%, 50%); }
+      #p10 { background-color: rgba(10%, 50%, 60%); }
+    </style>
+  </head>
+  <body>
+    <p id="p1">color</p>
+    <p id="p2">color</p>
+    <p id="p3">color</p>
+    <p id="p4">color</p>
+    <p id="p5">color</p>
+    <p id="p6">color</p>
+    <p id="p7">color</p>
+    <p id="p8">color</p>
+    <p id="p9">color</p>
+    <p id="p10">color</p>
+  </body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/interfaces/css-font-loading.idl b/third_party/WebKit/LayoutTests/external/wpt/interfaces/css-font-loading.idl
new file mode 100644
index 0000000..5609101
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/interfaces/css-font-loading.idl
@@ -0,0 +1,86 @@
+typedef (ArrayBuffer or ArrayBufferView) BinaryData;
+
+dictionary FontFaceDescriptors {
+  CSSOMString style = "normal";
+  CSSOMString weight = "normal";
+  CSSOMString stretch = "normal";
+  CSSOMString unicodeRange = "U+0-10FFFF";
+  CSSOMString variant = "normal";
+  CSSOMString featureSettings = "normal";
+  CSSOMString variationSettings = "normal";
+  CSSOMString display = "auto";
+};
+
+enum FontFaceLoadStatus { "unloaded", "loading", "loaded", "error" };
+
+[Constructor(CSSOMString family, (CSSOMString or BinaryData) source,
+             optional FontFaceDescriptors descriptors),
+ Exposed=(Window,Worker)]
+interface FontFace {
+  attribute CSSOMString family;
+  attribute CSSOMString style;
+  attribute CSSOMString weight;
+  attribute CSSOMString stretch;
+  attribute CSSOMString unicodeRange;
+  attribute CSSOMString variant;
+  attribute CSSOMString featureSettings;
+  attribute CSSOMString variationSettings;
+  attribute CSSOMString display;
+
+  readonly attribute FontFaceLoadStatus status;
+
+  Promise<FontFace> load();
+  readonly attribute Promise<FontFace> loaded;
+};
+
+dictionary FontFaceSetLoadEventInit : EventInit {
+  sequence<FontFace> fontfaces = [];
+};
+
+[Constructor(CSSOMString type, optional FontFaceSetLoadEventInit eventInitDict),
+ Exposed=(Window,Worker)]
+interface FontFaceSetLoadEvent : Event {
+  [SameObject] readonly attribute FrozenArray<FontFace> fontfaces;
+};
+
+enum FontFaceSetLoadStatus { "loading", "loaded" };
+
+callback ForEachCallback = void (FontFace font, long index, FontFaceSet self);
+
+[Exposed=(Window,Worker),
+ Constructor(sequence<FontFace> initialFaces)]
+interface FontFaceSet : EventTarget {
+  // FontFaceSet is Set-like!
+  setlike<FontFace>;
+  FontFaceSet add(FontFace font);
+  boolean delete(FontFace font);
+  void clear();
+
+  // events for when loading state changes
+  attribute EventHandler onloading;
+  attribute EventHandler onloadingdone;
+  attribute EventHandler onloadingerror;
+
+  // check and start loads if appropriate
+  // and fulfill promise when all loads complete
+  Promise<sequence<FontFace>> load(CSSOMString font, optional CSSOMString text = " ");
+
+  // return whether all fonts in the fontlist are loaded
+  // (does not initiate load if not available)
+  boolean check(CSSOMString font, optional CSSOMString text = " ");
+
+  // async notification that font loading and layout operations are done
+  readonly attribute Promise<FontFaceSet> ready;
+
+  // loading state, "loading" while one or more fonts loading, "loaded" otherwise
+  readonly attribute FontFaceSetLoadStatus status;
+};
+
+[Exposed=(Window,Worker),
+ NoInterfaceObject]
+interface FontFaceSource {
+  readonly attribute FontFaceSet fonts;
+};
+
+Document implements FontFaceSource;
+WorkerGlobalScope implements FontFaceSource;
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/heap-profiler/heap-snapshot-merged-nodes-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/heap-profiler/heap-snapshot-merged-nodes-expected.txt
index f506e097..e183171 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/heap-profiler/heap-snapshot-merged-nodes-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/heap-profiler/heap-snapshot-merged-nodes-expected.txt
@@ -2,5 +2,5 @@
 Took heap snapshot
 Parsed snapshot
 SUCCESS: found leaking
-SUCCESS: retaining path = [EventListener, InternalNode, HTMLDivElement, Window / file://, ]
+SUCCESS: retaining path = [Detached EventListener, Detached InternalNode, Detached HTMLDivElement, Window / file://, ]
 
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/heap-profiler/heap-snapshot-with-detached-dom-tree-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/heap-profiler/heap-snapshot-with-detached-dom-tree-expected.txt
new file mode 100644
index 0000000..93e02dc
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/heap-profiler/heap-snapshot-with-detached-dom-tree-expected.txt
@@ -0,0 +1,5 @@
+Test that all nodes from the detached DOM tree will be marked as detached.
+Took heap snapshot
+Parsed snapshot
+SUCCESS: found 3 detached DIV elements
+
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/heap-profiler/heap-snapshot-with-detached-dom-tree.js b/third_party/WebKit/LayoutTests/inspector-protocol/heap-profiler/heap-snapshot-with-detached-dom-tree.js
new file mode 100644
index 0000000..1c38b2b
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/heap-profiler/heap-snapshot-with-detached-dom-tree.js
@@ -0,0 +1,23 @@
+(async function(testRunner) {
+  var {page, session, dp} = await testRunner.startBlank(
+      `Test that all nodes from the detached DOM tree will be marked as detached.`);
+  await session.evaluate(`
+    window.retaining_wrapper = document.createElement('div');
+    var t = document.createElement('div');
+    retaining_wrapper.appendChild(t);
+    t.appendChild(document.createElement('div'));
+  `);
+  var Helper = await testRunner.loadScript('resources/heap-snapshot-common.js');
+  var helper = await Helper(testRunner, session);
+  var snapshot = await helper.takeHeapSnapshot();
+  var divCount = 0;
+  for (var it = snapshot._allNodes(); it.hasNext(); it.next()) {
+    if (it.node.name() === 'Detached HTMLDivElement')
+      ++divCount;
+  }
+  if (divCount === 3)
+    testRunner.log('SUCCESS: found 3 detached DIV elements');
+  else
+    return testRunner.fail('unexpected detached DIV count: ' + divCount);
+  testRunner.completeTest();
+})
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/heap-profiler/heap-snapshot-with-detached-iframe-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/heap-profiler/heap-snapshot-with-detached-iframe-expected.txt
new file mode 100644
index 0000000..2ee17548
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/heap-profiler/heap-snapshot-with-detached-iframe-expected.txt
@@ -0,0 +1,6 @@
+Test that a detached iframe will be marked as detached.
+Took heap snapshot
+Parsed snapshot
+SUCCESS: found Leak
+SUCCESS: detached iframe in retaining path
+
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/heap-profiler/heap-snapshot-with-detached-iframe.js b/third_party/WebKit/LayoutTests/inspector-protocol/heap-profiler/heap-snapshot-with-detached-iframe.js
new file mode 100644
index 0000000..525087ae
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/heap-profiler/heap-snapshot-with-detached-iframe.js
@@ -0,0 +1,43 @@
+(async function(testRunner) {
+  var {page, session, dp} = await testRunner.startBlank(
+      `Test that a detached iframe will be marked as detached.`);
+  dp.Page.enable();
+  session.evaluate(`
+    var frame = document.createElement('iframe');
+    frame.src = 'data:text/html,<script>class Leak{}; var x = new Leak();<'+
+                      '/script>';
+    document.body.appendChild(frame);
+    frame.addEventListener("load", function() {
+      var iframeWindow  = this.contentWindow;
+      function retainingListener() {
+        // This is leaking the iframe.
+        console.log(iframeWindow);
+      }
+      document.body.addEventListener('click', retainingListener, true);
+      document.body.removeChild(frame);
+    });
+  `);
+  await dp.Page.onceFrameStoppedLoading();
+  var Helper = await testRunner.loadScript('resources/heap-snapshot-common.js');
+  var helper = await Helper(testRunner, session);
+  var snapshot = await helper.takeHeapSnapshot();
+  var node;
+  for (var it = snapshot._allNodes(); it.hasNext(); it.next()) {
+    if (it.node.className() === 'Leak') {
+      node = it.node;
+      break;
+    }
+  }
+  if (node)
+    testRunner.log('SUCCESS: found ' + node.name());
+  else
+    return testRunner.fail('cannot find leaking node');
+
+  var retainers = helper.firstRetainingPath(node).map(node => node.name());
+
+  if (retainers.includes('Detached Window'))
+    testRunner.log('SUCCESS: detached iframe in retaining path');
+  else
+    return testRunner.fail('no detached iframe in retaining path');
+  testRunner.completeTest();
+})
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/heap-profiler/heap-snapshot-with-no-detached-iframe-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/heap-profiler/heap-snapshot-with-no-detached-iframe-expected.txt
new file mode 100644
index 0000000..0cdd6fe
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/heap-profiler/heap-snapshot-with-no-detached-iframe-expected.txt
@@ -0,0 +1,6 @@
+Test that an attached iframe is not marked as detached.
+Took heap snapshot
+Parsed snapshot
+SUCCESS: found Leak
+SUCCESS: no detached iframe in retaining path
+
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/heap-profiler/heap-snapshot-with-no-detached-iframe.js b/third_party/WebKit/LayoutTests/inspector-protocol/heap-profiler/heap-snapshot-with-no-detached-iframe.js
new file mode 100644
index 0000000..d37947e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/heap-profiler/heap-snapshot-with-no-detached-iframe.js
@@ -0,0 +1,42 @@
+(async function(testRunner) {
+  var {page, session, dp} = await testRunner.startBlank(
+      `Test that an attached iframe is not marked as detached.`);
+  dp.Page.enable();
+  session.evaluate(`
+    var frame = document.createElement('iframe');
+    frame.src = 'data:text/html,<script>class Leak{}; var x = new Leak();<'+
+                      '/script>';
+    document.body.appendChild(frame);
+    frame.addEventListener("load", function() {
+      var iframeWindow  = this.contentWindow;
+      function retainingListener() {
+        // This is leaking the iframe.
+        console.log(iframeWindow);
+      }
+      document.body.addEventListener('click', retainingListener, true);
+    });
+  `);
+  await dp.Page.onceFrameStoppedLoading();
+  var Helper = await testRunner.loadScript('resources/heap-snapshot-common.js');
+  var helper = await Helper(testRunner, session);
+  var snapshot = await helper.takeHeapSnapshot();
+  var node;
+  for (var it = snapshot._allNodes(); it.hasNext(); it.next()) {
+    if (it.node.className() === 'Leak') {
+      node = it.node;
+      break;
+    }
+  }
+  if (node)
+    testRunner.log('SUCCESS: found ' + node.name());
+  else
+    return testRunner.fail('cannot find leaking node');
+
+  var retainers = helper.firstRetainingPath(node).map(node => node.name());
+
+  if (!retainers.includes('Detached Window'))
+    testRunner.log('SUCCESS: no detached iframe in retaining path');
+  else
+    return testRunner.fail('unexpected detached iframe in retaining path');
+  testRunner.completeTest();
+})
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/text-control-intrinsic-widths-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/text-control-intrinsic-widths-expected.txt
index 951cef4..55c8c325 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/text-control-intrinsic-widths-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/text-control-intrinsic-widths-expected.txt
@@ -140,30 +140,30 @@
 
 Andale Mono
 input
-size=1 clientWidth=35
-size=2 clientWidth=40
-size=3 clientWidth=45
-size=4 clientWidth=50
-size=5 clientWidth=55
+size=1 clientWidth=8
+size=2 clientWidth=16
+size=3 clientWidth=24
+size=4 clientWidth=32
+size=5 clientWidth=40
 size=10 clientWidth=80
-size=20 clientWidth=130
-size=50 clientWidth=280
-size=100 clientWidth=530
-size=500 clientWidth=2530
-size=1000 clientWidth=5030
+size=20 clientWidth=160
+size=50 clientWidth=400
+size=100 clientWidth=800
+size=500 clientWidth=4000
+size=1000 clientWidth=8000
 
 textarea
-cols=1 clientWidth=22
-cols=2 clientWidth=27
-cols=3 clientWidth=32
-cols=4 clientWidth=37
-cols=5 clientWidth=42
-cols=10 clientWidth=67
-cols=20 clientWidth=117
-cols=50 clientWidth=267
-cols=100 clientWidth=517
-cols=500 clientWidth=2517
-cols=1000 clientWidth=5017
+cols=1 clientWidth=25
+cols=2 clientWidth=33
+cols=3 clientWidth=41
+cols=4 clientWidth=49
+cols=5 clientWidth=57
+cols=10 clientWidth=97
+cols=20 clientWidth=177
+cols=50 clientWidth=417
+cols=100 clientWidth=817
+cols=500 clientWidth=4017
+cols=1000 clientWidth=8017
 
 Arial
 input
@@ -356,30 +356,30 @@
 
 Webdings
 input
-size=1 clientWidth=35
-size=2 clientWidth=40
-size=3 clientWidth=45
-size=4 clientWidth=50
-size=5 clientWidth=55
-size=10 clientWidth=80
-size=20 clientWidth=130
-size=50 clientWidth=280
-size=100 clientWidth=530
-size=500 clientWidth=2530
-size=1000 clientWidth=5030
+size=1 clientWidth=13
+size=2 clientWidth=26
+size=3 clientWidth=39
+size=4 clientWidth=52
+size=5 clientWidth=65
+size=10 clientWidth=130
+size=20 clientWidth=260
+size=50 clientWidth=650
+size=100 clientWidth=1300
+size=500 clientWidth=6500
+size=1000 clientWidth=13000
 
 textarea
-cols=1 clientWidth=22
-cols=2 clientWidth=27
-cols=3 clientWidth=32
-cols=4 clientWidth=37
-cols=5 clientWidth=42
-cols=10 clientWidth=67
-cols=20 clientWidth=117
-cols=50 clientWidth=267
-cols=100 clientWidth=517
-cols=500 clientWidth=2517
-cols=1000 clientWidth=5017
+cols=1 clientWidth=30
+cols=2 clientWidth=43
+cols=3 clientWidth=56
+cols=4 clientWidth=69
+cols=5 clientWidth=82
+cols=10 clientWidth=147
+cols=20 clientWidth=277
+cols=50 clientWidth=667
+cols=100 clientWidth=1317
+cols=500 clientWidth=6517
+cols=1000 clientWidth=13017
 
 PASS successfullyParsed is true
 
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/validation-bubble-appearance-edge-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/validation-bubble-appearance-edge-expected.png
index 2ea6c72..3cba6a5 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/validation-bubble-appearance-edge-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/validation-bubble-appearance-edge-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/validation-bubble-appearance-iframe-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/validation-bubble-appearance-iframe-expected.png
index 46a1f61..bc1a5dd 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/validation-bubble-appearance-iframe-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/validation-bubble-appearance-iframe-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/validation-bubble-appearance-rtl-ui-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/validation-bubble-appearance-rtl-ui-expected.png
index c796fc4..5ae5408 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/validation-bubble-appearance-rtl-ui-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/validation-bubble-appearance-rtl-ui-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/inspector-protocol/layout-fonts/generic-system-ui-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/inspector-protocol/layout-fonts/generic-system-ui-expected.txt
index d1300a6..d38fe9d 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/inspector-protocol/layout-fonts/generic-system-ui-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/inspector-protocol/layout-fonts/generic-system-ui-expected.txt
@@ -1,9 +1,9 @@
 This text should use the system font.
 #system-ui:
-"Arial" : 37
+"DejaVu Sans" : 37
 
 This text should use the system font.
 #system-ui-20pt:
-"Arial" : 37
+"DejaVu Sans" : 37
 
 
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/scalefactor150/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/scalefactor150/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
index 951b1ff..3700cba 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/scalefactor150/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/scalefactor150/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/scalefactor200/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/scalefactor200/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
index 9c3d202..44ba554 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/scalefactor200/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/scalefactor200/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/scalefactor200withzoom/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/scalefactor200withzoom/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
index 9c3d202..44ba554 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/scalefactor200withzoom/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/scalefactor200withzoom/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/virtual/scalefactor150/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/virtual/scalefactor150/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
deleted file mode 100644
index b1797c3..0000000
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/virtual/scalefactor150/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/virtual/scalefactor200withzoom/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/virtual/scalefactor200withzoom/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
deleted file mode 100644
index 4d8f4d9..0000000
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/virtual/scalefactor200withzoom/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.11/virtual/scalefactor150/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.11/virtual/scalefactor150/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
deleted file mode 100644
index a34a245..0000000
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.11/virtual/scalefactor150/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.11/virtual/scalefactor200withzoom/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.11/virtual/scalefactor200withzoom/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
deleted file mode 100644
index 818104f8..0000000
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.11/virtual/scalefactor200withzoom/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/scalefactor150/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/scalefactor150/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
new file mode 100644
index 0000000..3c308d6
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/scalefactor150/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/scalefactor200withzoom/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/scalefactor200withzoom/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
new file mode 100644
index 0000000..a29dedd3
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/scalefactor200withzoom/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/virtual/scalefactor150/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png b/third_party/WebKit/LayoutTests/platform/mac-retina/virtual/scalefactor150/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
deleted file mode 100644
index 8f1bb8c7..0000000
--- a/third_party/WebKit/LayoutTests/platform/mac-retina/virtual/scalefactor150/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/webaudio/DynamicsCompressor/dynamicscompressor-clear-internal-state-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-retina/webaudio/DynamicsCompressor/dynamicscompressor-clear-internal-state-expected.txt
new file mode 100644
index 0000000..7ba628d
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac-retina/webaudio/DynamicsCompressor/dynamicscompressor-clear-internal-state-expected.txt
@@ -0,0 +1,8 @@
+This is a testharness.js-based test.
+PASS # AUDIT TASK RUNNER STARTED.
+PASS > [test] Validate Reduction Value of DynamicsCompressor after Disabling
+FAIL X Math.abs(compressor.reduction) is not less than or equal to 0.048223. Got 5.246633529663086. assert_true: expected true got false
+FAIL < [test] 1 out of 1 assertions were failed. assert_true: expected true got false
+FAIL # AUDIT TASK RUNNER FINISHED: 1 out of 1 tasks were failed. assert_true: expected true got false
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/Source/bindings/core/v8/V8EmbedderGraphBuilder.cpp b/third_party/WebKit/Source/bindings/core/v8/V8EmbedderGraphBuilder.cpp
index 091f93be..12d692f5 100644
--- a/third_party/WebKit/Source/bindings/core/v8/V8EmbedderGraphBuilder.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/V8EmbedderGraphBuilder.cpp
@@ -5,7 +5,9 @@
 #include "bindings/core/v8/V8EmbedderGraphBuilder.h"
 
 #include "bindings/core/v8/ActiveScriptWrappable.h"
+#include "bindings/core/v8/V8GCController.h"
 #include "bindings/core/v8/V8Node.h"
+#include "core/dom/Document.h"
 #include "platform/bindings/DOMWrapperMap.h"
 #include "platform/bindings/ScriptWrappable.h"
 #include "platform/bindings/ScriptWrappableVisitor.h"
@@ -26,8 +28,70 @@
 
 void V8EmbedderGraphBuilder::BuildEmbedderGraph() {
   isolate_->VisitHandlesWithClassIds(this);
-  VisitPendingActivities();
+// At this point we collected ScriptWrappables in three groups:
+// attached, detached, and unknown.
+#if DCHECK_IS_ON()
+  for (const WorklistItem& item : worklist_) {
+    DCHECK_EQ(DomTreeState::kAttached, item.node->GetDomTreeState());
+  }
+  for (const WorklistItem& item : detached_worklist_) {
+    DCHECK_EQ(DomTreeState::kDetached, item.node->GetDomTreeState());
+  }
+  for (const WorklistItem& item : unknown_worklist_) {
+    DCHECK_EQ(DomTreeState::kUnknown, item.node->GetDomTreeState());
+  }
+#endif
+  // We need to propagate attached/detached information to ScriptWrappables
+  // with the unknown state. The information propagates from a parent to
+  // a child as follows:
+  // - if the parent is attached, then the child is considered attached.
+  // - if the parent is detached and the child is unknown, then the child is
+  //   considered detached.
+  // - if the parent is unknown, then the state of the child does not change.
+  //
+  // We need to organize DOM traversal in three stages to ensure correct
+  // propagation:
+  // 1) Traverse from the attached nodes. All nodes discovered in this stage
+  //    will be marked as kAttached.
+  // 2) Traverse from the detached nodes. All nodes discovered in this stage
+  //    will be marked as kDetached if they are not already marked as kAttached.
+  // 3) Traverse from the unknown nodes. This is needed only for edge recording.
+  // Stage 1: find transitive closure of the attached nodes.
   VisitTransitiveClosure();
+  // Stage 2: find transitive closure of the detached nodes.
+  while (!detached_worklist_.empty()) {
+    auto item = detached_worklist_.back();
+    detached_worklist_.pop_back();
+    PushToWorklist(item);
+  }
+  VisitTransitiveClosure();
+  // Stage 3: find transitive closure of the unknown nodes.
+  // Nodes reachable only via pending activities are treated as unknown.
+  VisitPendingActivities();
+  while (!unknown_worklist_.empty()) {
+    auto item = unknown_worklist_.back();
+    unknown_worklist_.pop_back();
+    PushToWorklist(item);
+  }
+  VisitTransitiveClosure();
+  DCHECK(worklist_.empty());
+  DCHECK(detached_worklist_.empty());
+  DCHECK(unknown_worklist_.empty());
+}
+
+V8EmbedderGraphBuilder::DomTreeState
+V8EmbedderGraphBuilder::DomTreeStateFromWrapper(
+    uint16_t class_id,
+    v8::Local<v8::Object> v8_value) {
+  if (class_id != WrapperTypeInfo::kNodeClassId)
+    return DomTreeState::kUnknown;
+  Node* node = V8Node::ToImpl(v8_value);
+  Node* root = V8GCController::OpaqueRootForGC(isolate_, node);
+  if (root->isConnected() &&
+      !node->GetDocument().MasterDocument().IsContextDestroyed()) {
+    return DomTreeState::kAttached;
+  }
+  return DomTreeState::kDetached;
 }
 
 void V8EmbedderGraphBuilder::VisitPersistentHandle(
@@ -39,13 +103,25 @@
   v8::Local<v8::Object> v8_value = v8::Local<v8::Object>::New(
       isolate_, v8::Persistent<v8::Object>::Cast(*value));
   ScriptWrappable* traceable = ToScriptWrappable(v8_value);
-  if (traceable) {
-    Graph::Node* wrapper = GraphNode(v8_value);
-    Graph::Node* graph_node =
-        GraphNode(traceable, traceable->NameInHeapSnapshot(), wrapper);
-    // Visit traceable members. This will also add traceable => v8_value edge.
-    ParentScope parent(this, graph_node);
-    traceable->TraceWrappers(this);
+  if (!traceable)
+    return;
+  Graph::Node* wrapper = GraphNode(v8_value);
+  DomTreeState dom_tree_state = DomTreeStateFromWrapper(class_id, v8_value);
+  EmbedderNode* graph_node = GraphNode(
+      traceable, traceable->NameInHeapSnapshot(), wrapper, dom_tree_state);
+  const TraceWrapperDescriptor& wrapper_descriptor =
+      WrapperDescriptorFor<ScriptWrappable>(traceable);
+  WorklistItem item = ToWorklistItem(graph_node, wrapper_descriptor);
+  switch (graph_node->GetDomTreeState()) {
+    case DomTreeState::kAttached:
+      PushToWorklist(item);
+      break;
+    case DomTreeState::kDetached:
+      detached_worklist_.push_back(item);
+      break;
+    case DomTreeState::kUnknown:
+      unknown_worklist_.push_back(item);
+      break;
   }
 }
 
@@ -64,13 +140,11 @@
   // Add an edge from the current parent to this object.
   // Also push the object to the worklist in order to process its members.
   const void* traceable = wrapper_descriptor.base_object_payload;
-  Graph::Node* graph_node = GraphNode(
-      traceable, wrapper_descriptor.name_callback(traceable), nullptr);
+  EmbedderNode* graph_node =
+      GraphNode(traceable, wrapper_descriptor.name_callback(traceable), nullptr,
+                current_parent_->GetDomTreeState());
   graph_->AddEdge(current_parent_, graph_node);
-  if (!visited_.Contains(traceable)) {
-    visited_.insert(traceable);
-    worklist_.push_back(ToWorklistItem(graph_node, wrapper_descriptor));
-  }
+  PushToWorklist(ToWorklistItem(graph_node, wrapper_descriptor));
 }
 
 void V8EmbedderGraphBuilder::Visit(DOMWrapperMap<ScriptWrappable>* wrapper_map,
@@ -87,36 +161,48 @@
   return graph_->V8Node(value);
 }
 
-v8::EmbedderGraph::Node* V8EmbedderGraphBuilder::GraphNode(
+V8EmbedderGraphBuilder::EmbedderNode* V8EmbedderGraphBuilder::GraphNode(
     Traceable traceable,
     const char* name,
-    v8::EmbedderGraph::Node* wrapper) const {
+    v8::EmbedderGraph::Node* wrapper,
+    DomTreeState dom_tree_state) const {
   auto iter = graph_node_.find(traceable);
-  if (iter != graph_node_.end())
+  if (iter != graph_node_.end()) {
+    iter->value->UpdateDomTreeState(dom_tree_state);
     return iter->value;
+  }
   // Ownership of the new node is transferred to the graph_.
   // graph_node_.at(tracable) is valid for all BuildEmbedderGraph execution.
-  auto node = graph_->AddNode(
-      std::unique_ptr<Graph::Node>(new EmbedderNode(name, wrapper)));
+  auto raw_node = new EmbedderNode(name, wrapper, dom_tree_state);
+  EmbedderNode* node = static_cast<EmbedderNode*>(
+      graph_->AddNode(std::unique_ptr<Graph::Node>(raw_node)));
   graph_node_.insert(traceable, node);
   return node;
 }
 
 void V8EmbedderGraphBuilder::VisitPendingActivities() {
   // Ownership of the new node is transferred to the graph_.
-  Graph::Node* root = graph_->AddNode(
-      std::unique_ptr<Graph::Node>(new EmbedderRootNode("Pending activities")));
+  EmbedderNode* root =
+      static_cast<EmbedderNode*>(graph_->AddNode(std::unique_ptr<Graph::Node>(
+          new EmbedderRootNode("Pending activities"))));
   ParentScope parent(this, root);
   ActiveScriptWrappableBase::TraceActiveScriptWrappables(isolate_, this);
 }
 
 V8EmbedderGraphBuilder::WorklistItem V8EmbedderGraphBuilder::ToWorklistItem(
-    Graph::Node* node,
+    EmbedderNode* node,
     const TraceWrapperDescriptor& wrapper_descriptor) const {
   return {node, wrapper_descriptor.base_object_payload,
           wrapper_descriptor.trace_wrappers_callback};
 }
 
+void V8EmbedderGraphBuilder::PushToWorklist(WorklistItem item) const {
+  if (!visited_.Contains(item.traceable)) {
+    visited_.insert(item.traceable);
+    worklist_.push_back(item);
+  }
+}
+
 void V8EmbedderGraphBuilder::VisitTransitiveClosure() {
   // Depth-first search.
   while (!worklist_.empty()) {
diff --git a/third_party/WebKit/Source/bindings/core/v8/V8EmbedderGraphBuilder.h b/third_party/WebKit/Source/bindings/core/v8/V8EmbedderGraphBuilder.h
index f3ce7f54..eacc9a1 100644
--- a/third_party/WebKit/Source/bindings/core/v8/V8EmbedderGraphBuilder.h
+++ b/third_party/WebKit/Source/bindings/core/v8/V8EmbedderGraphBuilder.h
@@ -34,24 +34,60 @@
              const ScriptWrappable*) const final;
 
  private:
+  // Information about whether a node is attached to the main DOM tree
+  // or not. It is computed as follows:
+  // 1) A Document with IsContextDestroyed() = true is detached.
+  // 2) A Document with IsContextDestroyed() = false is attached.
+  // 3) A Node that is not connected to any Document is detached.
+  // 4) A Node that is connected to a detached Document is detached.
+  // 5) A Node that is connected to an attached Document is attached.
+  // 6) A ScriptWrappable that is reachable from an attached Node is
+  //    attached.
+  // 7) A ScriptWrappable that is reachable from a detached Node is
+  //    detached.
+  // 8) A ScriptWrappable that is not reachable from any Node is
+  //    considered (conservatively) as attached.
+  // The unknown state applies to ScriptWrappables during graph
+  // traversal when we don't have reachability information yet.
+  enum class DomTreeState { kAttached, kDetached, kUnknown };
+
+  DomTreeState DomTreeStateFromWrapper(uint16_t class_id,
+                                       v8::Local<v8::Object> v8_value);
+
   class EmbedderNode : public Graph::Node {
    public:
-    EmbedderNode(const char* name, Graph::Node* wrapper)
-        : name_(name), wrapper_(wrapper) {}
+    EmbedderNode(const char* name,
+                 Graph::Node* wrapper,
+                 DomTreeState dom_tree_state)
+        : name_(name), wrapper_(wrapper), dom_tree_state_(dom_tree_state) {}
 
+    DomTreeState GetDomTreeState() { return dom_tree_state_; }
+    void UpdateDomTreeState(DomTreeState parent_dom_tree_state) {
+      // If the child's state is unknown, then take the parent's state.
+      // If the parent is attached, then the child is also attached.
+      if (dom_tree_state_ == DomTreeState::kUnknown ||
+          parent_dom_tree_state == DomTreeState::kAttached) {
+        dom_tree_state_ = parent_dom_tree_state;
+      }
+    }
     // Graph::Node overrides.
     const char* Name() override { return name_; }
+    const char* NamePrefix() override {
+      return dom_tree_state_ == DomTreeState::kDetached ? "Detached" : nullptr;
+    }
     size_t SizeInBytes() override { return 0; }
     Graph::Node* WrapperNode() override { return wrapper_; }
 
    private:
     const char* name_;
     Graph::Node* wrapper_;
+    DomTreeState dom_tree_state_;
   };
 
   class EmbedderRootNode : public EmbedderNode {
    public:
-    explicit EmbedderRootNode(const char* name) : EmbedderNode(name, nullptr) {}
+    explicit EmbedderRootNode(const char* name)
+        : EmbedderNode(name, nullptr, DomTreeState::kUnknown) {}
     // Graph::Node override.
     bool IsRootNode() { return true; }
   };
@@ -60,7 +96,7 @@
     STACK_ALLOCATED();
 
    public:
-    ParentScope(V8EmbedderGraphBuilder* visitor, Graph::Node* parent)
+    ParentScope(V8EmbedderGraphBuilder* visitor, EmbedderNode* parent)
         : visitor_(visitor) {
       DCHECK_EQ(visitor->current_parent_, nullptr);
       visitor->current_parent_ = parent;
@@ -72,28 +108,40 @@
   };
 
   struct WorklistItem {
-    Graph::Node* node;
+    EmbedderNode* node;
     Traceable traceable;
     TraceWrappersCallback trace_wrappers_callback;
   };
 
-  WorklistItem ToWorklistItem(Graph::Node*,
+  WorklistItem ToWorklistItem(EmbedderNode*,
                               const TraceWrapperDescriptor&) const;
 
   Graph::Node* GraphNode(const v8::Local<v8::Value>&) const;
-  Graph::Node* GraphNode(Traceable,
-                         const char* name,
-                         Graph::Node* wrapper) const;
+  EmbedderNode* GraphNode(Traceable,
+                          const char* name,
+                          Graph::Node* wrapper,
+                          DomTreeState) const;
 
   void VisitPendingActivities();
   void VisitTransitiveClosure();
 
+  // Push the item to the default worklist if item.traceable was not
+  // already visited.
+  void PushToWorklist(WorklistItem) const;
+
   v8::Isolate* isolate_;
-  Graph::Node* current_parent_;
+  EmbedderNode* current_parent_;
   mutable Graph* graph_;
   mutable HashSet<Traceable> visited_;
-  mutable HashMap<Traceable, Graph::Node*> graph_node_;
+  mutable HashMap<Traceable, EmbedderNode*> graph_node_;
+  // The default worklist that is used to visit transitive closure.
   mutable Deque<WorklistItem> worklist_;
+  // The worklist that collects detached Nodes during persistent handle
+  // iteration.
+  mutable Deque<WorklistItem> detached_worklist_;
+  // The worklist that collects ScriptWrappables with unknown information
+  // about attached/detached state during persistent handle iteration.
+  mutable Deque<WorklistItem> unknown_worklist_;
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/dom/Document.cpp b/third_party/WebKit/Source/core/dom/Document.cpp
index e5d77fd3..ba77372 100644
--- a/third_party/WebKit/Source/core/dom/Document.cpp
+++ b/third_party/WebKit/Source/core/dom/Document.cpp
@@ -7327,6 +7327,7 @@
   // node_lists_ are traced in their corresponding NodeListsNodeData, keeping
   // them only alive for live nodes. Otherwise we would keep lists of dead
   // nodes alive that have not yet been invalidated.
+  visitor->TraceWrappers(dom_window_);
   visitor->TraceWrappers(imports_controller_);
   visitor->TraceWrappers(parser_);
   visitor->TraceWrappers(implementation_);
diff --git a/third_party/WebKit/Source/core/dom/Document.h b/third_party/WebKit/Source/core/dom/Document.h
index f192aa9..26c27bc 100644
--- a/third_party/WebKit/Source/core/dom/Document.h
+++ b/third_party/WebKit/Source/core/dom/Document.h
@@ -1566,7 +1566,7 @@
   PendingSheetLayout pending_sheet_layout_;
 
   Member<LocalFrame> frame_;
-  Member<LocalDOMWindow> dom_window_;
+  TraceWrapperMember<LocalDOMWindow> dom_window_;
   TraceWrapperMember<HTMLImportsController> imports_controller_;
 
   // The document of creator browsing context for frame-less documents such as
diff --git a/third_party/WebKit/Source/core/editing/RenderedPosition.cpp b/third_party/WebKit/Source/core/editing/RenderedPosition.cpp
index 98cf6da..35a8a66 100644
--- a/third_party/WebKit/Source/core/editing/RenderedPosition.cpp
+++ b/third_party/WebKit/Source/core/editing/RenderedPosition.cpp
@@ -248,8 +248,21 @@
       PrevLeafChild()->CaretRightmostOffset());
 }
 
+// Note: If the layout object has a scrolling contents layer, the selection
+// will be relative to that.
+static GraphicsLayer* GetGraphicsLayerBacking(
+    const LayoutObject& layout_object) {
+  const LayoutBoxModelObject& paint_invalidation_container =
+      layout_object.ContainerForPaintInvalidation();
+  DCHECK(paint_invalidation_container.Layer());
+  if (paint_invalidation_container.Layer()->GetCompositingState() ==
+      kNotComposited)
+    return nullptr;
+  return paint_invalidation_container.Layer()->GraphicsLayerBacking(
+      &layout_object);
+}
+
 // Convert a local point into the coordinate system of backing coordinates.
-// Also returns the backing layer if needed.
 static FloatPoint LocalToInvalidationBackingPoint(
     const LayoutPoint& local_point,
     const LayoutObject& layout_object) {
@@ -270,26 +283,18 @@
   PaintLayer::MapPointInPaintInvalidationContainerToBacking(
       paint_invalidation_container, container_point);
 
-  // Must not use the scrolling contents layer, so pass
-  // |paintInvalidationContainer|.
-  if (GraphicsLayer* graphics_layer =
-          paint_invalidation_container.Layer()->GraphicsLayerBacking(
-              &paint_invalidation_container))
+  if (GraphicsLayer* graphics_layer = GetGraphicsLayerBacking(layout_object))
     container_point.Move(-graphics_layer->OffsetFromLayoutObject());
 
-  return container_point;
-}
+  // Ensure the coordinates are in the scrolling contents space, if the object
+  // is a scroller.
+  if (paint_invalidation_container.UsesCompositedScrolling()) {
+    container_point.Move(paint_invalidation_container.Layer()
+                             ->GetScrollableArea()
+                             ->GetScrollOffset());
+  }
 
-static GraphicsLayer* GetGraphicsLayerBacking(
-    const LayoutObject& layout_object) {
-  const LayoutBoxModelObject& paint_invalidation_container =
-      layout_object.ContainerForPaintInvalidation();
-  DCHECK(paint_invalidation_container.Layer());
-  if (paint_invalidation_container.Layer()->GetCompositingState() ==
-      kNotComposited)
-    return nullptr;
-  return paint_invalidation_container.Layer()->GraphicsLayerBacking(
-      &paint_invalidation_container);
+  return container_point;
 }
 
 std::pair<LayoutPoint, LayoutPoint> static GetLocalSelectionStartpoints(
diff --git a/third_party/WebKit/Source/core/editing/RenderedPositionTest.cpp b/third_party/WebKit/Source/core/editing/RenderedPositionTest.cpp
index af07c01..e0137935 100644
--- a/third_party/WebKit/Source/core/editing/RenderedPositionTest.cpp
+++ b/third_party/WebKit/Source/core/editing/RenderedPositionTest.cpp
@@ -10,37 +10,55 @@
 #include "core/editing/testing/EditingTestBase.h"
 #include "core/frame/Settings.h"
 #include "core/html/forms/HTMLInputElement.h"
+#include "core/layout/LayoutBox.h"
+#include "core/paint/PaintLayerScrollableArea.h"
 #include "core/paint/compositing/CompositedSelection.h"
+#include "platform/testing/runtime_enabled_features_test_helpers.h"
 
 namespace blink {
 
-class RenderedPositionTest : public EditingTestBase {};
+class RenderedPositionTest : public ::testing::WithParamInterface<bool>,
+                             private ScopedRootLayerScrollingForTest,
+                             public EditingTestBase {
+ public:
+  RenderedPositionTest() : ScopedRootLayerScrollingForTest(GetParam()) {}
+  void SetUp() override {
+    EditingTestBase::SetUp();
+    GetPage().GetSettings().SetAcceleratedCompositingEnabled(true);
+    GetDocument().View()->SetParentVisible(true);
+    GetDocument().View()->SetSelfVisible(true);
+    LoadAhem();
+  }
 
-#if defined(OS_ANDROID)
-#define MAYBE_ComputeCompositedSelection DISABLED_ComputeCompositedSelection
-#else
-#define MAYBE_ComputeCompositedSelection ComputeCompositedSelection
-#endif
-TEST_F(RenderedPositionTest, MAYBE_ComputeCompositedSelection) {
-  // Enable compositing.
-  GetPage().GetSettings().SetAcceleratedCompositingEnabled(true);
-  GetDocument().View()->SetParentVisible(true);
-  GetDocument().View()->SetSelfVisible(true);
-  GetDocument().View()->UpdateAllLifecyclePhases();
+  void FocusAndSelectAll() {
+    HTMLInputElement* target =
+        ToHTMLInputElement(GetDocument().getElementById("target"));
+    DCHECK(target);
+    target->focus();
+    Selection().SetSelection(
+        SelectionInDOMTree::Builder()
+            .SelectAllChildren(*target->InnerEditorElement())
+            .Build(),
+        SetSelectionOptions::Builder().SetShouldShowHandle(true).Build());
+    UpdateAllLifecyclePhases();
+  }
+};
 
-  SetBodyContent(
-      "<input id=target width=20 value='test test test test test tes tes test'"
-      "style='width: 100px; height: 20px;'>");
-  HTMLInputElement* target =
-      ToHTMLInputElement(GetDocument().getElementById("target"));
-  DCHECK(target);
-  target->focus();
-  Selection().SetSelection(
-      SelectionInDOMTree::Builder()
-          .SelectAllChildren(*target->InnerEditorElement())
-          .Build(),
-      SetSelectionOptions::Builder().SetShouldShowHandle(true).Build());
-  UpdateAllLifecyclePhases();
+INSTANTIATE_TEST_CASE_P(All, RenderedPositionTest, ::testing::Bool());
+
+TEST_P(RenderedPositionTest, ComputeCompositedSelection) {
+  SetBodyContent(R"HTML(
+      <!DOCTYPE html>
+      input {
+        font: 10px/1 Ahem;
+        padding: 0;
+        border: 0;
+      }
+      <input id=target width=20 value='test test test test test tes tes test'
+      style='width: 100px; height: 20px;'>
+  )HTML");
+
+  FocusAndSelectAll();
 
   const CompositedSelection& composited_selection =
       RenderedPosition::ComputeCompositedSelection(Selection());
@@ -48,4 +66,115 @@
   EXPECT_TRUE(composited_selection.end.hidden);
 }
 
+TEST_P(RenderedPositionTest, PositionInScrollableRoot) {
+  SetBodyContent(R"HTML(
+      <!DOCTYPE html>
+      <style>
+        body {
+           margin: 0;
+           height: 2000px;
+           width: 2000px;
+        }
+        input {
+          font: 10px/1 Ahem;
+          padding: 0;
+          border: 0;
+          width: 100px;
+          height: 20px;
+          position: absolute;
+          top: 900px;
+          left: 1000px;
+        }
+      </style>
+      <input id=target width=20 value='test test test test test tes tes test'>
+  )HTML");
+
+  FocusAndSelectAll();
+
+  ScrollableArea* root_scroller = GetDocument().View()->GetScrollableArea();
+  root_scroller->SetScrollOffset(ScrollOffset(800, 500), kProgrammaticScroll);
+  ASSERT_EQ(ScrollOffset(800, 500), root_scroller->GetScrollOffset());
+
+  UpdateAllLifecyclePhases();
+
+  const CompositedSelection& composited_selection =
+      RenderedPosition::ComputeCompositedSelection(Selection());
+
+  // Top-left corner should be around (1000, 905) - 10px centered in 20px
+  // height.
+  EXPECT_EQ(FloatPoint(1000, 905),
+            composited_selection.start.edge_top_in_layer);
+  EXPECT_EQ(FloatPoint(1000, 915),
+            composited_selection.start.edge_bottom_in_layer);
+  EXPECT_EQ(FloatPoint(1369, 905), composited_selection.end.edge_top_in_layer);
+  EXPECT_EQ(FloatPoint(1369, 915),
+            composited_selection.end.edge_bottom_in_layer);
+}
+
+TEST_P(RenderedPositionTest, PositionInScroller) {
+  SetBodyContent(R"HTML(
+      <!DOCTYPE html>
+      <style>
+        body {
+           margin: 0;
+           height: 2000px;
+           width: 2000px;
+        }
+        input {
+          font: 10px/1 Ahem;
+          padding: 0;
+          border: 0;
+          width: 100px;
+          height: 20px;
+          position: absolute;
+          top: 900px;
+          left: 1000px;
+        }
+
+        #scroller {
+          width: 300px;
+          height: 300px;
+          position: absolute;
+          left: 300px;
+          top: 400px;
+          overflow: scroll;
+          border: 200px;
+          will-change: transform;
+        }
+
+        #space {
+          width: 2000px;
+          height: 2000px;
+        }
+      </style>
+      <div id="scroller">
+        <div id="space"></div>
+        <input id=target width=20 value='test test test test test tes tes test'>
+      </div>
+  )HTML");
+
+  FocusAndSelectAll();
+
+  Element* e = GetDocument().getElementById("scroller");
+  PaintLayerScrollableArea* scroller =
+      ToLayoutBox(e->GetLayoutObject())->GetScrollableArea();
+  scroller->SetScrollOffset(ScrollOffset(900, 800), kProgrammaticScroll);
+  ASSERT_EQ(ScrollOffset(900, 800), scroller->GetScrollOffset());
+
+  UpdateAllLifecyclePhases();
+
+  const CompositedSelection& composited_selection =
+      RenderedPosition::ComputeCompositedSelection(Selection());
+
+  // Top-left corner should be around (1000, 905) - 10px centered in 20px
+  // height.
+  EXPECT_EQ(FloatPoint(1000, 905),
+            composited_selection.start.edge_top_in_layer);
+  EXPECT_EQ(FloatPoint(1000, 915),
+            composited_selection.start.edge_bottom_in_layer);
+  EXPECT_EQ(FloatPoint(1369, 905), composited_selection.end.edge_top_in_layer);
+  EXPECT_EQ(FloatPoint(1369, 915),
+            composited_selection.end.edge_bottom_in_layer);
+}
+
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/exported/WebFrameTest.cpp b/third_party/WebKit/Source/core/exported/WebFrameTest.cpp
index 0aa806a..d232638 100644
--- a/third_party/WebKit/Source/core/exported/WebFrameTest.cpp
+++ b/third_party/WebKit/Source/core/exported/WebFrameTest.cpp
@@ -6332,11 +6332,7 @@
     blink::Node* layer_owner_node_for_start = V8Node::ToImplWithTypeCheck(
         v8::Isolate::GetCurrent(), expected_result.Get(0));
     ASSERT_TRUE(layer_owner_node_for_start);
-    EXPECT_EQ(layer_owner_node_for_start->GetLayoutObject()
-                  ->EnclosingLayer()
-                  ->EnclosingLayerForPaintInvalidation()
-                  ->GetCompositedLayerMapping()
-                  ->MainGraphicsLayer()
+    EXPECT_EQ(GetExpectedLayerForSelection(layer_owner_node_for_start)
                   ->PlatformLayer()
                   ->Id(),
               select_start->layer_id);
@@ -6351,11 +6347,7 @@
         expected_result.Get(context, 5).ToLocalChecked());
 
     ASSERT_TRUE(layer_owner_node_for_end);
-    EXPECT_EQ(layer_owner_node_for_end->GetLayoutObject()
-                  ->EnclosingLayer()
-                  ->EnclosingLayerForPaintInvalidation()
-                  ->GetCompositedLayerMapping()
-                  ->MainGraphicsLayer()
+    EXPECT_EQ(GetExpectedLayerForSelection(layer_owner_node_for_end)
                   ->PlatformLayer()
                   ->Id(),
               select_end->layer_id);
@@ -6407,6 +6399,18 @@
     RunTest(test_file);
   }
 
+  GraphicsLayer* GetExpectedLayerForSelection(blink::Node* node) const {
+    CompositedLayerMapping* clm = node->GetLayoutObject()
+                                      ->EnclosingLayer()
+                                      ->EnclosingLayerForPaintInvalidation()
+                                      ->GetCompositedLayerMapping();
+
+    // If the Node is a scroller, the selection will be relative to its
+    // scrolling contents layer.
+    return clm->ScrollingContentsLayer() ? clm->ScrollingContentsLayer()
+                                         : clm->MainGraphicsLayer();
+  }
+
   CompositedSelectionBoundsTestWebViewClient fake_selection_web_view_client_;
   CompositedSelectionBoundsTestLayerTreeView& fake_selection_layer_tree_view_;
   FrameTestHelpers::WebViewHelper web_view_helper_;
diff --git a/third_party/WebKit/Source/platform/OWNERS b/third_party/WebKit/Source/platform/OWNERS
index 513ee139..d0f18a4 100644
--- a/third_party/WebKit/Source/platform/OWNERS
+++ b/third_party/WebKit/Source/platform/OWNERS
@@ -21,8 +21,10 @@
 vollick@chromium.org
 wangxianzhu@chromium.org
 
-# In addition to the above, API_OWNERS are also adequate reviewers
-# for adding / changing the status of a feature.
+# Any API or core owner can also approve changes to runtime-enabled features.
+# Please make sure to get a review from someone with expertise on the feature
+# you are changing.
 per-file runtime_enabled_features.json5=file://third_party/WebKit/API_OWNERS
+per-file runtime_enabled_features.json5=file://third_party/WebKit/Source/core/OWNERS
 
 # COMPONENT: Platform
diff --git a/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzShaper.cpp b/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzShaper.cpp
index 23630e9..1d81c18 100644
--- a/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzShaper.cpp
+++ b/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzShaper.cpp
@@ -835,6 +835,13 @@
       if (caps_support.NeedsRunCaseSplitting()) {
         SplitUntilNextCaseChange(text_, &range_data->reshape_queue,
                                  current_queue_item, small_caps_behavior);
+        // Skip queue items generated by SplitUntilNextCaseChange that do not
+        // contribute to the shape result if the range_data restricts shaping to
+        // a substring.
+        if (range_data->start >= current_queue_item.start_index_ +
+                                     current_queue_item.num_characters_ ||
+            range_data->end <= current_queue_item.start_index_)
+          continue;
       }
     }
 
@@ -856,6 +863,7 @@
     unsigned shape_end =
         std::min(range_data->end, current_queue_item.start_index_ +
                                       current_queue_item.num_characters_);
+    DCHECK_GT(shape_end, shape_start);
 
     CaseMappingHarfBuzzBufferFiller(
         case_map_intend, font_description.LocaleOrDefault(), range_data->buffer,
diff --git a/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzShaperTest.cpp b/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzShaperTest.cpp
index 36c247a..d8173dd 100644
--- a/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzShaperTest.cpp
+++ b/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzShaperTest.cpp
@@ -391,6 +391,47 @@
   EXPECT_EQ(result->Bounds(), composite_result->Bounds());
 }
 
+TEST_F(HarfBuzzShaperTest, RangeShapeSmallCaps) {
+  // Test passes if no assertion is hit of the ones below, but also the newly
+  // introduced one in HarfBuzzShaper::ShapeSegment: DCHECK_GT(shape_end,
+  // shape_start) is not hit.
+  FontDescription font_description;
+  font_description.SetVariantCaps(FontDescription::kSmallCaps);
+  font_description.SetComputedSize(12.0);
+  Font font(font_description);
+  font.Update(nullptr);
+
+  // Shaping index 2 to 3 means that case splitting for small caps splits before
+  // character index 2 since the initial 'a' needs to be uppercased, but the
+  // space character does not need to be uppercased. This triggered
+  // crbug.com/817271.
+  String string(u"a aa");
+  HarfBuzzShaper shaper(string.Characters16(), string.length());
+  scoped_refptr<ShapeResult> result =
+      shaper.Shape(&font, TextDirection::kLtr, 2, 3);
+  EXPECT_EQ(1u, result->NumCharacters());
+
+  string = u"aa a";
+  HarfBuzzShaper shaper_two(string.Characters16(), string.length());
+  result = shaper_two.Shape(&font, TextDirection::kLtr, 3, 4);
+  EXPECT_EQ(1u, result->NumCharacters());
+
+  string = u"a aa";
+  HarfBuzzShaper shaper_three(string.Characters16(), string.length());
+  result = shaper_three.Shape(&font, TextDirection::kLtr, 1, 2);
+  EXPECT_EQ(1u, result->NumCharacters());
+
+  string = u"aa aa aa aa aa aa aa aa aa aa";
+  HarfBuzzShaper shaper_four(string.Characters16(), string.length());
+  result = shaper_four.Shape(&font, TextDirection::kLtr, 21, 23);
+  EXPECT_EQ(2u, result->NumCharacters());
+
+  string = u"aa aa aa aa aa aa aa aa aa aa";
+  HarfBuzzShaper shaper_five(string.Characters16(), string.length());
+  result = shaper_five.Shape(&font, TextDirection::kLtr, 27, 29);
+  EXPECT_EQ(2u, result->NumCharacters());
+}
+
 TEST_F(HarfBuzzShaperTest, ShapeVerticalMixed) {
   font_description.SetOrientation(FontOrientation::kVerticalMixed);
   font = Font(font_description);
@@ -483,7 +524,7 @@
   // Because all characters are at 0, the glyph bounds must be the char_width.
   // Allow being larger because accurate width requires re-measuring each glyph.
   EXPECT_GE(result->Bounds().MaxX(), char_width);
-  EXPECT_LE(result->Bounds().MaxX(), char_width * 1.1);
+  EXPECT_LE(result->Bounds().MaxX(), char_width * 1.2);
 }
 
 TEST_F(HarfBuzzShaperTest, NegativeLetterSpacingToNegative) {
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/common/net/git_cl.py b/third_party/WebKit/Tools/Scripts/webkitpy/common/net/git_cl.py
index 822343d..ae4c4109 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/common/net/git_cl.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/common/net/git_cl.py
@@ -196,7 +196,7 @@
             if is_swarming_task and not include_swarming_tasks:
                 continue
             is_cq = 'user_agent:cq' in result.get('tags', [])
-            is_experimental = result.get('experimental')
+            is_experimental = 'cq_experimental:true' in result.get('tags', [])
             if cq_only and not (is_cq and not is_experimental):
                 continue
             build_to_status[self._build(result)] = self._try_job_status(result)
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/common/net/git_cl_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/common/net/git_cl_unittest.py
index 1879d21..9b4ce350 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/common/net/git_cl_unittest.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/common/net/git_cl_unittest.py
@@ -288,26 +288,60 @@
                 'url': None,
             },
             {
+                'builder_name': 'cq-b',
+                'experimental': False,
+                'result': None,
+                'status': 'SCHEDULED',
+                'tags': ['cq_experimental:false', 'user_agent:cq'],
+                'url': None,
+            },
+            {
+                'builder_name': 'cq-c',
+                'experimental': True,
+                'result': None,
+                'status': 'SCHEDULED',
+                'tags': ['cq_experimental:false', 'user_agent:cq'],
+                'url': None,
+            },
+            {
                 'builder_name': 'cq-a-experimental',
                 'experimental': True,
                 'result': None,
                 'status': 'SCHEDULED',
-                'tags': ['user_agent:cq'],
+                'tags': ['cq_experimental:true', 'user_agent:cq'],
                 'url': None,
             },
             {
-                'builder_name': 'other',
+                'builder_name': 'cq-b-experimental',
+                'experimental': False,
+                'result': None,
+                'status': 'SCHEDULED',
+                'tags': ['cq_experimental:true', 'user_agent:cq'],
+                'url': None,
+            },
+            {
+                'builder_name': 'other-a',
                 'experimental': False,
                 'status': 'SCHEDULED',
                 'result': None,
                 'tags': ['user_agent:git_cl_try'],
                 'url': None,
             },
+            {
+                'builder_name': 'other-b',
+                'experimental': False,
+                'status': 'SCHEDULED',
+                'result': None,
+                'tags': ['is_experimental:false', 'user_agent:git_cl_try'],
+                'url': None,
+            },
         ]
         self.assertEqual(
             git_cl.latest_try_jobs(cq_only=True),
             {
                 Build('cq-a'): TryJobStatus('SCHEDULED'),
+                Build('cq-b'): TryJobStatus('SCHEDULED'),
+                Build('cq-c'): TryJobStatus('SCHEDULED'),
             })
 
     def test_latest_try_jobs(self):
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/android.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/android.py
index e09d305..c7477fd 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/android.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/android.py
@@ -390,10 +390,10 @@
             # TODO(sergeyu): Rename these files, they can be used on platforms
             # other than Android.
             host_device_tuples.append(
-                (self._build_path('content_shell_test_fonts/android_main_fonts.xml'),
+                (self._build_path('test_fonts/android_main_fonts.xml'),
                  device_path('android_main_fonts.xml')))
             host_device_tuples.append(
-                (self._build_path('content_shell_test_fonts/android_fallback_fonts.xml'),
+                (self._build_path('test_fonts/android_fallback_fonts.xml'),
                  device_path('android_fallback_fonts.xml')))
             for font_file in self._get_font_files():
                 host_device_tuples.append(
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/base.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/base.py
index 509e384..5bf6360 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/base.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/base.py
@@ -69,7 +69,7 @@
 MS_TRUETYPE_FONTS_PACKAGE = 'ttf-mscorefonts-installer'
 
 # Path relative to the build directory.
-CONTENT_SHELL_FONTS_DIR = "content_shell_test_fonts"
+CONTENT_SHELL_FONTS_DIR = "test_fonts"
 
 FONT_FILES = [
     [[MS_TRUETYPE_FONTS_DIR], 'Arial.ttf', MS_TRUETYPE_FONTS_PACKAGE],
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/fuchsia.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/fuchsia.py
index d69a2296..727aba6 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/fuchsia.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/fuchsia.py
@@ -159,11 +159,11 @@
         self._target.RunCommand(['mkdir', '/system/fonts'])
 
         self._target.PutFile(
-            os.path.join(build_path, 'content_shell_test_fonts', 'android_main_fonts.xml'),
+            os.path.join(build_path, 'test_fonts', 'android_main_fonts.xml'),
             FONTS_DEVICE_PATH + '/fonts.xml')
 
         self._target.PutFile(
-            os.path.join(build_path, 'content_shell_test_fonts', 'android_fallback_fonts.xml'),
+            os.path.join(build_path, 'test_fonts', 'android_fallback_fonts.xml'),
             FONTS_DEVICE_PATH + '/fonts_fallback.xml')
 
         self._target.PutFiles(fonts, FONTS_DEVICE_PATH)
diff --git a/third_party/content_shell_fonts/.gitignore b/third_party/content_shell_fonts/.gitignore
deleted file mode 100644
index a871776..0000000
--- a/third_party/content_shell_fonts/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-content_shell_test_fonts/
-content_shell_test_fonts.tar.gz
diff --git a/third_party/content_shell_fonts/BUILD.gn b/third_party/content_shell_fonts/BUILD.gn
deleted file mode 100644
index a1ddd95b..0000000
--- a/third_party/content_shell_fonts/BUILD.gn
+++ /dev/null
@@ -1,21 +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.
-
-copy("content_shell_fonts") {
-  sources = [
-    "LICENSE",
-    "content_shell_test_fonts/DejaVuSans.ttf",
-    "content_shell_test_fonts/Garuda.ttf",
-    "content_shell_test_fonts/Lohit-Devanagari.ttf",
-    "content_shell_test_fonts/Lohit-Gurmukhi.ttf",
-    "content_shell_test_fonts/Lohit-Tamil.ttf",
-    "content_shell_test_fonts/MuktiNarrow.ttf",
-    "content_shell_test_fonts/NotoSansCJKjp-Regular.otf",
-    "content_shell_test_fonts/NotoSansKhmer-Regular.ttf",
-  ]
-
-  outputs = [
-    "${root_build_dir}/content_shell_test_fonts/{{source_file_part}}",
-  ]
-}
diff --git a/third_party/content_shell_fonts/OWNERS b/third_party/content_shell_fonts/OWNERS
deleted file mode 100644
index aa56044..0000000
--- a/third_party/content_shell_fonts/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-dpranke@chromium.org
-drott@chromium.org
diff --git a/third_party/content_shell_fonts/content_shell_test_fonts.tar.gz.sha1 b/third_party/content_shell_fonts/content_shell_test_fonts.tar.gz.sha1
deleted file mode 100644
index bd62a83..0000000
--- a/third_party/content_shell_fonts/content_shell_test_fonts.tar.gz.sha1
+++ /dev/null
@@ -1 +0,0 @@
-eea1fc91877797451ff7cff29e49a3e15e1d9ee1
\ No newline at end of file
diff --git a/third_party/fontconfig/fontconfig.gni b/third_party/fontconfig/fontconfig.gni
index 3ea4dd2a..0965f9fe 100644
--- a/third_party/fontconfig/fontconfig.gni
+++ b/third_party/fontconfig/fontconfig.gni
@@ -7,5 +7,5 @@
 assert(is_linux)
 
 declare_args() {
-  use_bundled_fontconfig = is_chromecast || is_desktop_linux
+  use_bundled_fontconfig = is_linux
 }
diff --git a/third_party/test_fonts/.gitignore b/third_party/test_fonts/.gitignore
new file mode 100644
index 0000000..53122f6
--- /dev/null
+++ b/third_party/test_fonts/.gitignore
@@ -0,0 +1,2 @@
+test_fonts/
+test_fonts.tar.gz
diff --git a/third_party/test_fonts/BUILD.gn b/third_party/test_fonts/BUILD.gn
new file mode 100644
index 0000000..8015ac5f
--- /dev/null
+++ b/third_party/test_fonts/BUILD.gn
@@ -0,0 +1,22 @@
+# 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.
+
+copy("test_fonts") {
+  sources = [
+    "LICENSE",
+    "test_fonts/DejaVuSans-Bold.ttf",
+    "test_fonts/DejaVuSans.ttf",
+    "test_fonts/Garuda.ttf",
+    "test_fonts/Lohit-Devanagari.ttf",
+    "test_fonts/Lohit-Gurmukhi.ttf",
+    "test_fonts/Lohit-Tamil.ttf",
+    "test_fonts/MuktiNarrow.ttf",
+    "test_fonts/NotoSansCJKjp-Regular.otf",
+    "test_fonts/NotoSansKhmer-Regular.ttf",
+  ]
+
+  outputs = [
+    "${root_build_dir}/test_fonts/{{source_file_part}}",
+  ]
+}
diff --git a/third_party/content_shell_fonts/LICENSE b/third_party/test_fonts/LICENSE
similarity index 99%
rename from third_party/content_shell_fonts/LICENSE
rename to third_party/test_fonts/LICENSE
index 9b24d45..9a11b1e19 100644
--- a/third_party/content_shell_fonts/LICENSE
+++ b/third_party/test_fonts/LICENSE
@@ -448,6 +448,7 @@
 
 --------------------------------------------------------------------------------
 The Vera Bitstream License applies to the following files:
+DejaVuSans-Bold.ttf
 DejaVuSans.ttf
 
 
diff --git a/third_party/test_fonts/OWNERS b/third_party/test_fonts/OWNERS
new file mode 100644
index 0000000..d300591
--- /dev/null
+++ b/third_party/test_fonts/OWNERS
@@ -0,0 +1,3 @@
+dpranke@chromium.org
+drott@chromium.org
+thomasanderson@chromium.org
diff --git a/third_party/content_shell_fonts/README.chromium b/third_party/test_fonts/README.chromium
similarity index 65%
rename from third_party/content_shell_fonts/README.chromium
rename to third_party/test_fonts/README.chromium
index efce03a..f1cc479 100644
--- a/third_party/content_shell_fonts/README.chromium
+++ b/third_party/test_fonts/README.chromium
@@ -1,11 +1,11 @@
-Name: content_shell_fonts
+Name: test_fonts
 URL: https://pagure.io/lohit, http://www.nongnu.org/freebangfont/downloads.html#mukti, https://dejavu-fonts.github.io/Download.html
 Version: unknown
 License: SIL OPEN FONT LICENSE, GPL v2, Bitstream Vera Fonts Copyright
 Security Critical: no
 
 Description:
-A collection of fonts in the content_shell_fonts directory distributed in a
+A collection of fonts in the test_fonts directory distributed in a
 cloud storage bucket in order to ease running layout test under multiple Linux
 distributions.
 
@@ -13,23 +13,22 @@
 
 1.  Download fonts from their source repositories, see "Font Origins" below,
     build them if necessary.
-2.  Copy the necessary files to ./content_shell_test_fonts
+2.  Copy the necessary files to ./test_fonts
 3.  Verify that the licenses are correctly referenced in LICENSE (See the
     section headers in the LICENSE file: When adding a new license, add a dashed
     line, list the new font files that it applies to, and copy and paste the
     additional license below.)
-4.  Update the `//third_party/content_shell_fonts/` BUILD.gn target to include
-    all the current fonts and their license files.
+4.  Update the `//third_party/test_fonts/` BUILD.gn target to include all the
+    current fonts and their license files.
 5.  Run the `upload_to_google_storage.py` (from depot_tools) script to upload
-    the files. You must do this in the //third_party/content_shell_fonts directory.
-    To do this, execute:
-     $ upload_to_google_storage.py --archive -b chromium-fonts content_shell_test_fonts
-6.  Add all the font_bundle.tar.gz.sha1 file to the chromium src repository,
-    by executing the following command:
-     $ git add ./third_party/content_shell_fonts/content_shell_test_fonts.tar.gz.sha1
-7.  (optional) Modify loaded kSystemFontsForFontconfig and
-    kCloudStorageSyncedFonts lists in fontconfig_util_linux.cc . Also update
-    FONT_FILES in third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/base.py .
+    the files. You must do this in the //third_party/test_fonts directory.  To
+    do this, execute:
+	$ upload_to_google_storage.py --archive -b chromium-fonts test_fonts
+6.  Add all the font_bundle.tar.gz.sha1 file to the chromium src repository, by
+    executing the following command:
+	$ git add ./third_party/test_fonts/test_fonts.tar.gz.sha1
+7.  (optional) Update FONT_FILES in
+    third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/base.py .
 
 If you need access to the chromium-fonts bucket, contact Chrome infra. For
 details, please refer to
diff --git a/third_party/test_fonts/test_fonts.tar.gz.sha1 b/third_party/test_fonts/test_fonts.tar.gz.sha1
new file mode 100644
index 0000000..ec364f4108
--- /dev/null
+++ b/third_party/test_fonts/test_fonts.tar.gz.sha1
@@ -0,0 +1 @@
+9c1ff266a05e3b8523de198f62dabb9a881ab28f
\ No newline at end of file
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl
index aa5dc7b3..7444f33 100644
--- a/tools/mb/mb_config.pyl
+++ b/tools/mb/mb_config.pyl
@@ -413,6 +413,8 @@
       'Battor Agent Linux': 'release_bot',
       'Battor Agent Mac': 'release_bot',
       'Battor Agent Win': 'release_bot',
+      'Mac Builder FYI': 'official_goma',
+      'Win Builder FYI': 'official_goma_x86',
     },
 
     'chromium.swarm': {
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 237ccbb..29b988a 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -44823,6 +44823,9 @@
 </enum>
 
 <enum name="VAVDAH264DecoderFailure">
+  <obsolete>
+    Deprecated as of 4/2015, partially replaced by VAVDADecoderFailure.
+  </obsolete>
   <int value="0" label="FRAME_MBS_ONLY_FLAG_NOT_ONE"/>
   <int value="1" label="GAPS_IN_FRAME_NUM"/>
   <int value="2" label="MID_STREAM_RESOLUTION_CHANGE"/>
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 27b67e9..4c0efb2e 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -2192,6 +2192,15 @@
   </summary>
 </histogram>
 
+<histogram name="Apps.AppListHide.InputLatency" units="ms">
+  <owner>wutao@chromium.org</owner>
+  <summary>
+    Elapsed time from the input event to hide the launcher UI. This is logged
+    each time the launcher is dismissed by pressing search key, clicking shelf
+    button, or focusing out side of the launcher.
+  </summary>
+</histogram>
+
 <histogram name="Apps.AppListHowEnabled" enum="AppListEnableSource">
   <owner>tapted@chromium.org</owner>
   <summary>
@@ -2289,6 +2298,15 @@
   </summary>
 </histogram>
 
+<histogram name="Apps.AppListShow.InputLatency" units="ms">
+  <owner>wutao@chromium.org</owner>
+  <summary>
+    Elapsed time from the input event to show the launcher UI. This is logged
+    each time the app list is shown by pressing search key, clicking shelf
+    button, or swiping from shelf.
+  </summary>
+</histogram>
+
 <histogram name="Apps.AppListShowSource" enum="AppListShowSource">
   <owner>newcomer@chromium.org</owner>
   <summary>
@@ -36862,6 +36880,16 @@
   </summary>
 </histogram>
 
+<histogram name="Media.VaapiWrapper.VADisplayStateInitializeSuccess"
+    enum="BooleanSuccess">
+  <owner>acourbot@chromium.org</owner>
+  <owner>mcasas@chromium.org</owner>
+  <summary>
+    Whether the call to VaapiWrapper's VADisplayState::Initialize() succeeded or
+    not.
+  </summary>
+</histogram>
+
 <histogram name="Media.VAJDA.DecoderFailure" enum="VAJDADecoderFailure">
   <owner>kcwu@chromium.org</owner>
   <summary>
@@ -36883,6 +36911,14 @@
   </summary>
 </histogram>
 
+<histogram name="Media.VAVDA.VaapiWrapperCreationSuccess" enum="BooleanSuccess">
+  <owner>acourbot@chromium.org</owner>
+  <owner>mcasas@chromium.org</owner>
+  <summary>
+    Whether the creation of VaapiWrapper succeeded or not inside VaVDA.
+  </summary>
+</histogram>
+
 <histogram name="Media.VAVDAH264.DecoderFailure" enum="VAVDAH264DecoderFailure">
   <obsolete>
     Deprecated as of 4/2015, partially replaced by Media.VAVDA.DecoderFailure.
@@ -79288,6 +79324,21 @@
   </summary>
 </histogram>
 
+<histogram name="Search.ContextualSearch.Ranker.FeaturesAvailable"
+    enum="Boolean">
+  <owner>donnd@chromium.org</owner>
+  <owner>twellington@chromium.org</owner>
+  <summary>
+    Logs that the UX has entered a state where features are available to be
+    recorded to Ranker.  A value of true indicates that the available features
+    include outcomes, false if they are just features at inference-time. Use to
+    correlate with what actually gets recorded in the Search.
+    ContextualSearch.Ranker.Recorded histogram. Recorded when a tap gesture is
+    recognized that might trigger our UX (for pure features), and when the UX is
+    actually shown (for outcomes). Implemented for Android.
+  </summary>
+</histogram>
+
 <histogram name="Search.ContextualSearch.Ranker.Model.Status"
     enum="RankerModelStatus">
   <owner>hamelphi@google.com</owner>
diff --git a/tools/perf/core/perf_data_generator.py b/tools/perf/core/perf_data_generator.py
index 6b0126d..3edb90f 100755
--- a/tools/perf/core/perf_data_generator.py
+++ b/tools/perf/core/perf_data_generator.py
@@ -294,7 +294,7 @@
     swarming=[
       {
        'gpu': '8086:1616',
-       'os': 'Windows-10-16299.248',
+       'os': 'Windows-10',
        'pool': 'Chrome-perf',
        'device_ids': [
            'build117-b1', 'build118-b1',
@@ -308,7 +308,7 @@
     swarming=[
       {
        'gpu': '102b:0534',
-       'os': 'Windows-10-10240',
+       'os': 'Windows-10',
        'pool': 'Chrome-perf',
        'device_ids': [
            'build132-m1', 'build133-m1',
diff --git a/tools/traffic_annotation/auditor/BUILD.gn b/tools/traffic_annotation/auditor/BUILD.gn
index df52f36..c2a22d03 100644
--- a/tools/traffic_annotation/auditor/BUILD.gn
+++ b/tools/traffic_annotation/auditor/BUILD.gn
@@ -69,6 +69,7 @@
     "//net:traffic_annotation",
     "//third_party/libxml",
     "//third_party/protobuf:protobuf_full",
+    "//third_party/re2",
   ]
 }
 
diff --git a/tools/traffic_annotation/auditor/DEPS b/tools/traffic_annotation/auditor/DEPS
index cc1e04b..2e35345 100644
--- a/tools/traffic_annotation/auditor/DEPS
+++ b/tools/traffic_annotation/auditor/DEPS
@@ -2,4 +2,5 @@
   "+components/policy/proto",
   "+third_party/libxml",
   "+third_party/protobuf/src/google",
+  "+third_party/re2",
 ]
diff --git a/tools/traffic_annotation/auditor/auditor_result.cc b/tools/traffic_annotation/auditor/auditor_result.cc
index 85bbded9..320a884d 100644
--- a/tools/traffic_annotation/auditor/auditor_result.cc
+++ b/tools/traffic_annotation/auditor/auditor_result.cc
@@ -28,7 +28,8 @@
          type == AuditorResult::Type::ERROR_MISSING_TAG_USED ||
          type == AuditorResult::Type::ERROR_NO_ANNOTATION ||
          type == AuditorResult::Type::ERROR_MISSING_SECOND_ID ||
-         type == AuditorResult::Type::ERROR_DIRECT_ASSIGNMENT);
+         type == AuditorResult::Type::ERROR_DIRECT_ASSIGNMENT ||
+         type == AuditorResult::Type::ERROR_TEST_ANNOTATION);
   if (!message.empty())
     details_.push_back(message);
 };
@@ -163,6 +164,10 @@
           "files (like jumbo), rerun the auditor using --all-files switch.",
           details_[0].c_str());
 
+    case AuditorResult::Type::ERROR_TEST_ANNOTATION:
+      return base::StringPrintf("Annotation for tests is used in '%s:%i'.",
+                                file_path_.c_str(), line_);
+
     default:
       return std::string();
   }
diff --git a/tools/traffic_annotation/auditor/auditor_result.h b/tools/traffic_annotation/auditor/auditor_result.h
index 996921c..51c60d32 100644
--- a/tools/traffic_annotation/auditor/auditor_result.h
+++ b/tools/traffic_annotation/auditor/auditor_result.h
@@ -43,7 +43,8 @@
     ERROR_DIRECT_ASSIGNMENT,       // A value is directly assigned to a mutable
                                    // annotation or annotation instialized with
                                    // list expresssion.
-    ERROR_ANNOTATIONS_XML_UPDATE   // Annotations XML requires update.
+    ERROR_ANNOTATIONS_XML_UPDATE,  // Annotations XML requires update.
+    ERROR_TEST_ANNOTATION,         // Annotation for tests is used.
   };
 
   static const int kNoCodeLineSpecified;
diff --git a/tools/traffic_annotation/auditor/instance.cc b/tools/traffic_annotation/auditor/instance.cc
index a930834..086ed130 100644
--- a/tools/traffic_annotation/auditor/instance.cc
+++ b/tools/traffic_annotation/auditor/instance.cc
@@ -164,7 +164,8 @@
   if (unique_id_hash_code == TRAFFIC_ANNOTATION_FOR_TESTS.unique_id_hash_code ||
       unique_id_hash_code ==
           PARTIAL_TRAFFIC_ANNOTATION_FOR_TESTS.unique_id_hash_code) {
-    return AuditorResult(AuditorResult::Type::RESULT_IGNORE);
+    return AuditorResult(AuditorResult::Type::ERROR_TEST_ANNOTATION, "",
+                         file_path, line_number);
   }
 
   // Process undefined tags.
diff --git a/tools/traffic_annotation/auditor/safe_list.txt b/tools/traffic_annotation/auditor/safe_list.txt
index 93bf3ff..cd4c10ef 100644
--- a/tools/traffic_annotation/auditor/safe_list.txt
+++ b/tools/traffic_annotation/auditor/safe_list.txt
@@ -2,7 +2,9 @@
 # anntotation auditor. Refer to AuditorException::ExceptionType in
 # 'tools/traffic_annotation/auditor/traffic_annotation_auditor.h' for types of
 # exceptions.
-all,tools
+# Use * as wildcard for zero or more characters.
+all,tools/*
 missing,net/url_request/url_fetcher.cc
 missing,net/url_request/url_request_context.cc
-direct_assignment,download::ProtoConversions::EntryFromProto@components/download/internal/background_service/proto_conversions.cc
\ No newline at end of file
+direct_assignment,download::ProtoConversions::EntryFromProto@components/download/internal/background_service/proto_conversions.cc
+test_annotation,*test*,*fuzzer*,*mock*,*fake*,net/quic/chromium/quic_chromium_client_session_peer.cc
\ No newline at end of file
diff --git a/tools/traffic_annotation/auditor/traffic_annotation_auditor.cc b/tools/traffic_annotation/auditor/traffic_annotation_auditor.cc
index de66aa9..ff75bdc 100644
--- a/tools/traffic_annotation/auditor/traffic_annotation_auditor.cc
+++ b/tools/traffic_annotation/auditor/traffic_annotation_auditor.cc
@@ -18,6 +18,7 @@
 #include "build/build_config.h"
 #include "net/traffic_annotation/network_traffic_annotation.h"
 #include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
+#include "third_party/re2/src/re2/re2.h"
 #include "tools/traffic_annotation/auditor/traffic_annotation_file_filter.h"
 #include "tools/traffic_annotation/auditor/traffic_annotation_id_checker.h"
 
@@ -307,8 +308,8 @@
   const std::vector<std::string>& safe_list =
       safe_list_[static_cast<int>(exception_type)];
 
-  for (const std::string& ignore_path : safe_list) {
-    if (!strncmp(file_path.c_str(), ignore_path.c_str(), ignore_path.length()))
+  for (const std::string& ignore_pattern : safe_list) {
+    if (re2::RE2::FullMatch(file_path, ignore_pattern))
       return true;
   }
 
@@ -365,12 +366,24 @@
     if (block_type == "ANNOTATION") {
       AnnotationInstance new_annotation;
       result = new_annotation.Deserialize(lines, current, end_line);
-      if (result.IsOK()) {
-        extracted_annotations_.push_back(new_annotation);
-      } else if (result.type() == AuditorResult::Type::ERROR_MISSING_TAG_USED &&
-                 IsSafeListed(result.file_path(),
-                              AuditorException::ExceptionType::MISSING)) {
-        result = AuditorResult(AuditorResult::Type::RESULT_IGNORE);
+      switch (result.type()) {
+        case AuditorResult::Type::RESULT_OK:
+          extracted_annotations_.push_back(new_annotation);
+          break;
+        case AuditorResult::Type::ERROR_MISSING_TAG_USED:
+          if (IsSafeListed(result.file_path(),
+                           AuditorException::ExceptionType::MISSING)) {
+            result = AuditorResult(AuditorResult::Type::RESULT_IGNORE);
+          }
+          break;
+        case AuditorResult::Type::ERROR_TEST_ANNOTATION:
+          if (IsSafeListed(result.file_path(),
+                           AuditorException::ExceptionType::TEST_ANNOTATION)) {
+            result = AuditorResult(AuditorResult::Type::RESULT_IGNORE);
+          }
+          break;
+        default:
+          break;
       }
     } else if (block_type == "CALL") {
       CallInstance new_call;
@@ -418,37 +431,56 @@
 bool TrafficAnnotationAuditor::LoadSafeList() {
   base::FilePath safe_list_file =
       base::MakeAbsoluteFilePath(source_path_.Append(kSafeListPath));
-  std::string file_content;
-  if (base::ReadFileToString(safe_list_file, &file_content)) {
-    base::RemoveChars(file_content, "\r", &file_content);
-    std::vector<std::string> lines = base::SplitString(
-        file_content, "\n", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL);
-    for (const std::string& line : lines) {
-      // Ignore comments and empty lines.
-      if (!line.length() || line[0] == '#')
-        continue;
-      size_t comma = line.find(',');
-      if (comma == std::string::npos) {
-        LOG(ERROR) << "Unexpected syntax in safe_list.txt, line: " << line;
-        return false;
-      }
 
-      AuditorException::ExceptionType exception_type;
-      if (AuditorException::TypeFromString(line.substr(0, comma),
-                                           &exception_type)) {
-        safe_list_[static_cast<int>(exception_type)].push_back(
-            line.substr(comma + 1, line.length() - comma - 1));
-      } else {
-        LOG(ERROR) << "Unexpected type in safe_list.txt line: " << line;
-        return false;
-      }
-    }
-    safe_list_loaded_ = true;
-    return true;
+  std::string file_content;
+  if (!base::ReadFileToString(safe_list_file, &file_content)) {
+    LOG(ERROR) << "Could not read " << kSafeListPath.MaybeAsASCII();
+    return false;
   }
 
-  LOG(ERROR) << "Could not read " << kSafeListPath.MaybeAsASCII();
-  return false;
+  base::RemoveChars(file_content, "\r", &file_content);
+  std::vector<std::string> lines = base::SplitString(
+      file_content, "\n", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL);
+
+  for (const std::string& line : lines) {
+    // Ignore comments and empty lines.
+    if (!line.length() || line[0] == '#')
+      continue;
+
+    std::vector<std::string> tokens = base::SplitString(
+        line, ",", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL);
+
+    // Expect a type and at least one value in each line.
+    if (tokens.size() < 2) {
+      LOG(ERROR) << "Unexpected syntax in safe_list.txt, line: " << line;
+      return false;
+    }
+
+    AuditorException::ExceptionType exception_type;
+    if (!AuditorException::TypeFromString(tokens[0], &exception_type)) {
+      LOG(ERROR) << "Unexpected type in safe_list.txt line: " << line;
+      return false;
+    }
+    for (unsigned i = 1; i < tokens.size(); i++) {
+      // Convert the rest of the line into re2 patterns, making dots as fixed
+      // characters and asterisks as wildcards.
+      // Note that all file paths are converted to Linux style before checking.
+      if (!base::ContainsOnlyChars(
+              base::ToLowerASCII(tokens[i]),
+              "0123456789_abcdefghijklmnopqrstuvwxyz.*/:@")) {
+        LOG(ERROR) << "Unexpected character in safe_list.txt token: "
+                   << tokens[i];
+        return false;
+      }
+      std::string pattern;
+      base::ReplaceChars(tokens[i], ".", "[.]", &pattern);
+      base::ReplaceChars(pattern, "*", ".*", &pattern);
+      safe_list_[static_cast<int>(exception_type)].push_back(pattern);
+    }
+  }
+
+  safe_list_loaded_ = true;
+  return true;
 }
 
 // static
diff --git a/tools/traffic_annotation/auditor/traffic_annotation_auditor.h b/tools/traffic_annotation/auditor/traffic_annotation_auditor.h
index 55f16dda..62d6932e 100644
--- a/tools/traffic_annotation/auditor/traffic_annotation_auditor.h
+++ b/tools/traffic_annotation/auditor/traffic_annotation_auditor.h
@@ -20,7 +20,8 @@
     ALL,                // Ignore all errors (doesn't check the files at all).
     MISSING,            // Ignore missing annotations.
     DIRECT_ASSIGNMENT,  // Ignore direct assignment of annotation value.
-    EXCEPTION_TYPE_LAST = DIRECT_ASSIGNMENT
+    TEST_ANNOTATION,    // Ignore usages of annotation for tests.
+    EXCEPTION_TYPE_LAST = TEST_ANNOTATION
   } type;
 
   static bool TypeFromString(const std::string& type_string,
@@ -31,6 +32,8 @@
       *type_value = ExceptionType::MISSING;
     } else if (type_string == "direct_assignment") {
       *type_value = ExceptionType::DIRECT_ASSIGNMENT;
+    } else if (type_string == "test_annotation") {
+      *type_value = ExceptionType::TEST_ANNOTATION;
     } else {
       return false;
     }
diff --git a/tools/traffic_annotation/auditor/traffic_annotation_auditor_unittest.cc b/tools/traffic_annotation/auditor/traffic_annotation_auditor_unittest.cc
index 2a333e8..a074a8d 100644
--- a/tools/traffic_annotation/auditor/traffic_annotation_auditor_unittest.cc
+++ b/tools/traffic_annotation/auditor/traffic_annotation_auditor_unittest.cc
@@ -272,6 +272,18 @@
                                      AuditorException::ExceptionType::MISSING));
   EXPECT_TRUE(auditor().IsSafeListed("net/url_request/url_request_context.cc",
                                      AuditorException::ExceptionType::MISSING));
+
+  // Files having the word test in their full path can have annotation for
+  // tests.
+  EXPECT_FALSE(
+      auditor().IsSafeListed("net/url_request/url_fetcher.cc",
+                             AuditorException::ExceptionType::TEST_ANNOTATION));
+  EXPECT_TRUE(
+      auditor().IsSafeListed("chrome/browser/test_something.cc",
+                             AuditorException::ExceptionType::TEST_ANNOTATION));
+  EXPECT_TRUE(
+      auditor().IsSafeListed("test/send_something.cc",
+                             AuditorException::ExceptionType::TEST_ANNOTATION));
 }
 
 // Tests if annotation instances are corrrectly deserialized.
@@ -292,7 +304,7 @@
        AnnotationInstance::Type::ANNOTATION_COMPLETING},
       {"good_partial_annotation.txt", AuditorResult::Type::RESULT_OK,
        AnnotationInstance::Type::ANNOTATION_PARTIAL},
-      {"good_test_annotation.txt", AuditorResult::Type::RESULT_IGNORE},
+      {"good_test_annotation.txt", AuditorResult::Type::ERROR_TEST_ANNOTATION},
       {"missing_annotation.txt", AuditorResult::Type::ERROR_MISSING_TAG_USED},
       {"no_annotation.txt", AuditorResult::Type::ERROR_NO_ANNOTATION},
       {"fatal_annotation1.txt", AuditorResult::Type::ERROR_FATAL},
@@ -309,7 +321,7 @@
     AnnotationInstance annotation;
     AuditorResult::Type result_type =
         Deserialize(test_case.file_name, &annotation);
-    EXPECT_EQ(result_type, test_case.result_type);
+    EXPECT_EQ(result_type, test_case.result_type) << test_case.file_name;
 
     if (result_type == AuditorResult::Type::RESULT_OK)
       EXPECT_EQ(annotation.type, test_case.type);
diff --git a/tools/traffic_annotation/auditor/traffic_annotation_file_filter.cc b/tools/traffic_annotation/auditor/traffic_annotation_file_filter.cc
index 3413cfd7..c8c7cc34 100644
--- a/tools/traffic_annotation/auditor/traffic_annotation_file_filter.cc
+++ b/tools/traffic_annotation/auditor/traffic_annotation_file_filter.cc
@@ -16,6 +16,7 @@
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "build/build_config.h"
+#include "third_party/re2/src/re2/re2.h"
 
 namespace {
 
@@ -142,9 +143,8 @@
   for (const std::string& file_path : git_files_) {
     if (!strncmp(file_path.c_str(), directory_name.c_str(), name_length)) {
       bool ignore = false;
-      for (const std::string& ignore_path : ignore_list) {
-        if (!strncmp(file_path.c_str(), ignore_path.c_str(),
-                     ignore_path.length())) {
+      for (const std::string& ignore_pattern : ignore_list) {
+        if (re2::RE2::FullMatch(file_path.c_str(), ignore_pattern)) {
           ignore = true;
           break;
         }
diff --git a/tools/traffic_annotation/summary/annotations.xml b/tools/traffic_annotation/summary/annotations.xml
index 0a9687d..1bb5f1c6 100644
--- a/tools/traffic_annotation/summary/annotations.xml
+++ b/tools/traffic_annotation/summary/annotations.xml
@@ -252,6 +252,7 @@
  <item id="web_history_expire_between_dates" hash_code="126122632" type="1" second_id="110307337" content_hash_code="34304787" os_list="linux,windows" semantics_fields="2,3,4" policy_fields="4" file_path="components/history/core/browser/history_service.cc"/>
  <item id="web_history_query" hash_code="17400350" type="1" second_id="110307337" content_hash_code="36075147" os_list="linux,windows" semantics_fields="2,3,4" policy_fields="4" file_path="components/history/core/browser/browsing_history_service.cc"/>
  <item id="web_history_service" hash_code="110307337" type="2" content_hash_code="16140045" os_list="linux,windows" semantics_fields="1,5" policy_fields="-1,3" file_path="components/history/core/browser/web_history_service.cc"/>
+ <item id="webrtc_event_log_uploader" hash_code="24186190" type="0" content_hash_code="107123816" os_list="linux,windows" file_path="chrome/browser/media/webrtc/webrtc_event_log_uploader.cc"/>
  <item id="webrtc_log_upload" hash_code="62443804" type="0" content_hash_code="33661169" os_list="linux,windows" file_path="chrome/browser/media/webrtc/webrtc_log_uploader.cc"/>
  <item id="webrtc_peer_connection" hash_code="63497370" type="0" content_hash_code="60553259" os_list="linux,windows" file_path="content/renderer/media/webrtc/peer_connection_dependency_factory.cc"/>
  <item id="websocket_basic_stream" hash_code="51586722" type="0" content_hash_code="68121427" os_list="linux,windows" file_path="net/websockets/websocket_basic_stream.cc"/>
diff --git a/ui/app_list/app_list_metrics.h b/ui/app_list/app_list_metrics.h
index 0f3fd2d..b38ebbd 100644
--- a/ui/app_list/app_list_metrics.h
+++ b/ui/app_list/app_list_metrics.h
@@ -13,6 +13,16 @@
 class SearchModel;
 class SearchResult;
 
+// The UMA histogram that logs the input latency from input event to the
+// representation time of the shown launcher UI.
+constexpr char kAppListShowInputLatencyHistogram[] =
+    "Apps.AppListShow.InputLatency";
+
+// The UMA histogram that logs the input latency from input event to the
+// representation time of the dismissed launcher UI.
+constexpr char kAppListHideInputLatencyHistogram[] =
+    "Apps.AppListHide.InputLatency";
+
 void RecordFolderShowHideAnimationSmoothness(int actual_frames,
                                              int ideal_duration_ms,
                                              float refresh_rate);
diff --git a/ui/app_list/vector_icons/ic_arrow_up.1x.icon b/ui/app_list/vector_icons/ic_arrow_up.1x.icon
index d28822f..40d0ce7 100644
--- a/ui/app_list/vector_icons/ic_arrow_up.1x.icon
+++ b/ui/app_list/vector_icons/ic_arrow_up.1x.icon
@@ -9,5 +9,4 @@
 LINE_TO, 0, 7.66f,
 LINE_TO, 6, 2,
 R_LINE_TO, 6, 5.66f,
-CLOSE,
-END
+CLOSE
diff --git a/ui/app_list/vector_icons/ic_arrow_up.icon b/ui/app_list/vector_icons/ic_arrow_up.icon
index 5f8b186..91c3daf 100644
--- a/ui/app_list/vector_icons/ic_arrow_up.icon
+++ b/ui/app_list/vector_icons/ic_arrow_up.icon
@@ -9,5 +9,4 @@
 LINE_TO, 0, 16.33f,
 LINE_TO, 12, 5,
 R_LINE_TO, 12, 11.33f,
-CLOSE,
-END
+CLOSE
diff --git a/ui/app_list/vector_icons/ic_badge_instant.1x.icon b/ui/app_list/vector_icons/ic_badge_instant.1x.icon
index 77d71b1..664ec0f 100644
--- a/ui/app_list/vector_icons/ic_badge_instant.1x.icon
+++ b/ui/app_list/vector_icons/ic_badge_instant.1x.icon
@@ -18,5 +18,4 @@
 CUBIC_TO, 8.86f, 5, 9, 5.14f, 9, 5.31f,
 CUBIC_TO, 9, 5.38f, 8.98f, 5.44f, 8.94f, 5.49f,
 LINE_TO, 5.36f, 11,
-CLOSE,
-END
+CLOSE
diff --git a/ui/app_list/vector_icons/ic_badge_instant.icon b/ui/app_list/vector_icons/ic_badge_instant.icon
index f88d166..59349c6 100644
--- a/ui/app_list/vector_icons/ic_badge_instant.icon
+++ b/ui/app_list/vector_icons/ic_badge_instant.icon
@@ -18,5 +18,4 @@
 CUBIC_TO, 17.72f, 9.99f, 18, 10.27f, 18, 10.61f,
 CUBIC_TO, 18.01f, 10.76f, 17.95f, 10.88f, 17.88f, 10.99f,
 LINE_TO, 10.73f, 22,
-CLOSE,
-END
+CLOSE
diff --git a/ui/app_list/vector_icons/ic_badge_play.1x.icon b/ui/app_list/vector_icons/ic_badge_play.1x.icon
index 9fd281b..d5325b0 100644
--- a/ui/app_list/vector_icons/ic_badge_play.1x.icon
+++ b/ui/app_list/vector_icons/ic_badge_play.1x.icon
@@ -33,5 +33,4 @@
 LINE_TO, 1, 10.15f,
 CUBIC_TO, 1, 10.28f, 1.1f, 10.34f, 1.19f, 10.24f,
 LINE_TO, 5.5f, 5.93f,
-CLOSE,
-END
+CLOSE
diff --git a/ui/app_list/vector_icons/ic_badge_play.icon b/ui/app_list/vector_icons/ic_badge_play.icon
index 77e62cd..b3c4c7b 100644
--- a/ui/app_list/vector_icons/ic_badge_play.icon
+++ b/ui/app_list/vector_icons/ic_badge_play.icon
@@ -36,5 +36,4 @@
 LINE_TO, 3, 20.43f,
 CUBIC_TO, 3, 20.69f, 3.19f, 20.81f, 3.38f, 20.62f,
 LINE_TO, 12, 12,
-CLOSE,
-END
+CLOSE
diff --git a/ui/app_list/vector_icons/ic_badge_rating.1x.icon b/ui/app_list/vector_icons/ic_badge_rating.1x.icon
index 06b859c3..d7a8302 100644
--- a/ui/app_list/vector_icons/ic_badge_rating.1x.icon
+++ b/ui/app_list/vector_icons/ic_badge_rating.1x.icon
@@ -13,5 +13,4 @@
 LINE_TO, 1, 4.81f,
 LINE_TO, 3.73f, 7.3f,
 LINE_TO, 2.91f, 11,
-CLOSE,
-END
+CLOSE
diff --git a/ui/app_list/vector_icons/ic_badge_rating.icon b/ui/app_list/vector_icons/ic_badge_rating.icon
index 90938ee..4c0d253a7 100644
--- a/ui/app_list/vector_icons/ic_badge_rating.icon
+++ b/ui/app_list/vector_icons/ic_badge_rating.icon
@@ -13,5 +13,4 @@
 LINE_TO, 2, 9.62f,
 R_LINE_TO, 5.46f, 4.98f,
 LINE_TO, 5.82f, 22,
-CLOSE,
-END
+CLOSE
diff --git a/ui/app_list/vector_icons/ic_bookmark.1x.icon b/ui/app_list/vector_icons/ic_bookmark.1x.icon
index 9d81207..7c77a3c 100644
--- a/ui/app_list/vector_icons/ic_bookmark.1x.icon
+++ b/ui/app_list/vector_icons/ic_bookmark.1x.icon
@@ -13,5 +13,4 @@
 LINE_TO, 2, 7.34f,
 R_LINE_TO, 3.82f, 3.49f,
 LINE_TO, 4.67f, 16,
-CLOSE,
-END
+CLOSE
diff --git a/ui/app_list/vector_icons/ic_bookmark.icon b/ui/app_list/vector_icons/ic_bookmark.icon
index f8a846f..4f5ae02 100644
--- a/ui/app_list/vector_icons/ic_bookmark.icon
+++ b/ui/app_list/vector_icons/ic_bookmark.icon
@@ -13,5 +13,4 @@
 LINE_TO, 3, 14.67f,
 R_LINE_TO, 8.19f, 6.97f,
 LINE_TO, 8.73f, 32,
-CLOSE,
-END
+CLOSE
diff --git a/ui/app_list/vector_icons/ic_close.1x.icon b/ui/app_list/vector_icons/ic_close.1x.icon
index 3a5801a..55c4b63 100644
--- a/ui/app_list/vector_icons/ic_close.1x.icon
+++ b/ui/app_list/vector_icons/ic_close.1x.icon
@@ -15,5 +15,4 @@
 LINE_TO, 17.59f, 19,
 LINE_TO, 19, 17.59f,
 LINE_TO, 13.41f, 12,
-CLOSE,
-END
+CLOSE
diff --git a/ui/app_list/vector_icons/ic_close.icon b/ui/app_list/vector_icons/ic_close.icon
index a4e83b22..67d7220 100644
--- a/ui/app_list/vector_icons/ic_close.icon
+++ b/ui/app_list/vector_icons/ic_close.icon
@@ -15,5 +15,4 @@
 LINE_TO, 35.18f, 38,
 LINE_TO, 38, 35.18f,
 LINE_TO, 26.82f, 24,
-CLOSE,
-END
+CLOSE
diff --git a/ui/app_list/vector_icons/ic_domain.1x.icon b/ui/app_list/vector_icons/ic_domain.1x.icon
index da781731..502a38f 100644
--- a/ui/app_list/vector_icons/ic_domain.1x.icon
+++ b/ui/app_list/vector_icons/ic_domain.1x.icon
@@ -22,5 +22,4 @@
 LINE_TO, 10, 3,
 LINE_TO, 10, 6,
 LINE_TO, 13, 6,
-CLOSE,
-END
+CLOSE
diff --git a/ui/app_list/vector_icons/ic_domain.icon b/ui/app_list/vector_icons/ic_domain.icon
index 0a41747..d56e9a9 100644
--- a/ui/app_list/vector_icons/ic_domain.icon
+++ b/ui/app_list/vector_icons/ic_domain.icon
@@ -22,5 +22,4 @@
 LINE_TO, 20, 6,
 LINE_TO, 20, 13,
 LINE_TO, 26, 13,
-CLOSE,
-END
+CLOSE
diff --git a/ui/app_list/vector_icons/ic_equal.1x.icon b/ui/app_list/vector_icons/ic_equal.1x.icon
index 58c4f05..11ec410 100644
--- a/ui/app_list/vector_icons/ic_equal.1x.icon
+++ b/ui/app_list/vector_icons/ic_equal.1x.icon
@@ -14,5 +14,4 @@
 R_V_LINE_TO, 2,
 H_LINE_TO, 4,
 R_V_LINE_TO, -2,
-CLOSE,
-END
\ No newline at end of file
+CLOSE
diff --git a/ui/app_list/vector_icons/ic_equal.icon b/ui/app_list/vector_icons/ic_equal.icon
index 6f22451..4988a87 100644
--- a/ui/app_list/vector_icons/ic_equal.icon
+++ b/ui/app_list/vector_icons/ic_equal.icon
@@ -14,5 +14,4 @@
 R_V_LINE_TO, 3,
 H_LINE_TO, 9,
 R_V_LINE_TO, -3,
-CLOSE,
-END
\ No newline at end of file
+CLOSE
diff --git a/ui/app_list/vector_icons/ic_google_black.1x.icon b/ui/app_list/vector_icons/ic_google_black.1x.icon
index dd91373..f712169 100644
--- a/ui/app_list/vector_icons/ic_google_black.1x.icon
+++ b/ui/app_list/vector_icons/ic_google_black.1x.icon
@@ -17,5 +17,4 @@
 CUBIC_TO, 16.12f, 18, 17.54f, 15.57f, 17.81f, 14,
 LINE_TO, 12, 14,
 LINE_TO, 12, 10,
-CLOSE,
-END
+CLOSE
diff --git a/ui/app_list/vector_icons/ic_google_black.icon b/ui/app_list/vector_icons/ic_google_black.icon
index 6e55988..3e7b050d 100644
--- a/ui/app_list/vector_icons/ic_google_black.icon
+++ b/ui/app_list/vector_icons/ic_google_black.icon
@@ -16,5 +16,4 @@
 CUBIC_TO, 32.23f, 36, 35.09f, 31.14f, 35.62f, 28,
 LINE_TO, 24, 28,
 LINE_TO, 24, 20,
-CLOSE,
-END
+CLOSE
diff --git a/ui/app_list/vector_icons/ic_google_color.1x.icon b/ui/app_list/vector_icons/ic_google_color.1x.icon
index 317fe5c6..4cf472c1 100644
--- a/ui/app_list/vector_icons/ic_google_color.1x.icon
+++ b/ui/app_list/vector_icons/ic_google_color.1x.icon
@@ -46,5 +46,4 @@
 CUBIC_TO, 8.22f, 2, 4.77f, 4.25f, 3.09f, 7.52f,
 LINE_TO, 6.49f, 10.1f,
 CUBIC_TO, 7.3f, 7.74f, 9.55f, 5.98f, 12.2f, 5.98f,
-CLOSE,
-END
+CLOSE
diff --git a/ui/app_list/vector_icons/ic_google_color.icon b/ui/app_list/vector_icons/ic_google_color.icon
index 564966d..ca9fe70 100644
--- a/ui/app_list/vector_icons/ic_google_color.icon
+++ b/ui/app_list/vector_icons/ic_google_color.icon
@@ -46,5 +46,4 @@
 R_CUBIC_TO, 3, 0, 5.7f, 1, 7.8f, 3,
 R_LINE_TO, 5.8f, -5.7f,
 CUBIC_TO, 34.5f, 6, 29.9f, 4, 24.4f, 4,
-CLOSE,
-END
+CLOSE
diff --git a/ui/app_list/vector_icons/ic_history.1x.icon b/ui/app_list/vector_icons/ic_history.1x.icon
index b9695ccf..dca7a78 100644
--- a/ui/app_list/vector_icons/ic_history.1x.icon
+++ b/ui/app_list/vector_icons/ic_history.1x.icon
@@ -22,5 +22,4 @@
 LINE_TO, 8.2f, 9.8f,
 LINE_TO, 8.2f, 5,
 LINE_TO, 9.4f, 5,
-CLOSE,
-END
+CLOSE
diff --git a/ui/app_list/vector_icons/ic_history.icon b/ui/app_list/vector_icons/ic_history.icon
index 8adbe31f..9890851 100644
--- a/ui/app_list/vector_icons/ic_history.icon
+++ b/ui/app_list/vector_icons/ic_history.icon
@@ -22,5 +22,4 @@
 LINE_TO, 16.5f, 19.5f,
 LINE_TO, 16.5f, 10.5f,
 LINE_TO, 18.75f, 10.5f,
-CLOSE,
-END
+CLOSE
diff --git a/ui/app_list/vector_icons/ic_mic_black.1x.icon b/ui/app_list/vector_icons/ic_mic_black.1x.icon
index 24b28ac..72ec88f 100644
--- a/ui/app_list/vector_icons/ic_mic_black.1x.icon
+++ b/ui/app_list/vector_icons/ic_mic_black.1x.icon
@@ -21,5 +21,4 @@
 LINE_TO, 13, 18.72f,
 CUBIC_TO, 16.28f, 18.24f, 19, 15.42f, 19, 12,
 LINE_TO, 17.3f, 12,
-CLOSE,
-END
+CLOSE
diff --git a/ui/app_list/vector_icons/ic_mic_black.icon b/ui/app_list/vector_icons/ic_mic_black.icon
index ca365a0..08371f1 100644
--- a/ui/app_list/vector_icons/ic_mic_black.icon
+++ b/ui/app_list/vector_icons/ic_mic_black.icon
@@ -20,5 +20,4 @@
 LINE_TO, 26, 36.44f,
 CUBIC_TO, 32.56f, 35.48f, 38, 29.84f, 38, 23,
 LINE_TO, 34.6f, 23,
-CLOSE,
-END
+CLOSE
diff --git a/ui/app_list/vector_icons/ic_search.1x.icon b/ui/app_list/vector_icons/ic_search.1x.icon
index 8babbf81..1cf4f35 100644
--- a/ui/app_list/vector_icons/ic_search.1x.icon
+++ b/ui/app_list/vector_icons/ic_search.1x.icon
@@ -22,5 +22,4 @@
 CUBIC_TO, 2.83f, 4.67f, 4.67f, 2.83f, 6.95f, 2.83f,
 CUBIC_TO, 9.22f, 2.83f, 11.06f, 4.67f, 11.06f, 6.95f,
 CUBIC_TO, 11.06f, 9.22f, 9.22f, 11.06f, 6.95f, 11.06f,
-CLOSE,
-END
+CLOSE
diff --git a/ui/app_list/vector_icons/ic_search.icon b/ui/app_list/vector_icons/ic_search.icon
index 53ea5541..44b16812 100644
--- a/ui/app_list/vector_icons/ic_search.icon
+++ b/ui/app_list/vector_icons/ic_search.icon
@@ -23,5 +23,4 @@
 CUBIC_TO, 7.97f, 10.96f, 10.96f, 7.97f, 14.66f, 7.97f,
 CUBIC_TO, 18.36f, 7.97f, 21.35f, 10.96f, 21.35f, 14.66f,
 CUBIC_TO, 21.35f, 18.36f, 18.36f, 21.35f, 14.66f, 21.35f,
-CLOSE,
-END
+CLOSE
diff --git a/ui/app_list/vector_icons/ic_search_engine_not_google.1x.icon b/ui/app_list/vector_icons/ic_search_engine_not_google.1x.icon
index 5606e25c..a0e8629d 100644
--- a/ui/app_list/vector_icons/ic_search_engine_not_google.1x.icon
+++ b/ui/app_list/vector_icons/ic_search_engine_not_google.1x.icon
@@ -22,5 +22,4 @@
 CUBIC_TO, 5, 7.01f, 7.01f, 5, 9.5f, 5,
 CUBIC_TO, 11.99f, 5, 14, 7.01f, 14, 9.5f,
 CUBIC_TO, 14, 11.99f, 11.99f, 14, 9.5f, 14,
-CLOSE,
-END
+CLOSE
diff --git a/ui/app_list/vector_icons/ic_search_engine_not_google.icon b/ui/app_list/vector_icons/ic_search_engine_not_google.icon
index 3fd6c52c..4577140 100644
--- a/ui/app_list/vector_icons/ic_search_engine_not_google.icon
+++ b/ui/app_list/vector_icons/ic_search_engine_not_google.icon
@@ -21,5 +21,4 @@
 CUBIC_TO, 10, 14.02f, 14.02f, 10, 19, 10,
 CUBIC_TO, 23.98f, 10, 28, 14.02f, 28, 19,
 CUBIC_TO, 28, 23.98f, 23.98f, 28, 19, 28,
-CLOSE,
-END
+CLOSE
diff --git a/ui/events/keycodes/platform_key_map_win.cc b/ui/events/keycodes/platform_key_map_win.cc
index d7ecacc..fd694a98 100644
--- a/ui/events/keycodes/platform_key_map_win.cc
+++ b/ui/events/keycodes/platform_key_map_win.cc
@@ -279,7 +279,7 @@
 
 // TODO(crbug.com/25503): Controls Control+Alt vs AltGraph disambiguation.
 const base::Feature kFixAltGraphModifier{"FixAltGraph",
-                                         base::FEATURE_DISABLED_BY_DEFAULT};
+                                         base::FEATURE_ENABLED_BY_DEFAULT};
 
 }  // anonymous namespace
 
diff --git a/ui/gfx/BUILD.gn b/ui/gfx/BUILD.gn
index d268ffd..e0f776f 100644
--- a/ui/gfx/BUILD.gn
+++ b/ui/gfx/BUILD.gn
@@ -603,8 +603,6 @@
     "image/image_unittest_util.h",
     "image/image_unittest_util_ios.mm",
     "image/image_unittest_util_mac.mm",
-    "test/fontconfig_util_linux.cc",
-    "test/fontconfig_util_linux.h",
     "test/gfx_util.cc",
     "test/gfx_util.h",
     "test/icc_profiles.cc",
@@ -629,10 +627,6 @@
 
     deps += [ "//third_party:freetype_harfbuzz" ]
   }
-
-  if (is_linux) {
-    deps += [ "//third_party/fontconfig" ]
-  }
 }
 
 test("gfx_unittests") {
diff --git a/ui/gfx/font_render_params_linux_unittest.cc b/ui/gfx/font_render_params_linux_unittest.cc
index 34732ed..583932f 100644
--- a/ui/gfx/font_render_params_linux_unittest.cc
+++ b/ui/gfx/font_render_params_linux_unittest.cc
@@ -4,14 +4,16 @@
 
 #include "ui/gfx/font_render_params.h"
 
+#include <fontconfig/fontconfig.h>
+
 #include "base/files/scoped_temp_dir.h"
 #include "base/logging.h"
 #include "base/macros.h"
+#include "base/test/fontconfig_util_linux.h"
 #include "build/build_config.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/gfx/font.h"
 #include "ui/gfx/linux_font_delegate.h"
-#include "ui/gfx/test/fontconfig_util_linux.h"
 
 namespace gfx {
 
@@ -60,7 +62,6 @@
 class FontRenderParamsTest : public testing::Test {
  public:
   FontRenderParamsTest() {
-    SetUpFontconfig();
     CHECK(temp_dir_.CreateUniqueTempDir());
     original_font_delegate_ = LinuxFontDelegate::instance();
     LinuxFontDelegate::SetInstance(&test_font_delegate_);
@@ -70,7 +71,17 @@
   ~FontRenderParamsTest() override {
     LinuxFontDelegate::SetInstance(
         const_cast<LinuxFontDelegate*>(original_font_delegate_));
-    TearDownFontconfig();
+  }
+
+  void SetUp() override {
+    // Fontconfig should already be set up by the test runner.
+    DCHECK(FcConfigGetCurrent());
+  }
+
+  void TearDown() override {
+    // We might have made a mess introducing new fontconfig settings.  Reset the
+    // state of fontconfig for the next test.
+    base::SetUpFontconfig();
   }
 
  protected:
@@ -83,7 +94,6 @@
 };
 
 TEST_F(FontRenderParamsTest, Default) {
-  ASSERT_TRUE(LoadSystemFontIntoFontconfig("arial.ttf"));
   ASSERT_TRUE(LoadConfigDataIntoFontconfig(
       temp_dir_.GetPath(),
       std::string(kFontconfigFileHeader) +
@@ -91,36 +101,36 @@
           // match (since this is the style generally used in
           // /etc/fonts/conf.d).
           kFontconfigMatchFontHeader +
-          CreateFontconfigEditStanza("antialias", "bool", "true") +
-          CreateFontconfigEditStanza("autohint", "bool", "true") +
-          CreateFontconfigEditStanza("hinting", "bool", "true") +
-          CreateFontconfigEditStanza("hintstyle", "const", "hintslight") +
-          CreateFontconfigEditStanza("rgba", "const", "rgb") +
+          base::CreateFontconfigEditStanza("antialias", "bool", "true") +
+          base::CreateFontconfigEditStanza("autohint", "bool", "true") +
+          base::CreateFontconfigEditStanza("hinting", "bool", "true") +
+          base::CreateFontconfigEditStanza("hintstyle", "const", "hintslight") +
+          base::CreateFontconfigEditStanza("rgba", "const", "rgb") +
           kFontconfigMatchFooter +
           // Add a font match for Arial. Since it specifies a family, it
-          // shouldn't
-          // take effect when querying default settings.
+          // shouldn't take effect when querying default settings.
           kFontconfigMatchFontHeader +
-          CreateFontconfigTestStanza("family", "eq", "string", "Arial") +
-          CreateFontconfigEditStanza("antialias", "bool", "true") +
-          CreateFontconfigEditStanza("autohint", "bool", "false") +
-          CreateFontconfigEditStanza("hinting", "bool", "true") +
-          CreateFontconfigEditStanza("hintstyle", "const", "hintfull") +
-          CreateFontconfigEditStanza("rgba", "const", "none") +
+          base::CreateFontconfigTestStanza("family", "eq", "string", "Arial") +
+          base::CreateFontconfigEditStanza("antialias", "bool", "true") +
+          base::CreateFontconfigEditStanza("autohint", "bool", "false") +
+          base::CreateFontconfigEditStanza("hinting", "bool", "true") +
+          base::CreateFontconfigEditStanza("hintstyle", "const", "hintfull") +
+          base::CreateFontconfigEditStanza("rgba", "const", "none") +
           kFontconfigMatchFooter +
           // Add font matches for fonts between 10 and 20 points or pixels.
-          // Since
-          // they specify sizes, they also should not affect the defaults.
+          // Since they specify sizes, they also should not affect the defaults.
           kFontconfigMatchFontHeader +
-          CreateFontconfigTestStanza("size", "more_eq", "double", "10.0") +
-          CreateFontconfigTestStanza("size", "less_eq", "double", "20.0") +
-          CreateFontconfigEditStanza("antialias", "bool", "false") +
+          base::CreateFontconfigTestStanza("size", "more_eq", "double",
+                                           "10.0") +
+          base::CreateFontconfigTestStanza("size", "less_eq", "double",
+                                           "20.0") +
+          base::CreateFontconfigEditStanza("antialias", "bool", "false") +
           kFontconfigMatchFooter + kFontconfigMatchFontHeader +
-          CreateFontconfigTestStanza("pixel_size", "more_eq", "double",
-                                     "10.0") +
-          CreateFontconfigTestStanza("pixel_size", "less_eq", "double",
-                                     "20.0") +
-          CreateFontconfigEditStanza("antialias", "bool", "false") +
+          base::CreateFontconfigTestStanza("pixel_size", "more_eq", "double",
+                                           "10.0") +
+          base::CreateFontconfigTestStanza("pixel_size", "less_eq", "double",
+                                           "20.0") +
+          base::CreateFontconfigEditStanza("antialias", "bool", "false") +
           kFontconfigMatchFooter + kFontconfigFileFooter));
 
   FontRenderParams params = GetFontRenderParams(
@@ -135,21 +145,21 @@
 }
 
 TEST_F(FontRenderParamsTest, Size) {
-  ASSERT_TRUE(LoadSystemFontIntoFontconfig("arial.ttf"));
-  ASSERT_TRUE(LoadConfigDataIntoFontconfig(
+  ASSERT_TRUE(base::LoadConfigDataIntoFontconfig(
       temp_dir_.GetPath(),
       std::string(kFontconfigFileHeader) + kFontconfigMatchPatternHeader +
-          CreateFontconfigEditStanza("antialias", "bool", "true") +
-          CreateFontconfigEditStanza("hinting", "bool", "true") +
-          CreateFontconfigEditStanza("hintstyle", "const", "hintfull") +
-          CreateFontconfigEditStanza("rgba", "const", "none") +
+          base::CreateFontconfigEditStanza("antialias", "bool", "true") +
+          base::CreateFontconfigEditStanza("hinting", "bool", "true") +
+          base::CreateFontconfigEditStanza("hintstyle", "const", "hintfull") +
+          base::CreateFontconfigEditStanza("rgba", "const", "none") +
           kFontconfigMatchFooter + kFontconfigMatchPatternHeader +
-          CreateFontconfigTestStanza("pixelsize", "less_eq", "double", "10") +
-          CreateFontconfigEditStanza("antialias", "bool", "false") +
+          base::CreateFontconfigTestStanza("pixelsize", "less_eq", "double",
+                                           "10") +
+          base::CreateFontconfigEditStanza("antialias", "bool", "false") +
           kFontconfigMatchFooter + kFontconfigMatchPatternHeader +
-          CreateFontconfigTestStanza("size", "more_eq", "double", "20") +
-          CreateFontconfigEditStanza("hintstyle", "const", "hintslight") +
-          CreateFontconfigEditStanza("rgba", "const", "rgb") +
+          base::CreateFontconfigTestStanza("size", "more_eq", "double", "20") +
+          base::CreateFontconfigEditStanza("hintstyle", "const", "hintslight") +
+          base::CreateFontconfigEditStanza("rgba", "const", "rgb") +
           kFontconfigMatchFooter + kFontconfigFileFooter));
 
   // The defaults should be used when the supplied size isn't matched by the
@@ -179,22 +189,21 @@
 }
 
 TEST_F(FontRenderParamsTest, Style) {
-  ASSERT_TRUE(LoadSystemFontIntoFontconfig("arial.ttf"));
   // Load a config that disables subpixel rendering for bold text and disables
   // hinting for italic text.
   ASSERT_TRUE(LoadConfigDataIntoFontconfig(
       temp_dir_.GetPath(),
       std::string(kFontconfigFileHeader) + kFontconfigMatchPatternHeader +
-          CreateFontconfigEditStanza("antialias", "bool", "true") +
-          CreateFontconfigEditStanza("hinting", "bool", "true") +
-          CreateFontconfigEditStanza("hintstyle", "const", "hintslight") +
-          CreateFontconfigEditStanza("rgba", "const", "rgb") +
+          base::CreateFontconfigEditStanza("antialias", "bool", "true") +
+          base::CreateFontconfigEditStanza("hinting", "bool", "true") +
+          base::CreateFontconfigEditStanza("hintstyle", "const", "hintslight") +
+          base::CreateFontconfigEditStanza("rgba", "const", "rgb") +
           kFontconfigMatchFooter + kFontconfigMatchPatternHeader +
-          CreateFontconfigTestStanza("weight", "eq", "const", "bold") +
-          CreateFontconfigEditStanza("rgba", "const", "none") +
+          base::CreateFontconfigTestStanza("weight", "eq", "const", "bold") +
+          base::CreateFontconfigEditStanza("rgba", "const", "none") +
           kFontconfigMatchFooter + kFontconfigMatchPatternHeader +
-          CreateFontconfigTestStanza("slant", "eq", "const", "italic") +
-          CreateFontconfigEditStanza("hinting", "bool", "false") +
+          base::CreateFontconfigTestStanza("slant", "eq", "const", "italic") +
+          base::CreateFontconfigEditStanza("hinting", "bool", "false") +
           kFontconfigMatchFooter + kFontconfigFileFooter));
 
   FontRenderParamsQuery query;
@@ -230,10 +239,10 @@
   ASSERT_TRUE(LoadConfigDataIntoFontconfig(
       temp_dir_.GetPath(),
       std::string(kFontconfigFileHeader) + kFontconfigMatchPatternHeader +
-          CreateFontconfigEditStanza("antialias", "bool", "false") +
+          base::CreateFontconfigEditStanza("antialias", "bool", "false") +
           kFontconfigMatchFooter + kFontconfigMatchPatternHeader +
-          CreateFontconfigTestStanza("scalable", "eq", "bool", "true") +
-          CreateFontconfigEditStanza("antialias", "bool", "true") +
+          base::CreateFontconfigTestStanza("scalable", "eq", "bool", "true") +
+          base::CreateFontconfigEditStanza("antialias", "bool", "true") +
           kFontconfigMatchFooter + kFontconfigFileFooter));
 
   // Check that we specifically ask how scalable fonts should be rendered.
@@ -243,15 +252,15 @@
 }
 
 TEST_F(FontRenderParamsTest, UseBitmaps) {
-  ASSERT_TRUE(LoadSystemFontIntoFontconfig("arial.ttf"));
   // Load a config that enables embedded bitmaps for fonts <= 10 pixels.
   ASSERT_TRUE(LoadConfigDataIntoFontconfig(
       temp_dir_.GetPath(),
       std::string(kFontconfigFileHeader) + kFontconfigMatchPatternHeader +
-          CreateFontconfigEditStanza("embeddedbitmap", "bool", "false") +
+          base::CreateFontconfigEditStanza("embeddedbitmap", "bool", "false") +
           kFontconfigMatchFooter + kFontconfigMatchPatternHeader +
-          CreateFontconfigTestStanza("pixelsize", "less_eq", "double", "10") +
-          CreateFontconfigEditStanza("embeddedbitmap", "bool", "true") +
+          base::CreateFontconfigTestStanza("pixelsize", "less_eq", "double",
+                                           "10") +
+          base::CreateFontconfigEditStanza("embeddedbitmap", "bool", "true") +
           kFontconfigMatchFooter + kFontconfigFileFooter));
 
   FontRenderParamsQuery query;
@@ -269,10 +278,10 @@
   ASSERT_TRUE(LoadConfigDataIntoFontconfig(
       temp_dir_.GetPath(),
       std::string(kFontconfigFileHeader) + kFontconfigMatchPatternHeader +
-          CreateFontconfigEditStanza("antialias", "bool", "false") +
-          CreateFontconfigEditStanza("hinting", "bool", "false") +
-          CreateFontconfigEditStanza("hintstyle", "const", "hintnone") +
-          CreateFontconfigEditStanza("rgba", "const", "rgb") +
+          base::CreateFontconfigEditStanza("antialias", "bool", "false") +
+          base::CreateFontconfigEditStanza("hinting", "bool", "false") +
+          base::CreateFontconfigEditStanza("hintstyle", "const", "hintnone") +
+          base::CreateFontconfigEditStanza("rgba", "const", "rgb") +
           kFontconfigMatchFooter + kFontconfigFileFooter));
 
   // Full hinting should be forced. See the comment in GetFontRenderParams() for
@@ -318,7 +327,7 @@
   ASSERT_TRUE(LoadConfigDataIntoFontconfig(
       temp_dir_.GetPath(),
       std::string(kFontconfigFileHeader) + kFontconfigMatchPatternHeader +
-          CreateFontconfigEditStanza("antialias", "bool", "true") +
+          base::CreateFontconfigEditStanza("antialias", "bool", "true") +
           kFontconfigMatchFooter + kFontconfigFileFooter));
 
   // The subpixel rendering setting from the delegate should make it through.
@@ -328,7 +337,9 @@
 }
 
 TEST_F(FontRenderParamsTest, NoFontconfigMatch) {
-  // Don't load a Fontconfig configuration.
+  // A default configuration was set up globally.  Reset it to a blank config.
+  FcConfigSetCurrent(FcConfigCreate());
+
   FontRenderParams system_params;
   system_params.antialiasing = true;
   system_params.hinting = FontRenderParams::HINTING_MEDIUM;
@@ -352,8 +363,6 @@
 TEST_F(FontRenderParamsTest, MissingFamily) {
   // With Arial and Verdana installed, request (in order) Helvetica, Arial, and
   // Verdana and check that Arial is returned.
-  ASSERT_TRUE(LoadSystemFontIntoFontconfig("arial.ttf"));
-  ASSERT_TRUE(LoadSystemFontIntoFontconfig("verdana.ttf"));
   FontRenderParamsQuery query;
   query.families.push_back("Helvetica");
   query.families.push_back("Arial");
@@ -365,15 +374,13 @@
 
 TEST_F(FontRenderParamsTest, SubstituteFamily) {
   // Configure Fontconfig to use Verdana for both Helvetica and Arial.
-  ASSERT_TRUE(LoadSystemFontIntoFontconfig("arial.ttf"));
-  ASSERT_TRUE(LoadSystemFontIntoFontconfig("verdana.ttf"));
   ASSERT_TRUE(LoadConfigDataIntoFontconfig(
       temp_dir_.GetPath(),
       std::string(kFontconfigFileHeader) +
-          CreateFontconfigAliasStanza("Helvetica", "Verdana") +
+          base::CreateFontconfigAliasStanza("Helvetica", "Verdana") +
           kFontconfigMatchPatternHeader +
-          CreateFontconfigTestStanza("family", "eq", "string", "Arial") +
-          CreateFontconfigEditStanza("family", "string", "Verdana") +
+          base::CreateFontconfigTestStanza("family", "eq", "string", "Arial") +
+          base::CreateFontconfigEditStanza("family", "string", "Verdana") +
           kFontconfigMatchFooter + kFontconfigFileFooter));
 
   FontRenderParamsQuery query;
diff --git a/ui/gfx/paint_vector_icon.cc b/ui/gfx/paint_vector_icon.cc
index 2669ca3..171bc56 100644
--- a/ui/gfx/paint_vector_icon.cc
+++ b/ui/gfx/paint_vector_icon.cc
@@ -42,12 +42,14 @@
 // Helper that simplifies iterating over a sequence of PathElements.
 class PathParser {
  public:
-  PathParser(const PathElement* path_elements)
-      : path_elements_(path_elements) {}
+  PathParser(const PathElement* path_elements, size_t path_size)
+      : path_elements_(path_elements), path_size_(path_size) {}
   ~PathParser() {}
 
   void Advance() { command_index_ += GetArgumentCount() + 1; }
 
+  bool HasCommandsRemaining() const { return command_index_ < path_size_; }
+
   CommandType CurrentCommand() const {
     return path_elements_[command_index_].command;
   }
@@ -103,7 +105,6 @@
       case FLIPS_IN_RTL:
       case TRANSITION_FROM:
       case TRANSITION_TO:
-      case END:
         return 0;
     }
 
@@ -112,7 +113,8 @@
   }
 
   const PathElement* path_elements_;
-  int command_index_ = 0;
+  size_t path_size_;
+  size_t command_index_ = 0;
 
   DISALLOW_COPY_AND_ASSIGN(PathParser);
 };
@@ -149,7 +151,6 @@
   RETURN_IF_IS(CLIP);
   RETURN_IF_IS(DISABLE_AA);
   RETURN_IF_IS(FLIPS_IN_RTL);
-  RETURN_IF_IS(END);
 #undef RETURN_IF_IS
 
   NOTREACHED() << "Unrecognized command: " << source;
@@ -175,6 +176,7 @@
 
 void PaintPath(Canvas* canvas,
                const PathElement* path_elements,
+               size_t path_size,
                int dip_size,
                SkColor color,
                const base::TimeDelta& elapsed_time) {
@@ -188,8 +190,8 @@
   bool flips_in_rtl = false;
   CommandType previous_command_type = NEW_PATH;
 
-  for (PathParser parser(path_elements); parser.CurrentCommand() != END;
-       parser.Advance()) {
+  for (PathParser parser(path_elements, path_size);
+       parser.HasCommandsRemaining(); parser.Advance()) {
     auto arg = [&parser](int i) { return parser.GetArgument(i); };
     const CommandType command_type = parser.CurrentCommand();
     auto start_new_path = [&paths]() {
@@ -430,10 +432,6 @@
         flags_array.pop_back();
         break;
       }
-
-      case END:
-        NOTREACHED();
-        break;
     }
 
     previous_command_type = command_type;
@@ -481,7 +479,7 @@
       if (!data_.badge_icon.is_empty())
         PaintVectorIcon(canvas, data_.badge_icon, size_.width(), data_.color);
     } else {
-      PaintPath(canvas, path_.data(), size_.width(), data_.color,
+      PaintPath(canvas, path_.data(), path_.size(), size_.width(), data_.color,
                 base::TimeDelta());
     }
   }
@@ -562,20 +560,13 @@
                      SkColor color,
                      const base::TimeDelta& elapsed_time) {
   DCHECK(!icon.is_empty());
-  if (icon.rep) {
+  if (icon.rep)
     DCHECK(icon.rep->path_size > 0);
-    DCHECK_EQ(END, icon.rep->path[icon.rep->path_size - 1].command)
-        << icon.name;
-  }
-  if (icon.rep_1x) {
+  if (icon.rep_1x)
     DCHECK(icon.rep_1x->path_size > 0);
-    DCHECK_EQ(END, icon.rep_1x->path[icon.rep_1x->path_size - 1].command)
-        << icon.name;
-  }
-  const PathElement* path = (canvas->image_scale() == 1.f && icon.rep_1x)
-                                ? icon.rep_1x->path
-                                : icon.rep->path;
-  PaintPath(canvas, path, dip_size, color, elapsed_time);
+  const VectorIconRep* rep =
+      (canvas->image_scale() == 1.f && icon.rep_1x) ? icon.rep_1x : icon.rep;
+  PaintPath(canvas, rep->path, rep->path_size, dip_size, color, elapsed_time);
 }
 
 ImageSkia CreateVectorIcon(const IconDescription& params) {
@@ -620,8 +611,8 @@
 
 base::TimeDelta GetDurationOfAnimation(const VectorIcon& icon) {
   base::TimeDelta last_motion;
-  for (PathParser parser(icon.rep->path); parser.CurrentCommand() != END;
-       parser.Advance()) {
+  for (PathParser parser(icon.rep->path, icon.rep->path_size);
+       parser.HasCommandsRemaining(); parser.Advance()) {
     if (parser.CurrentCommand() != TRANSITION_END)
       continue;
 
diff --git a/ui/gfx/paint_vector_icon_unittest.cc b/ui/gfx/paint_vector_icon_unittest.cc
index 3b5a9f4c..1188c35e 100644
--- a/ui/gfx/paint_vector_icon_unittest.cc
+++ b/ui/gfx/paint_vector_icon_unittest.cc
@@ -43,14 +43,9 @@
   Canvas canvas(recorder.beginRecording(100, 100), 1.0f);
 
   const PathElement elements[] = {
-      MOVE_TO, 4, 5,
-      LINE_TO, 10, 11,
-      CLOSE,
+      MOVE_TO, 4, 5, LINE_TO, 10, 11, CLOSE,
       // This move should use (4, 5) as the start point rather than (10, 11).
-      R_MOVE_TO, 20, 21,
-      R_LINE_TO, 50, 51,
-      END,
-  };
+      R_MOVE_TO, 20, 21, R_LINE_TO, 50, 51};
   const VectorIconRep icon_rep = {elements, arraysize(elements)};
   const VectorIcon icon = {&icon_rep};
 
@@ -79,16 +74,19 @@
 
   // Create a 20x20 square icon which has FLIPS_IN_RTL, and CANVAS_DIMENSIONS
   // are twice as large as |canvas|.
-  const PathElement elements[] = {
-      CANVAS_DIMENSIONS, 2 * canvas_size,
-      FLIPS_IN_RTL,
-      MOVE_TO, 10, 10,
-      R_H_LINE_TO, 20,
-      R_V_LINE_TO, 20,
-      R_H_LINE_TO, -20,
-      CLOSE,
-      END,
-  };
+  const PathElement elements[] = {CANVAS_DIMENSIONS,
+                                  2 * canvas_size,
+                                  FLIPS_IN_RTL,
+                                  MOVE_TO,
+                                  10,
+                                  10,
+                                  R_H_LINE_TO,
+                                  20,
+                                  R_V_LINE_TO,
+                                  20,
+                                  R_H_LINE_TO,
+                                  -20,
+                                  CLOSE};
   const VectorIconRep icon_rep = {elements, arraysize(elements)};
   const VectorIcon icon = {&icon_rep};
   PaintVectorIcon(&canvas, icon, canvas_size, color);
diff --git a/ui/gfx/platform_font_linux_unittest.cc b/ui/gfx/platform_font_linux_unittest.cc
index f677ba4..3953a6a 100644
--- a/ui/gfx/platform_font_linux_unittest.cc
+++ b/ui/gfx/platform_font_linux_unittest.cc
@@ -13,7 +13,6 @@
 #include "ui/gfx/font.h"
 #include "ui/gfx/font_render_params.h"
 #include "ui/gfx/linux_font_delegate.h"
-#include "ui/gfx/test/fontconfig_util_linux.h"
 
 namespace gfx {
 
@@ -62,7 +61,6 @@
 class PlatformFontLinuxTest : public testing::Test {
  public:
   PlatformFontLinuxTest() {
-    SetUpFontconfig();
     original_font_delegate_ = LinuxFontDelegate::instance();
     LinuxFontDelegate::SetInstance(&test_font_delegate_);
   }
@@ -71,7 +69,6 @@
     LinuxFontDelegate::SetInstance(
         const_cast<LinuxFontDelegate*>(original_font_delegate_));
     PlatformFontLinux::ReloadDefaultFont();
-    TearDownFontconfig();
   }
 
  protected:
@@ -87,9 +84,6 @@
 // Test that PlatformFontLinux's default constructor initializes the instance
 // with the correct parameters.
 TEST_F(PlatformFontLinuxTest, DefaultFont) {
-  ASSERT_TRUE(LoadSystemFontIntoFontconfig("arial.ttf"));
-  ASSERT_TRUE(LoadSystemFontIntoFontconfig("times_new_roman.ttf"));
-
 #if defined(OS_CHROMEOS)
   PlatformFontLinux::SetDefaultFontDescription("Arial,Times New Roman,13px");
 #else
diff --git a/ui/gfx/render_text_unittest.cc b/ui/gfx/render_text_unittest.cc
index ee8ac5b..7c1fcfdd 100644
--- a/ui/gfx/render_text_unittest.cc
+++ b/ui/gfx/render_text_unittest.cc
@@ -4369,13 +4369,13 @@
     }
     {
       SCOPED_TRACE("TextDoesntClip Left Side");
-#if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_CHROMEOS) || \
+#if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX) || \
     defined(ARCH_CPU_MIPS_FAMILY)
-      // TODO(dschuyler): On Windows, Chrome OS, and Mac smoothing draws to the
-      // left of text.  This appears to be a preexisting issue that wasn't
-      // revealed by the prior unit tests.  RenderText currently only uses
-      // origins and advances and ignores bounding boxes so cannot account for
-      // under- and over-hang.
+      // TODO(dschuyler): On Windows, Chrome OS, Linux, and Mac smoothing draws
+      // to the left of text.  This appears to be a preexisting issue that
+      // wasn't revealed by the prior unit tests.  RenderText currently only
+      // uses origins and advances and ignores bounding boxes so cannot account
+      // for under- and over-hang.
       rect_buffer.EnsureSolidRect(SK_ColorWHITE, 0, kTestSize, kTestSize - 1,
                                   string_size.height());
 #else
@@ -4385,13 +4385,13 @@
     }
     {
       SCOPED_TRACE("TextDoesntClip Right Side");
-#if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_CHROMEOS) || \
+#if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX) || \
     defined(ARCH_CPU_MIPS_FAMILY)
-      // TODO(dschuyler): On Windows, Chrome OS, and Mac smoothing draws to the
-      // right of text.  This appears to be a preexisting issue that wasn't
-      // revealed by the prior unit tests.  RenderText currently only uses
-      // origins and advances and ignores bounding boxes so cannot account for
-      // under- and over-hang.
+      // TODO(dschuyler): On Windows, Chrome OS, Linux, and Mac smoothing draws
+      // to the right of text.  This appears to be a preexisting issue that
+      // wasn't revealed by the prior unit tests.  RenderText currently only
+      // uses origins and advances and ignores bounding boxes so cannot account
+      // for under- and over-hang.
       rect_buffer.EnsureSolidRect(SK_ColorWHITE,
                                   kTestSize + string_size.width() + 1,
                                   kTestSize, kTestSize - 1,
diff --git a/ui/gfx/test/fontconfig_util_linux.cc b/ui/gfx/test/fontconfig_util_linux.cc
deleted file mode 100644
index 4afd735..0000000
--- a/ui/gfx/test/fontconfig_util_linux.cc
+++ /dev/null
@@ -1,193 +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/gfx/test/fontconfig_util_linux.h"
-
-#include <fontconfig/fontconfig.h>
-
-#include "base/base_paths.h"
-#include "base/files/file_path.h"
-#include "base/files/file_util.h"
-#include "base/logging.h"
-#include "base/macros.h"
-#include "base/path_service.h"
-#include "base/strings/string_util.h"
-#include "base/strings/stringprintf.h"
-
-namespace gfx {
-
-const char* const kSystemFontsForFontconfig[] = {
-    "/usr/share/fonts/opentype/ipafont-gothic/ipag.ttf",
-    "/usr/share/fonts/opentype/ipafont-gothic/ipagp.ttf",
-    "/usr/share/fonts/opentype/ipafont-mincho/ipam.ttf",
-    "/usr/share/fonts/opentype/ipafont-mincho/ipamp.ttf",
-    "/usr/share/fonts/truetype/msttcorefonts/Arial.ttf",
-    "/usr/share/fonts/truetype/msttcorefonts/Arial_Bold.ttf",
-    "/usr/share/fonts/truetype/msttcorefonts/Arial_Bold_Italic.ttf",
-    "/usr/share/fonts/truetype/msttcorefonts/Arial_Italic.ttf",
-    "/usr/share/fonts/truetype/msttcorefonts/Comic_Sans_MS.ttf",
-    "/usr/share/fonts/truetype/msttcorefonts/Comic_Sans_MS_Bold.ttf",
-    "/usr/share/fonts/truetype/msttcorefonts/Courier_New.ttf",
-    "/usr/share/fonts/truetype/msttcorefonts/Courier_New_Bold.ttf",
-    "/usr/share/fonts/truetype/msttcorefonts/Courier_New_Bold_Italic.ttf",
-    "/usr/share/fonts/truetype/msttcorefonts/Courier_New_Italic.ttf",
-    "/usr/share/fonts/truetype/msttcorefonts/Georgia.ttf",
-    "/usr/share/fonts/truetype/msttcorefonts/Georgia_Bold.ttf",
-    "/usr/share/fonts/truetype/msttcorefonts/Georgia_Bold_Italic.ttf",
-    "/usr/share/fonts/truetype/msttcorefonts/Georgia_Italic.ttf",
-    "/usr/share/fonts/truetype/msttcorefonts/Impact.ttf",
-    "/usr/share/fonts/truetype/msttcorefonts/Trebuchet_MS.ttf",
-    "/usr/share/fonts/truetype/msttcorefonts/Trebuchet_MS_Bold.ttf",
-    "/usr/share/fonts/truetype/msttcorefonts/Trebuchet_MS_Bold_Italic.ttf",
-    "/usr/share/fonts/truetype/msttcorefonts/Trebuchet_MS_Italic.ttf",
-    "/usr/share/fonts/truetype/msttcorefonts/Times_New_Roman.ttf",
-    "/usr/share/fonts/truetype/msttcorefonts/Times_New_Roman_Bold.ttf",
-    "/usr/share/fonts/truetype/msttcorefonts/Times_New_Roman_Bold_Italic.ttf",
-    "/usr/share/fonts/truetype/msttcorefonts/Times_New_Roman_Italic.ttf",
-    "/usr/share/fonts/truetype/msttcorefonts/Verdana.ttf",
-    "/usr/share/fonts/truetype/msttcorefonts/Verdana_Bold.ttf",
-    "/usr/share/fonts/truetype/msttcorefonts/Verdana_Bold_Italic.ttf",
-    "/usr/share/fonts/truetype/msttcorefonts/Verdana_Italic.ttf",
-};
-
-const size_t kNumSystemFontsForFontconfig =
-    arraysize(kSystemFontsForFontconfig);
-
-const char* const kCloudStorageSyncedFonts[] = {
-    // The DejaVuSans font is used by the css2.1 tests.
-    "DejaVuSans.ttf",
-    "Garuda.ttf",
-    "Lohit-Devanagari.ttf",
-    "Lohit-Tamil.ttf",
-    "Lohit-Gurmukhi.ttf",
-    "MuktiNarrow.ttf",
-    "NotoSansCJKjp-Regular.otf",
-    "NotoSansKhmer-Regular.ttf"};
-
-const size_t kNumCloudStorageSyncedFonts = arraysize(kCloudStorageSyncedFonts);
-
-void SetUpFontconfig() {
-  FcInit();
-
-  // A primer on undocumented FcConfig reference-counting:
-  //
-  // - FcConfigCreate() creates a config with a refcount of 1.
-  // - FcConfigReference() increments a config's refcount.
-  // - FcConfigDestroy() decrements a config's refcount, deallocating the
-  //   config when the count reaches 0.
-  // - FcConfigSetCurrent() calls FcConfigDestroy() on the old config, and
-  //   calls FcConfigReference() on the new config.
-  FcConfig* config = FcConfigCreate();
-  FcConfigBuildFonts(config);
-  CHECK(FcConfigSetCurrent(config));
-}
-
-void TearDownFontconfig() {
-  FcFini();
-}
-
-bool LoadFontIntoFontconfig(const base::FilePath& path) {
-  if (!base::PathExists(path)) {
-    LOG(ERROR) << "You are missing " << path.value() << ". Try re-running "
-               << "build/install-build-deps.sh. "
-               << "Please make sure that "
-               << "third_party/content_shell_fonts/ has downloaded "
-               << "and extracted the content_shell_test_fonts."
-               << "Also see "
-               << "https://chromium.googlesource.com/chromium/src/+/master/"
-               << "docs/layout_tests_linux.md";
-    return false;
-  }
-
-  if (!FcConfigAppFontAddFile(
-          NULL, reinterpret_cast<const FcChar8*>(path.value().c_str()))) {
-    LOG(ERROR) << "Failed to load font " << path.value();
-    return false;
-  }
-
-  return true;
-}
-
-bool LoadSystemFontIntoFontconfig(const std::string& basename) {
-  for (size_t i = 0; i < kNumSystemFontsForFontconfig; ++i) {
-    base::FilePath path(kSystemFontsForFontconfig[i]);
-    if (base::EqualsCaseInsensitiveASCII(path.BaseName().value(), basename))
-      return LoadFontIntoFontconfig(path);
-  }
-  LOG(ERROR) << "Unable to find system font named " << basename;
-  return false;
-}
-
-bool LoadCloudStorageSyncedFontIntoFontConfig(const std::string& fontfilename) {
-  base::FilePath content_shell_test_fonts_path;
-  PathService::Get(base::DIR_MODULE, &content_shell_test_fonts_path);
-  // See third_party/content_shell_test_fonts/ for information how these fonts
-  // are synced. Target directory out/<buildDir>/content_shell_test_fonts needs
-  // to match what is specified as the target in
-  // third_party/content_shell_test_fonts/BUILD.gn as output directory.
-  base::FilePath font_file_path =
-      content_shell_test_fonts_path
-          .Append(FILE_PATH_LITERAL("content_shell_test_fonts"))
-          .Append(FILE_PATH_LITERAL(fontfilename));
-  return LoadFontIntoFontconfig(font_file_path);
-}
-
-bool LoadConfigFileIntoFontconfig(const base::FilePath& path) {
-  // Unlike other FcConfig functions, FcConfigParseAndLoad() doesn't default to
-  // the current config when passed NULL. So that's cool.
-  if (!FcConfigParseAndLoad(FcConfigGetCurrent(),
-          reinterpret_cast<const FcChar8*>(path.value().c_str()), FcTrue)) {
-    LOG(ERROR) << "Fontconfig failed to load " << path.value();
-    return false;
-  }
-  return true;
-}
-
-bool LoadConfigDataIntoFontconfig(const base::FilePath& temp_dir,
-                                  const std::string& data) {
-  base::FilePath path;
-  if (!CreateTemporaryFileInDir(temp_dir, &path)) {
-    PLOG(ERROR) << "Unable to create temporary file in " << temp_dir.value();
-    return false;
-  }
-  if (base::WriteFile(path, data.data(), data.size()) !=
-      static_cast<int>(data.size())) {
-    PLOG(ERROR) << "Unable to write config data to " << path.value();
-    return false;
-  }
-  return LoadConfigFileIntoFontconfig(path);
-}
-
-std::string CreateFontconfigEditStanza(const std::string& name,
-                                       const std::string& type,
-                                       const std::string& value) {
-  return base::StringPrintf(
-      "    <edit name=\"%s\" mode=\"assign\">\n"
-      "      <%s>%s</%s>\n"
-      "    </edit>\n",
-      name.c_str(), type.c_str(), value.c_str(), type.c_str());
-}
-
-std::string CreateFontconfigTestStanza(const std::string& name,
-                                       const std::string& op,
-                                       const std::string& type,
-                                       const std::string& value) {
-  return base::StringPrintf(
-      "    <test name=\"%s\" compare=\"%s\" qual=\"any\">\n"
-      "      <%s>%s</%s>\n"
-      "    </test>\n",
-      name.c_str(), op.c_str(), type.c_str(), value.c_str(), type.c_str());
-}
-
-std::string CreateFontconfigAliasStanza(const std::string& original_family,
-                                        const std::string& preferred_family) {
-  return base::StringPrintf(
-      "  <alias>\n"
-      "    <family>%s</family>\n"
-      "    <prefer><family>%s</family></prefer>\n"
-      "  </alias>\n",
-      original_family.c_str(), preferred_family.c_str());
-}
-
-}  // namespace gfx
diff --git a/ui/gfx/test/fontconfig_util_linux.h b/ui/gfx/test/fontconfig_util_linux.h
deleted file mode 100644
index 96dfed7..0000000
--- a/ui/gfx/test/fontconfig_util_linux.h
+++ /dev/null
@@ -1,72 +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 UI_GFX_TEST_FONTCONFIG_UTIL_LINUX_H_
-#define UI_GFX_TEST_FONTCONFIG_UTIL_LINUX_H_
-
-#include <stddef.h>
-
-#include <string>
-
-namespace base {
-class FilePath;
-}
-
-namespace gfx {
-
-// Array of paths to font files that are expected to exist on machines where
-// tests are run.
-extern const char* const kSystemFontsForFontconfig[];
-extern const size_t kNumSystemFontsForFontconfig;
-
-extern const char* const kCloudStorageSyncedFonts[];
-extern const size_t kNumCloudStorageSyncedFonts;
-
-// Initializes Fontconfig and creates and swaps in a new, empty config.
-void SetUpFontconfig();
-
-// Deinitializes Fontconfig.
-void TearDownFontconfig();
-
-// Loads the font file at |path| into the current config, returning true on
-// success.
-bool LoadFontIntoFontconfig(const base::FilePath& path);
-
-// Loads the first system font in kSystemFontsForFontconfig with a base filename
-// of |basename|. Case is ignored. FcFontMatch() requires there to be at least
-// one font present.
-bool LoadSystemFontIntoFontconfig(const std::string& basename);
-
-// Loads a font named by |fontfilename|, taken from kCloudStorageSyncedFonts
-// into the current config. Returns true on success, false if the font cannot be
-// found from the set of cloud synced fonts.
-bool LoadCloudStorageSyncedFontIntoFontConfig(const std::string& fontfilename);
-
-// Instructs Fontconfig to load |path|, an XML configuration file, into the
-// current config, returning true on success.
-bool LoadConfigFileIntoFontconfig(const base::FilePath& path);
-
-// Writes |data| to a file in |temp_dir| and passes it to
-// LoadConfigFileIntoFontconfig().
-bool LoadConfigDataIntoFontconfig(const base::FilePath& temp_dir,
-                                  const std::string& data);
-
-// Returns a Fontconfig <edit> stanza.
-std::string CreateFontconfigEditStanza(const std::string& name,
-                                       const std::string& type,
-                                       const std::string& value);
-
-// Returns a Fontconfig <test> stanza.
-std::string CreateFontconfigTestStanza(const std::string& name,
-                                       const std::string& op,
-                                       const std::string& type,
-                                       const std::string& value);
-
-// Returns a Fontconfig <alias> stanza.
-std::string CreateFontconfigAliasStanza(const std::string& original_family,
-                                        const std::string& preferred_family);
-
-}  // namespace gfx
-
-#endif  // UI_GFX_TEST_FONTCONFIG_UTIL_LINUX_H_
diff --git a/ui/gfx/vector_icon_types.h b/ui/gfx/vector_icon_types.h
index e5f14b1..e03aa126 100644
--- a/ui/gfx/vector_icon_types.h
+++ b/ui/gfx/vector_icon_types.h
@@ -63,9 +63,6 @@
   // Parameters are delay (ms), duration (ms), and tween type
   // (gfx::Tween::Type).
   TRANSITION_END,
-  // Marks the end of the list of commands. TODO(estade): remove this sentinel
-  // value and rely on VectorIcon::path_size.
-  END
 };
 
 // A POD that describes either a path command or an argument for it.
diff --git a/ui/gl/gl_image_ahardwarebuffer.h b/ui/gl/gl_image_ahardwarebuffer.h
index b3ebd04..3170e0f 100644
--- a/ui/gl/gl_image_ahardwarebuffer.h
+++ b/ui/gl/gl_image_ahardwarebuffer.h
@@ -6,6 +6,7 @@
 #define UI_GL_GL_IMAGE_AHARDWAREBUFFER_H_
 
 #include "base/macros.h"
+#include "ui/gl/gl_bindings.h"
 #include "ui/gl/gl_export.h"
 #include "ui/gl/gl_image_egl.h"
 
diff --git a/ui/gl/gl_image_egl.h b/ui/gl/gl_image_egl.h
index b32e948..e014dc7 100644
--- a/ui/gl/gl_image_egl.h
+++ b/ui/gl/gl_image_egl.h
@@ -5,9 +5,10 @@
 #ifndef UI_GL_GL_IMAGE_EGL_H_
 #define UI_GL_GL_IMAGE_EGL_H_
 
+#include <EGL/eglplatform.h>
+
 #include "base/macros.h"
 #include "base/threading/thread_checker.h"
-#include "ui/gl/gl_bindings.h"
 #include "ui/gl/gl_export.h"
 #include "ui/gl/gl_image.h"
 
@@ -35,12 +36,12 @@
   // it is required to pass EGL_NO_CONTEXT. This allows to create an EGLImage
   // from an external resource. Then this EGLImage can be converted to a GL
   // texture.
-  bool Initialize(EGLContext context,
-                  EGLenum target,
-                  EGLClientBuffer buffer,
+  bool Initialize(void* context /* EGLContext */,
+                  unsigned target /* EGLenum */,
+                  void* buffer /* EGLClientBuffer */,
                   const EGLint* attrs);
 
-  EGLImageKHR egl_image_;
+  void* egl_image_ /* EGLImageKHR */;
   const gfx::Size size_;
   base::ThreadChecker thread_checker_;
 
diff --git a/ui/gl/gl_image_native_pixmap_unittest.cc b/ui/gl/gl_image_native_pixmap_unittest.cc
index 99a852db..a8639cb 100644
--- a/ui/gl/gl_image_native_pixmap_unittest.cc
+++ b/ui/gl/gl_image_native_pixmap_unittest.cc
@@ -4,6 +4,7 @@
 
 #include "ui/gl/gl_image_native_pixmap.h"
 
+#include "ui/gl/gl_bindings.h"
 #include "ui/gl/test/gl_image_test_template.h"
 
 namespace gl {
diff --git a/ui/message_center/vector_icons/notification_close_button.1x.icon b/ui/message_center/vector_icons/notification_close_button.1x.icon
index 2bea75d..8df1cab 100644
--- a/ui/message_center/vector_icons/notification_close_button.1x.icon
+++ b/ui/message_center/vector_icons/notification_close_button.1x.icon
@@ -15,5 +15,4 @@
 LINE_TO, 9.64f, 10.5f,
 LINE_TO, 10.5f, 9.64f,
 LINE_TO, 6.86f, 6,
-CLOSE,
-END
+CLOSE
diff --git a/ui/message_center/vector_icons/notification_close_button.icon b/ui/message_center/vector_icons/notification_close_button.icon
index 5ce70e4..37b056a 100644
--- a/ui/message_center/vector_icons/notification_close_button.icon
+++ b/ui/message_center/vector_icons/notification_close_button.icon
@@ -15,5 +15,4 @@
 LINE_TO, 18.27f, 20,
 LINE_TO, 20, 18.27f,
 LINE_TO, 13.73f, 12,
-CLOSE,
-END
+CLOSE
diff --git a/ui/message_center/vector_icons/notification_expand_less.icon b/ui/message_center/vector_icons/notification_expand_less.icon
index b30ee42..d15fce2a 100644
--- a/ui/message_center/vector_icons/notification_expand_less.icon
+++ b/ui/message_center/vector_icons/notification_expand_less.icon
@@ -9,5 +9,4 @@
 LINE_TO, 15, 11.31f,
 R_LINE_TO, -7, -6.89f,
 R_LINE_TO, -7, 6.89f,
-CLOSE,
-END
+CLOSE
diff --git a/ui/message_center/vector_icons/notification_expand_more.icon b/ui/message_center/vector_icons/notification_expand_more.icon
index b779f5f..155f6b5 100644
--- a/ui/message_center/vector_icons/notification_expand_more.icon
+++ b/ui/message_center/vector_icons/notification_expand_more.icon
@@ -9,5 +9,4 @@
 LINE_TO, 15, 4.69f,
 R_LINE_TO, -7, 6.89f,
 R_LINE_TO, -7, -6.89f,
-CLOSE,
-END
+CLOSE
diff --git a/ui/message_center/vector_icons/notification_inline_reply.icon b/ui/message_center/vector_icons/notification_inline_reply.icon
index e1286993..abb71d49 100644
--- a/ui/message_center/vector_icons/notification_inline_reply.icon
+++ b/ui/message_center/vector_icons/notification_inline_reply.icon
@@ -9,5 +9,4 @@
 LINE_TO, 10, 40.44f,
 LINE_TO, 64.29f, 48,
 LINE_TO, 10, 55.56f,
-CLOSE,
-END
\ No newline at end of file
+CLOSE
diff --git a/ui/message_center/vector_icons/notification_settings_button.1x.icon b/ui/message_center/vector_icons/notification_settings_button.1x.icon
index d999691..8d4a4971 100644
--- a/ui/message_center/vector_icons/notification_settings_button.1x.icon
+++ b/ui/message_center/vector_icons/notification_settings_button.1x.icon
@@ -50,5 +50,4 @@
 CUBIC_TO, 6.83f, 4.5f, 7.5f, 5.17f, 7.5f, 6,
 CUBIC_TO, 7.5f, 6.83f, 6.83f, 7.5f, 6, 7.5f,
 LINE_TO, 6, 7.5f,
-CLOSE,
-END
+CLOSE
diff --git a/ui/message_center/vector_icons/notification_settings_button.icon b/ui/message_center/vector_icons/notification_settings_button.icon
index ae7e26a..2f312ea9 100644
--- a/ui/message_center/vector_icons/notification_settings_button.icon
+++ b/ui/message_center/vector_icons/notification_settings_button.icon
@@ -50,5 +50,4 @@
 CUBIC_TO, 13.66f, 9, 15, 10.34f, 15, 12,
 CUBIC_TO, 15, 13.66f, 13.66f, 15, 12, 15,
 LINE_TO, 12, 15,
-CLOSE,
-END
+CLOSE
diff --git a/ui/message_center/vector_icons/product.icon b/ui/message_center/vector_icons/product.icon
index 97f8448b..7068cb2 100644
--- a/ui/message_center/vector_icons/product.icon
+++ b/ui/message_center/vector_icons/product.icon
@@ -32,5 +32,4 @@
 R_CUBIC_TO, 0, -7.73f, 6.27f, -14, 14, -14,
 R_CUBIC_TO, 7.73f, 0, 14, 6.27f, 14, 14,
 R_CUBIC_TO, 0, 7.73f, -6.27f, 14, -14, 14,
-CLOSE,
-END
+CLOSE
diff --git a/ui/ozone/platform/headless/BUILD.gn b/ui/ozone/platform/headless/BUILD.gn
index 6de5730..0637f8e 100644
--- a/ui/ozone/platform/headless/BUILD.gn
+++ b/ui/ozone/platform/headless/BUILD.gn
@@ -20,6 +20,8 @@
     "ozone_platform_headless.h",
   ]
 
+  defines = [ "OZONE_IMPLEMENTATION" ]
+
   deps = [
     "//base",
     "//skia",
diff --git a/ui/views/vector_icons/checkbox_active.icon b/ui/views/vector_icons/checkbox_active.icon
index 199c3fd9..d9ffe03 100644
--- a/ui/views/vector_icons/checkbox_active.icon
+++ b/ui/views/vector_icons/checkbox_active.icon
@@ -23,6 +23,4 @@
 LINE_TO, 6.5f, 9,
 LINE_TO, 11.5f, 4.5f,
 LINE_TO, 12.5f, 5.5f,
-CLOSE,
-
-END
+CLOSE
diff --git a/ui/views/vector_icons/checkbox_normal.icon b/ui/views/vector_icons/checkbox_normal.icon
index 0b1efe5..8ea38e01 100644
--- a/ui/views/vector_icons/checkbox_normal.icon
+++ b/ui/views/vector_icons/checkbox_normal.icon
@@ -22,6 +22,4 @@
 V_LINE_TO, 3.004f,
 CUBIC_TO, 14, 2.449f, 13.551f, 2, 12.996f, 2,
 LINE_TO, 12.996f, 2,
-CLOSE,
-
-END
+CLOSE
diff --git a/ui/views/vector_icons/menu_check.1x.icon b/ui/views/vector_icons/menu_check.1x.icon
index 739f668..18d76177 100644
--- a/ui/views/vector_icons/menu_check.1x.icon
+++ b/ui/views/vector_icons/menu_check.1x.icon
@@ -10,5 +10,4 @@
 R_LINE_TO, 1.35f, 1.39f,
 R_LINE_TO, -8.55f, 8.78f,
 LINE_TO, 2, 9.22f,
-CLOSE,
-END
+CLOSE
diff --git a/ui/views/vector_icons/menu_check.icon b/ui/views/vector_icons/menu_check.icon
index c06a2cc..46f105a 100644
--- a/ui/views/vector_icons/menu_check.icon
+++ b/ui/views/vector_icons/menu_check.icon
@@ -10,5 +10,4 @@
 LINE_TO, 28, 9.59f,
 LINE_TO, 12.02f, 26,
 LINE_TO, 5, 18.78f,
-CLOSE,
-END
+CLOSE
diff --git a/ui/views/vector_icons/menu_radio_empty.icon b/ui/views/vector_icons/menu_radio_empty.icon
index 62ef2daec..047257b4 100644
--- a/ui/views/vector_icons/menu_radio_empty.icon
+++ b/ui/views/vector_icons/menu_radio_empty.icon
@@ -4,5 +4,4 @@
 
 CANVAS_DIMENSIONS, 32,
 CIRCLE, 16, 16, 14,
-CIRCLE, 16, 16, 11,
-END
+CIRCLE, 16, 16, 11
diff --git a/ui/views/vector_icons/menu_radio_selected.icon b/ui/views/vector_icons/menu_radio_selected.icon
index 0533b99b..5f94564c 100644
--- a/ui/views/vector_icons/menu_radio_selected.icon
+++ b/ui/views/vector_icons/menu_radio_selected.icon
@@ -5,5 +5,4 @@
 CANVAS_DIMENSIONS, 32,
 CIRCLE, 16, 16, 14,
 CIRCLE, 16, 16, 11,
-CIRCLE, 16, 16, 7,
-END
+CIRCLE, 16, 16, 7
diff --git a/ui/views/vector_icons/radio_button_active.icon b/ui/views/vector_icons/radio_button_active.icon
index 0533b99b..5f94564c 100644
--- a/ui/views/vector_icons/radio_button_active.icon
+++ b/ui/views/vector_icons/radio_button_active.icon
@@ -5,5 +5,4 @@
 CANVAS_DIMENSIONS, 32,
 CIRCLE, 16, 16, 14,
 CIRCLE, 16, 16, 11,
-CIRCLE, 16, 16, 7,
-END
+CIRCLE, 16, 16, 7
diff --git a/ui/views/vector_icons/radio_button_normal.icon b/ui/views/vector_icons/radio_button_normal.icon
index 62ef2daec..047257b4 100644
--- a/ui/views/vector_icons/radio_button_normal.icon
+++ b/ui/views/vector_icons/radio_button_normal.icon
@@ -4,5 +4,4 @@
 
 CANVAS_DIMENSIONS, 32,
 CIRCLE, 16, 16, 14,
-CIRCLE, 16, 16, 11,
-END
+CIRCLE, 16, 16, 11
diff --git a/ui/views/vector_icons/submenu_arrow.1x.icon b/ui/views/vector_icons/submenu_arrow.1x.icon
index c964eee..823fd4d 100644
--- a/ui/views/vector_icons/submenu_arrow.1x.icon
+++ b/ui/views/vector_icons/submenu_arrow.1x.icon
@@ -8,5 +8,4 @@
 R_LINE_TO, 5, -4,
 R_LINE_TO, -5, -4,
 R_V_LINE_TO, 8,
-CLOSE,
-END
+CLOSE
diff --git a/ui/views/vector_icons/submenu_arrow.icon b/ui/views/vector_icons/submenu_arrow.icon
index 2ebf8a3..74b764c 100644
--- a/ui/views/vector_icons/submenu_arrow.icon
+++ b/ui/views/vector_icons/submenu_arrow.icon
@@ -8,5 +8,4 @@
 R_LINE_TO, 11, -8,
 LINE_TO, 3, 0,
 R_V_LINE_TO, 16,
-CLOSE,
-END
+CLOSE
diff --git a/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc b/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc
index 1f9b269..cde45a41 100644
--- a/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc
+++ b/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc
@@ -72,8 +72,6 @@
 
 namespace {
 
-bool g_disable_activation_change_handling_ = false;
-
 // This class provides functionality to create a top level widget to host a
 // child window.
 class DesktopNativeWidgetTopLevelHandler : public aura::WindowObserver {
@@ -238,11 +236,6 @@
     NULL;
 wm::CursorManager* DesktopNativeWidgetAura::cursor_manager_ = NULL;
 
-// static
-void DesktopNativeWidgetAura::DisableActivationChangeHandlingForTests() {
-  g_disable_activation_change_handling_ = true;
-}
-
 DesktopNativeWidgetAura::DesktopNativeWidgetAura(
     internal::NativeWidgetDelegate* delegate)
     : desktop_window_tree_host_(NULL),
@@ -355,9 +348,6 @@
 }
 
 void DesktopNativeWidgetAura::HandleActivationChanged(bool active) {
-  if (g_disable_activation_change_handling_)
-    return;
-
   native_widget_delegate_->OnNativeWidgetActivationChanged(active);
   wm::ActivationClient* activation_client =
       wm::GetActivationClient(host_->window());
diff --git a/ui/views/widget/desktop_aura/desktop_native_widget_aura.h b/ui/views/widget/desktop_aura/desktop_native_widget_aura.h
index 73b6a006..812a37da 100644
--- a/ui/views/widget/desktop_aura/desktop_native_widget_aura.h
+++ b/ui/views/widget/desktop_aura/desktop_native_widget_aura.h
@@ -100,10 +100,6 @@
   // Overridden from internal::NativeWidgetPrivate:
   gfx::NativeWindow GetNativeWindow() const override;
 
-  // Forces HandleActivationChanged to do nothing, making Chrome-internal notion
-  // of focused and active windows independent from the OS.
-  static void DisableActivationChangeHandlingForTests();
-
  protected:
   // Overridden from internal::NativeWidgetPrivate:
   void InitNativeWidget(const Widget::InitParams& params) override;